Added runtime config.
parent
fcff93c533
commit
27eafbd71d
|
@ -1,4 +1,5 @@
|
||||||
node_modules
|
node_modules
|
||||||
site
|
site
|
||||||
|
config/local.toml
|
||||||
build/**
|
build/**
|
||||||
lib/inspircd-*
|
lib/inspircd-*
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
[bcrypt]
|
||||||
|
saltRounds = 12
|
||||||
|
|
||||||
|
[satyr]
|
||||||
|
registration = false
|
||||||
|
webFormat = 'hls'
|
||||||
|
record = false
|
||||||
|
restrictedNames = ['live','stream']
|
||||||
|
|
||||||
|
[ircd]
|
||||||
|
enable = false
|
||||||
|
port = 7000
|
||||||
|
user = ''
|
||||||
|
pass = ''
|
||||||
|
|
||||||
|
[database]
|
||||||
|
host = 'localhost'
|
||||||
|
user = 'satyr'
|
||||||
|
password = ''
|
||||||
|
database = 'satyr_db'
|
||||||
|
connectionLimit = '50'
|
||||||
|
connectionTimeout = 'false'
|
||||||
|
insecureAuth = false
|
||||||
|
debug = false
|
||||||
|
|
||||||
|
[server]
|
||||||
|
logs = 0
|
||||||
|
api = false
|
||||||
|
api_user = false
|
||||||
|
api_pass = false
|
||||||
|
|
||||||
|
[server.rtmp]
|
||||||
|
port = 1935
|
||||||
|
chunk_size = 6000
|
||||||
|
gop_cache = true
|
||||||
|
ping = 30
|
||||||
|
ping_timeout = 60
|
||||||
|
|
||||||
|
[server.http]
|
||||||
|
port = 8080
|
||||||
|
allow_origin = '*'
|
||||||
|
directory = './site'
|
||||||
|
|
||||||
|
[media]
|
||||||
|
streamKeys = false
|
||||||
|
record = false
|
||||||
|
publicEndpoint = 'live'
|
||||||
|
privateEndpoint = 'stream'
|
||||||
|
ffmpeg = ''
|
||||||
|
|
||||||
|
[transcode]
|
||||||
|
hls = true
|
||||||
|
hlsFlags = '[hls_time=2:hls_list_size=3:hls_flags=delete_segments]'
|
||||||
|
dash = false
|
||||||
|
dashFlags = '[f=dash:window_size=3:extra_window_size=5]'
|
|
@ -174,6 +174,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
},
|
},
|
||||||
|
"config": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/config/-/config-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-rOsfIOAcG82AWouK4/vBS/OKz3UPl2T/kP0irExmXJJOoWg2CmdfPLdx56bCoMUMFNh+7soQkQWCUC8DyemiwQ==",
|
||||||
|
"requires": {
|
||||||
|
"json5": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||||
|
@ -508,6 +516,21 @@
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||||
},
|
},
|
||||||
|
"json5": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
||||||
|
"requires": {
|
||||||
|
"minimist": "^1.2.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"minimist": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||||
|
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.15",
|
"version": "4.17.15",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||||
|
@ -985,6 +1008,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
|
||||||
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
|
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
|
||||||
},
|
},
|
||||||
|
"toml": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="
|
||||||
|
},
|
||||||
"type-is": {
|
"type-is": {
|
||||||
"version": "1.6.18",
|
"version": "1.6.18",
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||||
|
|
|
@ -14,9 +14,11 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt": "^3.0.6",
|
"bcrypt": "^3.0.6",
|
||||||
"check-localhost": "0.0.1",
|
"check-localhost": "0.0.1",
|
||||||
|
"config": "^3.2.2",
|
||||||
"irc": "^0.5.2",
|
"irc": "^0.5.2",
|
||||||
"mysql": "^2.17.1",
|
"mysql": "^2.17.1",
|
||||||
"node-media-server": ">=2.1.3 <3.0.0"
|
"node-media-server": ">=2.1.3 <3.0.0",
|
||||||
|
"toml": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^12.7.5"
|
"@types/node": "^12.7.5"
|
||||||
|
|
|
@ -1,44 +1,71 @@
|
||||||
import * as mediaserver from "./server";
|
import * as mediaserver from "./server";
|
||||||
import * as ircd from "./ircd";
|
import * as ircd from "./ircd";
|
||||||
import * as db from "./database";
|
import * as db from "./database";
|
||||||
|
const config = require('config');
|
||||||
|
|
||||||
const mediaconfig: any = {
|
/*var dbcfg: object;
|
||||||
rtmp: {
|
var servercfg: object;
|
||||||
port: 1935,
|
var bcryptcfg: object;
|
||||||
chunk_size: 60000,
|
var satyrcfg: object;
|
||||||
gop_cache: true,
|
var ircdcfg: object;
|
||||||
ping: 30,
|
|
||||||
ping_timeout: 60
|
|
||||||
},
|
|
||||||
http: {
|
|
||||||
port:8000,
|
|
||||||
allow_origin: '*',
|
|
||||||
mediaroot: './site'
|
|
||||||
},
|
|
||||||
trans: {
|
|
||||||
ffmpeg: '/usr/bin/ffmpeg',
|
|
||||||
tasks: [
|
|
||||||
{
|
|
||||||
app: 'live',
|
|
||||||
hls: 'true',
|
|
||||||
hlsFlags: '[hls_time=2:hls_list_size=3:hls_flags=delete_segments]'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const dbconfig: any = {
|
|
||||||
connectionLimit: 50,
|
|
||||||
host : 'localhost',
|
|
||||||
user : 'satyr',
|
|
||||||
password : 'password',
|
|
||||||
database : 'satyr_db'
|
|
||||||
};
|
|
||||||
|
|
||||||
function boot(): void{
|
function init(): void{
|
||||||
db.run(dbconfig);
|
dbcfg = config.get('database');
|
||||||
mediaserver.boot(mediaconfig);
|
bcryptcfg = config.get('bcrypt');
|
||||||
|
servercfg = config.get('server');
|
||||||
|
satyrcfg = config.get('satyr');
|
||||||
|
ircdcfg = config.get('ircd');
|
||||||
|
}*/
|
||||||
|
|
||||||
|
function run(): void{
|
||||||
|
//init();
|
||||||
|
const dbcfg = config.database;
|
||||||
|
const bcryptcfg = config.bcrypt;
|
||||||
|
const satyr: object = {
|
||||||
|
privateEndpoint: config.media.privateEndpoint,
|
||||||
|
record: config.media.record,
|
||||||
|
streamKeys: config.media.streamKeys,
|
||||||
|
registration: config.satyr.registration,
|
||||||
|
webFormat: config.satyr.webFormat,
|
||||||
|
restrictedNames: config.satyr.restrictedNames
|
||||||
|
};
|
||||||
|
const nms: object = {
|
||||||
|
logType: config.server.logs,
|
||||||
|
rtmp: {
|
||||||
|
port: config.server.rtmp.port,
|
||||||
|
chunk_size: config.server.rtmp.chunk_size,
|
||||||
|
gop_cache: config.server.rtmp.gop_cache,
|
||||||
|
ping: config.server.rtmp.ping,
|
||||||
|
ping_timeout: config.server.rtmp.ping_timeout,
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
port: config.server.http.port,
|
||||||
|
mediaroot: config.server.http.directory,
|
||||||
|
allow_origin: config.server.http.allow_origin
|
||||||
|
},
|
||||||
|
trans: {
|
||||||
|
ffmpeg: config.media.ffmpeg,
|
||||||
|
tasks: [
|
||||||
|
{
|
||||||
|
app: config.media.publicEndpoint,
|
||||||
|
hls: config.transcode.hls,
|
||||||
|
hlsFlags: config.transcode.hlsFlags,
|
||||||
|
dash: config.transcode.dash,
|
||||||
|
dashFlags: config.transcode.dashFlags
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
auth: {
|
||||||
|
api: config.server.api,
|
||||||
|
api_user: config.server.api_user,
|
||||||
|
api_pass: config.server.api_pass
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
db.run(dbcfg, bcryptcfg);
|
||||||
|
mediaserver.boot(nms, satyr);
|
||||||
ircd.boot();
|
ircd.boot();
|
||||||
}
|
}
|
||||||
boot();
|
run();
|
||||||
export { boot };
|
export { run };
|
|
@ -1,9 +1,11 @@
|
||||||
import * as mysql from "mysql";
|
import * as mysql from "mysql";
|
||||||
import * as bcrypt from "bcrypt";
|
import * as bcrypt from "bcrypt";
|
||||||
var raw: any;
|
var raw: any;
|
||||||
|
var cryptoconfig: object;
|
||||||
|
|
||||||
function run (dbconfig: any){
|
function run (db: object, bcrypt: object){
|
||||||
raw = mysql.createPool(dbconfig);
|
raw = mysql.createPool(db);
|
||||||
|
cryptoconfig = bcrypt;
|
||||||
}
|
}
|
||||||
|
|
||||||
function streamKeyAuth(key: string){
|
function streamKeyAuth(key: string){
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import * as NodeMediaServer from "node-media-server";
|
import * as NodeMediaServer from "node-media-server";
|
||||||
import { mkdir } from "fs";
|
import { mkdir } from "fs";
|
||||||
import * as db from "./database";
|
import * as db from "./database";
|
||||||
|
//import { transcode } from "buffer";
|
||||||
const isLocal = require("check-localhost");
|
const isLocal = require("check-localhost");
|
||||||
const { exec } = require('child_process');
|
const { exec } = require('child_process');
|
||||||
|
|
||||||
function boot (mediaconfig: any) {
|
function boot (mediaconfig: any, satyrconfig: any) {
|
||||||
const nms = new NodeMediaServer(mediaconfig);
|
const nms = new NodeMediaServer(mediaconfig);
|
||||||
nms.run();
|
nms.run();
|
||||||
|
|
||||||
nms.on('postPublish', (id, StreamPath, args) => {
|
nms.on('postPublish', (id, StreamPath, args) => {
|
||||||
|
//this is unreadable, add some comments
|
||||||
console.log("[NodeMediaServer] Prepublish Hook for stream:",id);
|
console.log("[NodeMediaServer] Prepublish Hook for stream:",id);
|
||||||
let session = nms.getSession(id);
|
let session = nms.getSession(id);
|
||||||
let app: string = StreamPath.split("/")[1];
|
let app: string = StreamPath.split("/")[1];
|
||||||
|
@ -18,30 +20,30 @@ function boot (mediaconfig: any) {
|
||||||
session.reject();
|
session.reject();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(app === "live") {
|
if(app === mediaconfig.trans.tasks.app) {
|
||||||
isLocal(session.ip).then( (local) => {
|
isLocal(session.ip).then( (local) => {
|
||||||
if(local) {
|
if(local) {
|
||||||
console.log("[NodeMediaServer] Local publish, stream:",`${id} ok.`);
|
console.log("[NodeMediaServer] Local publish, stream:",`${id} ok.`);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
console.log("[NodeMediaServer] Non-local Publish to /live, rejecting stream:",id);
|
console.log("[NodeMediaServer] Non-local Publish to public endpoint, rejecting stream:",id);
|
||||||
session.reject();
|
session.reject();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log("[NodeMediaServer] Public endpoint, checking record flag.");
|
console.log("[NodeMediaServer] Public endpoint, checking record flag.");
|
||||||
db.raw.query('select username,record_flag from users where username=\''+key+'\' and record_flag=true limit 1', (error, results, fields) => {
|
db.raw.query('select username,record_flag from users where username=\''+key+'\' and record_flag=true limit 1', (error, results, fields) => {
|
||||||
if (error) {throw error;}
|
if (error) {throw error;}
|
||||||
if(results[0]){
|
if(results[0] && satyrconfig.record){
|
||||||
console.log('[NodeMediaServer] Initiating recording for stream:',id);
|
console.log('[NodeMediaServer] Initiating recording for stream:',id);
|
||||||
mkdir('./site/live/'+results[0].username, { recursive : true }, (err) => {
|
mkdir(mediaconfig.http.mediaroot+'/'+mediaconfig.trans.tasks.app+'/'+results[0].username, { recursive : true }, (err) => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
let subprocess = exec('ffmpeg -i rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+mediaconfig.trans.tasks.app+'/'+results[0].username+' -vcodec copy -acodec copy '+mediaconfig.http.mediaroot+'/'+mediaconfig.trans.tasks.app+'/'+results[0].username+'/$(date +%d%b%Y-%H%M).mp4',{
|
||||||
|
detached : true,
|
||||||
|
stdio : 'inherit'
|
||||||
|
});
|
||||||
|
subprocess.unref();
|
||||||
|
//spawn an ffmpeg process to record the stream, then detach it completely
|
||||||
});
|
});
|
||||||
let subprocess = exec('ffmpeg -i rtmp://127.0.0.1/live/'+results[0].username+' -vcodec copy -acodec copy ./site/live/'+results[0].username+'/$(date +%d%b%Y-%H%M).mp4',{
|
|
||||||
detached : true,
|
|
||||||
stdio : 'inherit'
|
|
||||||
});
|
|
||||||
subprocess.unref();
|
|
||||||
//spawn an ffmpeg process to record the stream, then detach it completely
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log('[NodeMediaServer] Skipping recording for stream:',id);
|
console.log('[NodeMediaServer] Skipping recording for stream:',id);
|
||||||
|
@ -49,8 +51,8 @@ function boot (mediaconfig: any) {
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(app !== "stream"){
|
if(app !== satyrconfig.privateEndpoint){
|
||||||
//app isn't 'live' if we've reached this point
|
//app isn't at public endpoint if we've reached this point
|
||||||
console.log("[NodeMediaServer] Wrong endpoint, rejecting stream:",id);
|
console.log("[NodeMediaServer] Wrong endpoint, rejecting stream:",id);
|
||||||
session.reject();
|
session.reject();
|
||||||
return false;
|
return false;
|
||||||
|
@ -58,7 +60,7 @@ function boot (mediaconfig: any) {
|
||||||
db.raw.query('select username from users where stream_key=\''+key+'\' limit 1', (error, results, fields) => {
|
db.raw.query('select username from users where stream_key=\''+key+'\' limit 1', (error, results, fields) => {
|
||||||
if (error) {throw error;}
|
if (error) {throw error;}
|
||||||
if(results[0]){
|
if(results[0]){
|
||||||
exec('ffmpeg -analyzeduration 0 -i rtmp://localhost/stream/'+key+' -vcodec copy -acodec copy -crf 18 -f flv rtmp://localhost:1935/live/'+results[0].username);
|
exec('ffmpeg -analyzeduration 0 -i rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+satyrconfig.privateEndpoint+'/'+key+' -vcodec copy -acodec copy -crf 18 -f flv rtmp://127.0.0.1:'+mediaconfig.rtmp.port+'/'+mediaconfig.trans.tasks.app+'/'+results[0].username);
|
||||||
console.log('[NodeMediaServer] Stream key okay for stream:',id);
|
console.log('[NodeMediaServer] Stream key okay for stream:',id);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
@ -76,13 +78,13 @@ function boot (mediaconfig: any) {
|
||||||
session.reject();
|
session.reject();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(app === "stream") {
|
if(app === satyrconfig.privateEndpoint) {
|
||||||
isLocal(session.ip).then( (local) => {
|
isLocal(session.ip).then( (local) => {
|
||||||
if(local) {
|
if(local) {
|
||||||
console.log("[NodeMediaServer] Local play, client:",`${id} ok.`);
|
console.log("[NodeMediaServer] Local play, client:",`${id} ok.`);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
console.log("[NodeMediaServer] Non-local Play from /stream, rejecting client:",id);
|
console.log("[NodeMediaServer] Non-local Play from private endpoint, rejecting client:",id);
|
||||||
session.reject();
|
session.reject();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Reference in New Issue