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
site
config/local.toml
build/**
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",
"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": {
"version": "1.1.0",
"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",
"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": {
"version": "4.17.15",
"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",
"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": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",

@ -14,9 +14,11 @@
"dependencies": {
"bcrypt": "^3.0.6",
"check-localhost": "0.0.1",
"config": "^3.2.2",
"irc": "^0.5.2",
"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": {
"@types/node": "^12.7.5"

@ -1,44 +1,71 @@
import * as mediaserver from "./server";
import * as ircd from "./ircd";
import * as db from "./database";
const config = require('config');
const mediaconfig: any = {
rtmp: {
port: 1935,
chunk_size: 60000,
gop_cache: true,
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]'
}
]
}
};
/*var dbcfg: object;
var servercfg: object;
var bcryptcfg: object;
var satyrcfg: object;
var ircdcfg: object;
const dbconfig: any = {
connectionLimit: 50,
host : 'localhost',
user : 'satyr',
password : 'password',
database : 'satyr_db'
};
function boot(): void{
db.run(dbconfig);
mediaserver.boot(mediaconfig);
function init(): void{
dbcfg = config.get('database');
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();
}
boot();
export { boot };
run();
export { run };

@ -1,9 +1,11 @@
import * as mysql from "mysql";
import * as bcrypt from "bcrypt";
var raw: any;
var cryptoconfig: object;
function run (dbconfig: any){
raw = mysql.createPool(dbconfig);
function run (db: object, bcrypt: object){
raw = mysql.createPool(db);
cryptoconfig = bcrypt;
}
function streamKeyAuth(key: string){

@ -1,14 +1,16 @@
import * as NodeMediaServer from "node-media-server";
import { mkdir } from "fs";
import * as db from "./database";
//import { transcode } from "buffer";
const isLocal = require("check-localhost");
const { exec } = require('child_process');
function boot (mediaconfig: any) {
function boot (mediaconfig: any, satyrconfig: any) {
const nms = new NodeMediaServer(mediaconfig);
nms.run();
nms.on('postPublish', (id, StreamPath, args) => {
//this is unreadable, add some comments
console.log("[NodeMediaServer] Prepublish Hook for stream:",id);
let session = nms.getSession(id);
let app: string = StreamPath.split("/")[1];
@ -18,30 +20,30 @@ function boot (mediaconfig: any) {
session.reject();
return false;
}
if(app === "live") {
if(app === mediaconfig.trans.tasks.app) {
isLocal(session.ip).then( (local) => {
if(local) {
console.log("[NodeMediaServer] Local publish, stream:",`${id} ok.`);
}
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();
}
});
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) => {
if (error) {throw error;}
if(results[0]){
if(results[0] && satyrconfig.record){
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;
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 {
console.log('[NodeMediaServer] Skipping recording for stream:',id);
@ -49,8 +51,8 @@ function boot (mediaconfig: any) {
});
return true;
}
if(app !== "stream"){
//app isn't 'live' if we've reached this point
if(app !== satyrconfig.privateEndpoint){
//app isn't at public endpoint if we've reached this point
console.log("[NodeMediaServer] Wrong endpoint, rejecting stream:",id);
session.reject();
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) => {
if (error) {throw error;}
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);
}
else{
@ -76,13 +78,13 @@ function boot (mediaconfig: any) {
session.reject();
return false;
}
if(app === "stream") {
if(app === satyrconfig.privateEndpoint) {
isLocal(session.ip).then( (local) => {
if(local) {
console.log("[NodeMediaServer] Local play, client:",`${id} ok.`);
}
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();
}
});