Added runtime config.

merge-requests/1/merge
knotteye 5 years ago
parent fcff93c533
commit 27eafbd71d
  1. 1
      .gitignore
  2. 55
      config/default.toml
  3. 28
      package-lock.json
  4. 4
      package.json
  5. 99
      src/controller.ts
  6. 6
      src/database.ts
  7. 34
      src/server.ts

1
.gitignore vendored

@ -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]'

28
package-lock.json generated

@ -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();
} }
}); });