config tests added,
titles tests added, .env file support added with dotenv, README.md file updated for .evn file support, database lost connection bug crash fixed, session server run_session long timeout bug fixed, links module added, webrtc_proc json arguments added, app_proc stdout and stderr support added, infinity app_proc spawn freeze bug fixed
This commit is contained in:
@@ -1,3 +1,14 @@
|
||||
# pixel-streaming-session-server
|
||||
|
||||
pixel streaming session server
|
||||
pixel streaming session server
|
||||
|
||||
configure environment variables with .env file
|
||||
|
||||
.env:
|
||||
|
||||
PORT=
|
||||
EXTERNAL_DOMAIN=""
|
||||
COORDINATOR_URL=""
|
||||
DATABASE_URL=""
|
||||
DATABASE_NAME=""
|
||||
WEBRTC_PORT_BEGIN=
|
||||
@@ -6,6 +6,18 @@ const body_parser = require('body-parser')
|
||||
const {request_logger, error_logger} = require('./src/middlewares/logger')
|
||||
const {error_handler} = require('./src/middlewares/error_handler')
|
||||
const {start_observer} = require('./src/modules/session_observer')
|
||||
const {test_config} = require('./tests/config')
|
||||
const {test_titles} = require('./tests/titles')
|
||||
|
||||
if (!test_config()) {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (!test_titles()) {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log('all initial tests successfully passed')
|
||||
|
||||
start_observer()
|
||||
|
||||
@@ -24,5 +36,4 @@ app.use(error_handler)
|
||||
|
||||
// start listen server
|
||||
app.listen(port)
|
||||
console.log('all config.js tests passed successfully [not developed]')
|
||||
console.log(`Listening at http://localhost:${port}`)
|
||||
@@ -1,6 +1,8 @@
|
||||
require('dotenv').config()
|
||||
|
||||
module.exports = {
|
||||
port: parseInt(process.env.PORT),
|
||||
external_url: process.env.EXTERNAL_URL,
|
||||
external_domain: process.env.EXTERNAL_DOMAIN,
|
||||
coordinator_url: process.env.COORDINATOR_URL,
|
||||
database_url: process.env.DATABASE_URL,
|
||||
database_name: process.env.DATABASE_NAME,
|
||||
|
||||
Generated
+3018
File diff suppressed because it is too large
Load Diff
@@ -17,8 +17,12 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"celebrate": "^15.0.1",
|
||||
"dotenv": "^16.0.3",
|
||||
"express": "^4.18.2",
|
||||
"is-running": "^2.1.0",
|
||||
"mongodb": "^4.13.0",
|
||||
"node-datetime": "^2.1.2",
|
||||
"node-modules": "^1.0.1",
|
||||
"portfinder": "^1.0.32",
|
||||
"request": "^2.88.2"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ const {get_app_path} = require('../modules/titles')
|
||||
const not_found_error = require('../../lib/src/http/errors/not_found_error')
|
||||
const server_error = require('../../lib/src/http/errors/server_error')
|
||||
const {run_webrtc, run_app} = require('../modules/run_process')
|
||||
const {external_url} = require('../../config')
|
||||
const {create_websocket_url} = require('../modules/links')
|
||||
|
||||
|
||||
const run_session = async (req, res, next) => {
|
||||
@@ -42,8 +42,8 @@ const run_session = async (req, res, next) => {
|
||||
next(new server_error('can not add session to database'))
|
||||
return
|
||||
}
|
||||
|
||||
res.json({websocket_url:`wss://${external_url}${webrtc_port}/`})
|
||||
|
||||
res.json({websocket_url:create_websocket_url(webrtc_port)})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -2,18 +2,21 @@ const { MongoClient } = require("mongodb")
|
||||
const { database_url, database_name } = require('../../config')
|
||||
let max_database_connection_timeout = 1000
|
||||
|
||||
const client = new MongoClient(database_url, {
|
||||
serverSelectionTimeoutMS: max_database_connection_timeout,
|
||||
useUnifiedTopology: true
|
||||
})
|
||||
|
||||
const get_db = async () => {
|
||||
const client = new MongoClient(database_url, {
|
||||
serverSelectionTimeoutMS: max_database_connection_timeout,
|
||||
useUnifiedTopology: true
|
||||
})
|
||||
try {
|
||||
await client.connect()
|
||||
await client.db(database_name).command({ ping: 1 })
|
||||
return client.db(database_name)
|
||||
} catch (err) {
|
||||
console.log('can not connect to database')
|
||||
console.error('can not connect to database')
|
||||
await client.close()
|
||||
return null
|
||||
}
|
||||
return client.db(database_name)
|
||||
}
|
||||
|
||||
const add_running_session = async (session_id, app_pid, webrtc_pid) => {
|
||||
@@ -46,7 +49,6 @@ const get_running_sessions = async () => {
|
||||
if (!db) {
|
||||
return null
|
||||
}
|
||||
|
||||
var running_sessions = await db.collection('running_session').find().toArray()
|
||||
return (!running_sessions.length) ? null : running_sessions
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
const {external_domain} = require('../../config')
|
||||
|
||||
const create_websocket_url = (webrtc_port) => {
|
||||
var valid_external_domain = external_domain
|
||||
|
||||
// if external domain contains http OR https part remove it
|
||||
valid_external_domain = valid_external_domain.replace('http://', '').replace('https://', '')
|
||||
|
||||
valid_external_domain = (valid_external_domain.slice(-1) == '/') ?
|
||||
valid_external_domain.substring(0, valid_external_domain.length - 1) : valid_external_domain
|
||||
|
||||
return `wss://${valid_external_domain}/${webrtc_port}/`
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
create_websocket_url
|
||||
}
|
||||
@@ -10,7 +10,7 @@ const is_proc_running = (pid) => {
|
||||
return is_running(pid)
|
||||
}
|
||||
|
||||
const is_proc_running_async = async (pid, check_time) => {
|
||||
const is_proc_running_async = async (pid, time_ms) => {
|
||||
var timeout_count = 0
|
||||
var check_times = 10
|
||||
|
||||
@@ -22,7 +22,7 @@ const is_proc_running_async = async (pid, check_time) => {
|
||||
if (timeout_count > check_times) {
|
||||
return true
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, check_time / check_times))
|
||||
await new Promise(resolve => setTimeout(resolve, time_ms / check_times))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@ const run_webrtc = async (webrtc_port, app_port) => {
|
||||
|
||||
var webrtc_proc
|
||||
try {
|
||||
webrtc_proc = fork(webrtc_server_path, [webrtc_port.toString(), app_port.toString()], {
|
||||
var webrtc_proc_arg = JSON.stringify({webrtc_port:webrtc_port, app_port:app_port})
|
||||
webrtc_proc = fork(webrtc_server_path, [webrtc_proc_arg], {
|
||||
detached: true
|
||||
})
|
||||
} catch (err) {
|
||||
@@ -49,9 +50,18 @@ const run_app = async (app_path, app_port) => {
|
||||
var app_proc
|
||||
try {
|
||||
app_proc = spawn(app_path, [].concat(app_args_static,
|
||||
[app_port_arg + app_port.toString()]), {
|
||||
[app_port_arg + app_port.toString()], { cwd: './', stdio: ['ignore', 'pipe', 'pipe']}), {
|
||||
detached: true
|
||||
})
|
||||
|
||||
// bind some events to unfreez process
|
||||
app_proc.stdout.on('data', data => {
|
||||
//console.log('stdout: ' + data.toString());
|
||||
})
|
||||
|
||||
app_proc.stderr.on('data', data => {
|
||||
//console.log('stderr: ' + data.toString());
|
||||
})
|
||||
} catch (err) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ const run_process = require('../modules/run_process')
|
||||
const database = require('../database/database')
|
||||
const {is_proc_running, kill_proc} = require('./run_process')
|
||||
const coordinator = require('./coordinator')
|
||||
const wait_list = require('./wait_list')
|
||||
|
||||
const observer_timeout = 100
|
||||
var pending_list = new wait_list([])
|
||||
|
||||
const start_observer = () => {
|
||||
check()
|
||||
@@ -16,16 +18,22 @@ const check_sessions = async (sessions) => {
|
||||
await Promise.all(sessions.map(async (session) => {
|
||||
var webrtc_running = is_proc_running(session.webrtc_pid)
|
||||
var app_running = is_proc_running(session.app_pid)
|
||||
|
||||
|
||||
if (webrtc_running && app_running) {
|
||||
return
|
||||
}
|
||||
|
||||
// if something running kill process and skip remove from database
|
||||
if (!webrtc_running && !app_running) {
|
||||
var close_session_result = await coordinator.close_session(session.session_id)
|
||||
if (close_session_result) {
|
||||
database.remove_running_session(session.session_id)
|
||||
if (!pending_list.is_waiting(session.session_id)) {
|
||||
pending_list.add(session.session_id)
|
||||
var close_session_result = await coordinator.close_session(session.session_id)
|
||||
if (close_session_result) {
|
||||
database.remove_running_session(session.session_id)
|
||||
} else {
|
||||
pending_list.remove(session.session_id)
|
||||
console.log('can not connect to coordinator')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
kill_proc(session.webrtc_pid)
|
||||
@@ -36,7 +44,7 @@ const check_sessions = async (sessions) => {
|
||||
|
||||
const check = async () => {
|
||||
var sessions = await database.get_running_sessions()
|
||||
|
||||
|
||||
if (!sessions) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
module.exports = class wait_list {
|
||||
constructor(list) {
|
||||
this.list = list
|
||||
}
|
||||
|
||||
is_waiting(id) {
|
||||
return (this.list.indexOf(id) > -1)
|
||||
}
|
||||
|
||||
add(id) {
|
||||
if (this.is_waiting(id)) {
|
||||
return
|
||||
}
|
||||
this.list.push(id)
|
||||
}
|
||||
|
||||
remove(id) {
|
||||
this.list.splice(this.list.indexOf(id), 1)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
var config = require('../config')
|
||||
|
||||
const not_valid = (message) => {
|
||||
console.error('not valid (config.js): ', message)
|
||||
}
|
||||
|
||||
const test_config = () => {
|
||||
var config_pass = true
|
||||
|
||||
if (!config) {
|
||||
not_valid('config')
|
||||
config_pass = false
|
||||
}
|
||||
|
||||
if (!config.port) {
|
||||
not_valid('port')
|
||||
config_pass = false
|
||||
}
|
||||
|
||||
if (!config.external_domain) {
|
||||
not_valid('external_domain')
|
||||
config_pass = false
|
||||
}
|
||||
|
||||
if (!config.coordinator_url) {
|
||||
not_valid('coordinator_url')
|
||||
config_pass = false
|
||||
}
|
||||
|
||||
if (!config.database_url) {
|
||||
not_valid('database_url')
|
||||
config_pass = false
|
||||
}
|
||||
|
||||
if (!config.database_name) {
|
||||
not_valid('database_name')
|
||||
config_pass = false
|
||||
}
|
||||
|
||||
if (!config.webrtc_port_begin) {
|
||||
not_valid('webrtc_port_begin')
|
||||
config_pass = false
|
||||
}
|
||||
|
||||
if (!config.session_limit) {
|
||||
not_valid('session_limit')
|
||||
config_pass = false
|
||||
}
|
||||
|
||||
if (!config.log_path) {
|
||||
not_valid('log_path')
|
||||
config_pass = false
|
||||
}
|
||||
|
||||
if (!config.webrtc_server_path) {
|
||||
not_valid('webrtc_server_path')
|
||||
config_pass = false
|
||||
}
|
||||
|
||||
if (!config.app_args) {
|
||||
not_valid('webrtc_server_path')
|
||||
config_pass = false
|
||||
}
|
||||
return config_pass
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
test_config
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
const fs = require('fs')
|
||||
|
||||
const titles = require('../titles')
|
||||
|
||||
const path_not_exists = (message) => {
|
||||
console.error('path not exists (titles.json): \n', message)
|
||||
}
|
||||
|
||||
const test_titles = () => {
|
||||
var titles_pass = true
|
||||
|
||||
titles.forEach(title => {
|
||||
if (!fs.existsSync(title.path)) {
|
||||
titles_pass = false
|
||||
path_not_exists(`\ttitle: ${title.title}, path: ${title.path}`)
|
||||
}
|
||||
})
|
||||
|
||||
return titles_pass
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
test_titles
|
||||
}
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
[
|
||||
{
|
||||
"title":"test-fortis",
|
||||
"path":"D:/shared/Builds/Fortis_UnStable_64/WindowsNoEditor/FORTIS_Taktika.exe"
|
||||
},
|
||||
{
|
||||
"title":"test-ivazowsky",
|
||||
"path":"D:/shared/Builds/ivazowsky/Ivaz_Optimized_2/Ivazowsky.exe"
|
||||
},
|
||||
{
|
||||
"title":"test-mosharov",
|
||||
"path":"D:/shared/Builds/mosharov/mosharov-stream-v1/Masharovdev.exe"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user