From dfe18c861331f39e4b505c48a059efbe6b0883f7 Mon Sep 17 00:00:00 2001 From: Christoph Johannsdotter Date: Mon, 25 Jan 2016 21:38:04 +0100 Subject: [PATCH] RC4 --- CHANGELOG.md | 18 ++ Dockerfile | 38 ++-- Dockerfile_armv6l | 51 +++--- Dockerfile_armv7l | 47 +++-- README.md | 12 +- bower.json | 2 +- gruntfile.js | 132 ++++++-------- package.json | 25 +-- run.sh | 30 +++- src/classes/Logger.js | 22 ++- src/classes/Restreamer.js | 168 ++++++++---------- src/classes/WebsocketController.js | 32 ++-- src/start.js | 141 +++++++-------- src/webserver/app.js | 47 ++--- src/webserver/config/passport.js | 32 ++-- src/webserver/controllers/index.js | 34 ++-- src/webserver/middlewares/expressLogger.js | 10 +- src/webserver/public/scripts/apps/datarhei.js | 6 +- .../scripts/controllers/languageCtrl.js | 4 +- .../public/scripts/controllers/mainCtrl.js | 122 ++++++++----- .../public/scripts/factories/websockets.js | 10 +- src/webserver/public/scripts/index.js | 2 +- static/webserver/public/index.html | 2 +- static/webserver/public/main.html | 8 +- 24 files changed, 502 insertions(+), 493 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4bc2be..6901ed5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## Changes from 0.1.0-RC3 to 0.1.0-RC4 + +* added https sources to Dockerfiles (thx @ [nodiscc](https://github.com/nodiscc)) +* fixed visualisation problem of new RTMP/RTSP endpoint (JSONDB processing) +* optimized input-process (removed generateOutputRTMPPath) +* cleaned up NPM packages +* added ESLint insteed of JSHint+ first ruleset +* first code optimizations (ecma5 -> ecma6) +* optimized RaspiCam-Hack for Raspberry Pi 1 +* updated NPM packages and node +* refactored FFmpeg-Fluent integration by own fork (reduces process-output) +* fixed output-process (generated high CPU load on arm) +* fixed preview player (no play-icon, didn't stop when the modalbox is closed) + +##### Merged pull requests: + +* Fixed ARM typo @ [Vyacheslav Shevchenko](https://github.com/bliz937) + ## Changes from 0.1.0-RC2 to 0.1.0-RC3 * fixed links to docs diff --git a/Dockerfile b/Dockerfile index b872f86..1ae4999 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,18 @@ -FROM node:4.2.3-slim +FROM node:4.2.6-slim MAINTAINER datarhei ENV FFMPEG_VERSION 2.8.1 ENV YASM_VERSION 1.3.0 -ENV LAME_VERSION 3.99.5 +ENV LAME_VERSION 3_99_5 ENV NGINX_VERSION 1.8.0 +ENV NGINX_RTMP_VERSION 1.1.7 ENV SRC /usr/local ENV LD_LIBRARY_PATH ${SRC}/lib ENV PKG_CONFIG_PATH ${SRC}/lib/pkgconfig -ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev unzip" +ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev" RUN rm -rf /var/lib/apt/lists/* && \ apt-get update && \ @@ -19,8 +20,8 @@ RUN rm -rf /var/lib/apt/lists/* && \ # yasm RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -Os http://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \ - tar xzvf yasm-${YASM_VERSION}.tar.gz && \ + curl -LOks https://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \ + tar xzvf yasm-${YASM_VERSION}.tar.gz && \ cd yasm-${YASM_VERSION} && \ ./configure --prefix="$SRC" --bindir="${SRC}/bin" && \ make && \ @@ -40,9 +41,9 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \ # libmp3lame RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -L -Os http://downloads.sourceforge.net/project/lame/lame/${LAME_VERSION%.*}/lame-${LAME_VERSION}.tar.gz && \ - tar xzvf lame-${LAME_VERSION}.tar.gz && \ - cd lame-${LAME_VERSION} && \ + curl -LOks https://github.com/rbrito/lame/archive/RELEASE__${LAME_VERSION}.tar.gz && \ + tar xzvf RELEASE__${LAME_VERSION}.tar.gz && \ + cd lame-RELEASE__${LAME_VERSION} && \ ./configure --prefix="${SRC}" --bindir="${SRC}/bin" --disable-shared --enable-nasm && \ make && \ make install && \ @@ -51,12 +52,12 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \ # ffmpeg RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -Os http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ - tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + curl -LOks https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \ cd ffmpeg-${FFMPEG_VERSION} && \ ./configure --prefix="${SRC}" --extra-cflags="-I${SRC}/include" --extra-ldflags="-L${SRC}/lib" --bindir="${SRC}/bin" \ - --extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \ - --enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \ + --extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \ + --enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \ make && \ make install && \ make distclean && \ @@ -70,13 +71,12 @@ RUN ffmpeg -buildconf # nginx-rtmp RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -LOks http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ - tar -zxvf nginx-${NGINX_VERSION}.tar.gz && \ - curl -LOks https://github.com/arut/nginx-rtmp-module/archive/master.zip && \ - unzip master.zip && \ - rm master.zip && \ - cd nginx-${NGINX_VERSION} && \ - ./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master && \ + curl -LOks https://github.com/nginx/nginx/archive/release-${NGINX_VERSION}.tar.gz && \ + tar xzvf release-${NGINX_VERSION}.tar.gz && \ + curl -LOks https://github.com/arut/nginx-rtmp-module/archive/v${NGINX_RTMP_VERSION}.tar.gz && \ + tar xzvf v${NGINX_RTMP_VERSION}.tar.gz && \ + cd nginx-release-${NGINX_VERSION} && \ + auto/configure --with-http_ssl_module --add-module=../nginx-rtmp-module-${NGINX_RTMP_VERSION} && \ make && \ make install && \ rm -rf ${DIR} diff --git a/Dockerfile_armv6l b/Dockerfile_armv6l index 28f37e1..45ed7fe 100644 --- a/Dockerfile_armv6l +++ b/Dockerfile_armv6l @@ -2,30 +2,30 @@ FROM resin/rpi-raspbian:jessie MAINTAINER datarhei -ENV NODE_VERSION 4.2.3 -ENV NPM_VERSION 2.14.7 +ENV NODE_VERSION 4.2.6 +ENV NPM_VERSION 2.14.12 ENV FFMPEG_VERSION 2.8.1 ENV YASM_VERSION 1.3.0 -ENV LAME_VERSION 3.99.5 +ENV LAME_VERSION 3_99_5 ENV NGINX_VERSION 1.8.0 +ENV NGINX_RTMP_VERSION 1.1.7 ENV SRC /usr/local ENV LD_LIBRARY_PATH ${SRC}/lib ENV PKG_CONFIG_PATH ${SRC}/lib/pkgconfig -ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev unzip" +ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev" RUN rm -rf /var/lib/apt/lists/* && \ apt-get update && \ - apt-get install -y curl wget git libpcre3 tar ${BUILDDEPS} + apt-get install -y curl git libpcre3 tar ${BUILDDEPS} # node RUN DIR=$(mktemp -d) && cd ${DIR} && \ set -x && \ - wget "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-armv6l.tar.gz" && \ - tar -xzf "node-v$NODE_VERSION-linux-armv6l.tar.gz" -C /usr/local --strip-components=1 && \ - rm "node-v$NODE_VERSION-linux-armv6l.tar.gz" && \ + curl -LOks https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-armv6l.tar.gz && \ + tar -xzf "node-v$NODE_VERSION-linux-armv6l.tar.gz" -C /usr/local --strip-components=1 && \ npm install -g npm@"$NPM_VERSION" --unsafe-perm && \ npm cache clear && \ npm config set unsafe-perm true -g --unsafe-perm && \ @@ -33,8 +33,8 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \ # yasm RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -Os http://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \ - tar xzvf yasm-${YASM_VERSION}.tar.gz && \ + curl -LOks https://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \ + tar xzvf yasm-${YASM_VERSION}.tar.gz && \ cd yasm-${YASM_VERSION} && \ ./configure --prefix="$SRC" --bindir="${SRC}/bin" && \ make && \ @@ -54,9 +54,9 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \ # libmp3lame RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -L -Os http://downloads.sourceforge.net/project/lame/lame/${LAME_VERSION%.*}/lame-${LAME_VERSION}.tar.gz && \ - tar xzvf lame-${LAME_VERSION}.tar.gz && \ - cd lame-${LAME_VERSION} && \ + curl -LOks https://github.com/rbrito/lame/archive/RELEASE__${LAME_VERSION}.tar.gz && \ + tar xzvf RELEASE__${LAME_VERSION}.tar.gz && \ + cd lame-RELEASE__${LAME_VERSION} && \ ./configure --prefix="${SRC}" --bindir="${SRC}/bin" --disable-shared --enable-nasm && \ make && \ make install && \ @@ -65,12 +65,12 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \ # ffmpeg RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -Os http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ - tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + curl -LOks https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \ cd ffmpeg-${FFMPEG_VERSION} && \ ./configure --prefix="${SRC}" --extra-cflags="-I${SRC}/include" --extra-ldflags="-L${SRC}/lib" --bindir="${SRC}/bin" \ - --extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \ - --enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \ + --extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \ + --enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \ make && \ make install && \ make distclean && \ @@ -84,21 +84,22 @@ RUN ffmpeg -buildconf # nginx-rtmp RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -LOks http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ - tar -zxvf nginx-${NGINX_VERSION}.tar.gz && \ - curl -LOks https://github.com/arut/nginx-rtmp-module/archive/master.zip && \ - unzip master.zip && \ - rm master.zip && \ - cd nginx-${NGINX_VERSION} && \ - ./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master && \ + curl -LOks https://github.com/nginx/nginx/archive/release-${NGINX_VERSION}.tar.gz && \ + tar xzvf release-${NGINX_VERSION}.tar.gz && \ + curl -LOks https://github.com/arut/nginx-rtmp-module/archive/v${NGINX_RTMP_VERSION}.tar.gz && \ + tar xzvf v${NGINX_RTMP_VERSION}.tar.gz && \ + cd nginx-release-${NGINX_VERSION} && \ + auto/configure --with-http_ssl_module --add-module=../nginx-rtmp-module-${NGINX_RTMP_VERSION} && \ make && \ make install && \ rm -rf ${DIR} RUN apt-get purge -y --auto-remove ${BUILDDEPS} && \ - apt-get install -y --force-yes git && \ rm -rf /tmp/* +RUN apt-get update && \ + apt-get install -y --force-yes git + COPY . /restreamer WORKDIR /restreamer diff --git a/Dockerfile_armv7l b/Dockerfile_armv7l index 64241a2..23a6b85 100644 --- a/Dockerfile_armv7l +++ b/Dockerfile_armv7l @@ -2,30 +2,30 @@ FROM armbuild/debian:jessie MAINTAINER datarhei -ENV NODE_VERSION 4.2.3 -ENV NPM_VERSION 2.14.7 +ENV NODE_VERSION 4.2.6 +ENV NPM_VERSION 2.14.12 ENV FFMPEG_VERSION 2.8.1 ENV YASM_VERSION 1.3.0 -ENV LAME_VERSION 3.99.5 +ENV LAME_VERSION 3_99_5 ENV NGINX_VERSION 1.8.0 +ENV NGINX_RTMP_VERSION 1.1.7 ENV SRC /usr/local ENV LD_LIBRARY_PATH ${SRC}/lib ENV PKG_CONFIG_PATH ${SRC}/lib/pkgconfig -ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev unzip" +ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev" RUN rm -rf /var/lib/apt/lists/* && \ apt-get update && \ - apt-get install -y curl wget git libpcre3 tar ${BUILDDEPS} + apt-get install -y curl git libpcre3 tar ${BUILDDEPS} # node RUN DIR=$(mktemp -d) && cd ${DIR} && \ set -x && \ - wget "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-armv7l.tar.gz" && \ - tar -xzf "node-v$NODE_VERSION-linux-armv7l.tar.gz" -C /usr/local --strip-components=1 && \ - rm "node-v$NODE_VERSION-linux-armv7l.tar.gz" && \ + curl -LOks https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-armv7l.tar.gz && \ + tar -xzf "node-v$NODE_VERSION-linux-armv7l.tar.gz" -C /usr/local --strip-components=1 && \ npm install -g npm@"$NPM_VERSION" --unsafe-perm && \ npm cache clear && \ npm config set unsafe-perm true -g --unsafe-perm && \ @@ -33,8 +33,8 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \ # yasm RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -Os http://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \ - tar xzvf yasm-${YASM_VERSION}.tar.gz && \ + curl -LOks https://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \ + tar xzvf yasm-${YASM_VERSION}.tar.gz && \ cd yasm-${YASM_VERSION} && \ ./configure --prefix="$SRC" --bindir="${SRC}/bin" && \ make && \ @@ -54,9 +54,9 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \ # libmp3lame RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -L -Os http://downloads.sourceforge.net/project/lame/lame/${LAME_VERSION%.*}/lame-${LAME_VERSION}.tar.gz && \ - tar xzvf lame-${LAME_VERSION}.tar.gz && \ - cd lame-${LAME_VERSION} && \ + curl -LOks https://github.com/rbrito/lame/archive/RELEASE__${LAME_VERSION}.tar.gz && \ + tar xzvf RELEASE__${LAME_VERSION}.tar.gz && \ + cd lame-RELEASE__${LAME_VERSION} && \ ./configure --prefix="${SRC}" --bindir="${SRC}/bin" --disable-shared --enable-nasm && \ make && \ make install && \ @@ -65,12 +65,12 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \ # ffmpeg RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -Os http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ - tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + curl -LOks https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \ cd ffmpeg-${FFMPEG_VERSION} && \ ./configure --prefix="${SRC}" --extra-cflags="-I${SRC}/include" --extra-ldflags="-L${SRC}/lib" --bindir="${SRC}/bin" \ - --extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \ - --enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \ + --extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \ + --enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \ make && \ make install && \ make distclean && \ @@ -84,13 +84,12 @@ RUN ffmpeg -buildconf # nginx-rtmp RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -LOks http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ - tar -zxvf nginx-${NGINX_VERSION}.tar.gz && \ - curl -LOks https://github.com/arut/nginx-rtmp-module/archive/master.zip && \ - unzip master.zip && \ - rm master.zip && \ - cd nginx-${NGINX_VERSION} && \ - ./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master && \ + curl -LOks https://github.com/nginx/nginx/archive/release-${NGINX_VERSION}.tar.gz && \ + tar xzvf release-${NGINX_VERSION}.tar.gz && \ + curl -LOks https://github.com/arut/nginx-rtmp-module/archive/v${NGINX_RTMP_VERSION}.tar.gz && \ + tar xzvf v${NGINX_RTMP_VERSION}.tar.gz && \ + cd nginx-release-${NGINX_VERSION} && \ + auto/configure --with-http_ssl_module --add-module=../nginx-rtmp-module-${NGINX_RTMP_VERSION} && \ make && \ make install && \ rm -rf ${DIR} diff --git a/README.md b/README.md index 1c34680..7d0cbed 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,14 @@ Datarhei/Restreamer offers smart free video streaming in real time. Stream H.264 - Docker and Kitematic (Docker-Toolbox) optimizations and very easy installation ##Roadmap -- RC4 (planned 1.25.2016) - - refactoring ffmpeg-fluent integration - - nginx process monitor - - cleanup packages - - optimizing ui (jsonDB processing, input-validation, clappr-integration) - RC5 (planned 2.1.2016) - - code optimizations (full ecma6, lint, jsdocs) + - start writing tests + - input-validation + - optimizing scope of stats + - cleanup JSONDB - start restructuring code + - cleanup packages + - NGINX process monitor ##Documentation Documentation is available on [Datarhei/Restreamer GitHub pages](https://datarhei.github.io/restreamer/). diff --git a/bower.json b/bower.json index cf284d5..139b2f1 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "Restreamer", - "version": "0.1.0-RC3", + "version": "0.1.0-RC4", "license": "Apache-2.0", "dependencies": { "bootstrap": "3.3.6", diff --git a/gruntfile.js b/gruntfile.js index 86d29fb..fe1d0e0 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -6,7 +6,7 @@ module.exports = function(grunt) { compiledFrontendJS: ['bin/webserver/public/scripts/**/*.js', 'bin/executors/**/gui/js/*.js'], es6Src: ['**/*.js'], stylesheets: ['static/webserver/public/css/*.css'] - }; + }; // find all node modules var modules = []; var pck = require('./package.json') @@ -19,8 +19,8 @@ module.exports = function(grunt) { return './node_modules/' + m + '/**/*' }); } - // Project Configuration - grunt.initConfig({ + // Project Configuration + grunt.initConfig({ watch: { scripts: { files: ['src/**/*.js'], @@ -63,7 +63,7 @@ module.exports = function(grunt) { }, //temp workaround - https://github.com/clappr/clappr/issues/709 clappr: { - command: 'git clone https://github.com/clappr/clappr.git bin/webserver/public/libs/clappr' + command: 'git clone https://github.com/clappr/clappr bin/webserver/public/libs/clappr' } }, babel: { @@ -82,101 +82,85 @@ module.exports = function(grunt) { ] } }, - pkg: grunt.file.readJSON('package.json'), - jshint: { - all: { - src: [ - 'src/*.js', - 'src/classes/*.js', - 'src/webserver/*.js', - 'src/webserver/**/*.js', - 'src/webserver/**/**/*.js', - 'src/webserver/**/**/**/*.js' - ], + pkg: grunt.file.readJSON('package.json'), + eslint: { + all: ['src/**/*.js'], + options: { + configFile: '.eslintrc.json' + } + }, + csslint: { + options: { + csslintrc: '.csslintrc' + }, + all: { + src: ['static/webserver/public/css/*.css'] + } + }, + uglify: { + production: { options: { - jshintrc: '.jshintrc' + mangle: true + }, + files: { + 'bin/webserver/public/dist/application.min.js': 'bin/webserver/public/dist/application.js' } } }, - csslint: { - options: { - csslintrc: '.csslintrc' - }, - all: { - src: ['static/webserver/public/css/*.css'] - } - }, - uglify: { - production: { - options: { - mangle: true - }, - files: { - 'bin/webserver/public/dist/application.min.js': 'bin/webserver/public/dist/application.js' - } - } - }, - cssmin: { - combine: { - files: { - 'bin/webserver/public/css/restreamer.min.css': '<%= stylesheets %>' - } - } - }, - ngAnnotate: { - production: { - files: { - 'bin/webserver/public/dist/application.js': '<%= compiledFrontendJS %>' - } - } - }, - env: { - test: { - NODE_ENV: 'test' - }, - secure: { - NODE_ENV: 'secure' - } - } - }); + cssmin: { + combine: { + files: { + 'bin/webserver/public/css/restreamer.min.css': '<%= stylesheets %>' + } + } + }, + ngAnnotate: { + production: { + files: { + 'bin/webserver/public/dist/application.js': '<%= compiledFrontendJS %>' + } + } + }, + }); - // Load NPM tasks - require('load-grunt-tasks')(grunt); + /* + Load NPM tasks + */ + require('load-grunt-tasks')(grunt); grunt.task.registerTask('loadConfig', 'Task that loads the config into a grunt option.', function() { grunt.config.set('es6Src', files.es6Src); grunt.config.set('compiledFrontendJS', files.compiledFrontendJS); grunt.config.set('stylesheets', files.stylesheets); }); grunt.loadNpmTasks('grunt-shell'); - grunt.loadNpmTasks('grunt-contrib-copy') - grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('gruntify-eslint'); grunt.loadNpmTasks('grunt-contrib-watch'); /* Helper tasks to keep overview - */ - //css lint - grunt.registerTask('lint', ['csslint', 'jshint']); - //clear old bin folder and create new one + */ + // lint + grunt.registerTask('lint', ['csslint', 'eslint']); + // clear old bin folder and create new one grunt.registerTask('clearOldBuild', ['shell:removeOldBinFolder', 'shell:createBinFolder']); - //install frontendlibraries (atm through bower) + // install frontendlibraries (atm through bower) grunt.registerTask('installFrontendLibraries', ['shell:bower', 'shell:clappr']); - //minify the frontend files + // minify the frontend files grunt.registerTask('minifyFrontendFiles', ['cssmin', 'ngAnnotate', 'uglify']); - /* - Build Tasks - */ + /* + Build Tasks + */ grunt.registerTask('build', ['loadConfig','clearOldBuild', 'shell:copyStatics', 'babel', 'minifyFrontendFiles', 'installFrontendLibraries']); grunt.registerTask('build-code', ['loadConfig', 'shell:copyStatics', 'babel', 'minifyFrontendFiles']); /* Run Tasks */ - //run current build in /bin + // run current build in /bin grunt.registerTask('run', ['shell:start']); - //rebuild and run + // rebuild and run grunt.registerTask('run-clean', ['build', 'run']); - //update code and run - grunt.registerTask("run-update-code", ['loadConfig','babel','shell:copyStatics', 'minifyFrontendFiles', 'run']) + // update code and run + grunt.registerTask('run-update-code', ['loadConfig','babel','shell:copyStatics', 'minifyFrontendFiles', 'run']) }; diff --git a/package.json b/package.json index a9b1998..ebe6cf2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Restreamer", - "version": "0.1.0-RC3", + "version": "0.1.0-RC4", "description": "Allows you to do h.264 real-time video streaming on your website without a streaming provider", "author": "datarhei.org", "license": "Apache-2.0", @@ -8,54 +8,35 @@ "start": "node ./bin/start" }, "dependencies": { - "app-root-path": "1.0.0", - "async": "~1.5.0", "body-parser": "1.14.2", "bytes": "^2.1.0", - "colors": "^1.1.2", "compression": "~1.6.0", "connect-flash": "^0.1.1", "cookie-parser": "1.4.0", - "debug": "2.2.0", - "dockerode": "2.2.8", - "ejs": "2.3.4", - "exec": "^0.2.1", "express": "4.13.3", "express-session": "^1.12.1", - "fluent-ffmpeg": "git://github.com/christophjohannsdotter/node-fluent-ffmpeg#FIX_stderr-variable_of_infinite_growth", - "i18n": "0.5.0", + "fluent-ffmpeg": "git://github.com/datarhei/node-fluent-ffmpeg", "jsonschema": "^1.0.2", "moment-timezone": "^0.5.0", - "morgan": "1.6.1", "node-json-db": "^0.5.1", "passport": "^0.3.2", "passport-local": "^1.0.0", "q": "1.4.1", - "q-io": "~1.13.1", "request": "2.67.0", - "sequent": "0.1.2", "serve-favicon": "2.3.0", - "shortid": "2.2.4", "socket.io": "1.4.0" }, "devDependencies": { "babel-preset-es2015": "^6.1.2", - "chai": "^3.3.0", "grunt": "^0.4.5", "grunt-babel": "^6.0.0", - "grunt-concurrent": "~2.1.0", - "grunt-contrib-copy": "0.8", "grunt-contrib-csslint": "^0.5.0", "grunt-contrib-cssmin": "~0.14.0", - "grunt-contrib-jshint": "~0.11.3", "grunt-contrib-uglify": "~0.11.0", "grunt-contrib-watch": "^0.6.1", - "grunt-env": "~0.4.1", "grunt-ng-annotate": "~1.0.1", - "grunt-nodemon": "~0.4.1", - "grunt-nw-builder": "^2.0.0", "grunt-shell": "^1.1.2", - "jshint-stylish": "^2.0.0", + "gruntify-eslint": "^1.3.0", "load-grunt-tasks": "~3.4.0" } } diff --git a/run.sh b/run.sh index a98a03d..f7e1036 100755 --- a/run.sh +++ b/run.sh @@ -1,12 +1,36 @@ #!/bin/bash -cpu=$(uname -m | cut -c 1-3) -if [ "${MODE}" == "RASPICAM" ] && [ "$cpu" == "arm" ]; +CPU_TYPE=$(uname -m | cut -c 1-3) +if [ "${MODE}" == "RASPICAM" ] && [ "$CPU_TYPE" == "arm" ]; then echo "/opt/vc/lib" > /etc/ld.so.conf.d/00-vmcs.conf ldconfig npm start & - sleep 20 + NGINX_RUNNING=0 + until [ "$NGINX_RUNNING" = "1" ]; do + if pgrep "nginx" > /dev/null + then + NGINX_RUNNING=1 + else + NGINX_RUNNING=0 + sleep 5 + fi + done /opt/vc/bin/raspivid -t 0 -w 1280 -h 720 -fps 25 -b 500000 -o - | ffmpeg -i - -c copy -f flv rtmp://127.0.0.1:1935/live/raspicam.stream +elif [ "${MODE}" == "USBCAM" ]; +then + apt-get update && apt-get install -y v4l-utils libv4l-0 + npm start & + NGINX_RUNNING=0 + until [ "$NGINX_RUNNING" = "1" ]; do + if pgrep "nginx" > /dev/null + then + NGINX_RUNNING=1 + else + NGINX_RUNNING=0 + sleep 5 + fi + done + ffmpeg -f v4l2 -r 25 -s 1280x720 -i /dev/video0 -f flv rtmp://127.0.0.1:1935/live/usb.stream else npm start fi diff --git a/src/classes/Logger.js b/src/classes/Logger.js index 283d4a0..8b8463f 100644 --- a/src/classes/Logger.js +++ b/src/classes/Logger.js @@ -7,16 +7,14 @@ 'use strict'; -const moment = require("moment-timezone"); -require("colors"); - +const moment = require('moment-timezone'); const LEVEL_ERROR = 1; const LEVEL_WARN = 2; const LEVEL_INFO = 3; const LEVEL_DEBUG = 4; //set default timezone to use the timezone before the default values are -process.env.TIMEZONE = process.env.TIMEZONE ? process.env.TIMEZONE : "Europe/Berlin"; +process.env.TIMEZONE = process.env.TIMEZONE ? process.env.TIMEZONE : 'Europe/Berlin'; /** * Class for logger @@ -51,11 +49,11 @@ class Logger { return; } if (context === false){ - context = ""; + context = ''; }else{ - context = "(" + context + ")"; + context = '(' + context + ')'; } - var str = "[" + (moment().tz(process.env.TIMEZONE).format('DD-MM-YYYY HH:mm:ss.SSS')) + "] [" + type + "] " + message + " " + context; + var str = '[' + (moment().tz(process.env.TIMEZONE).format('DD-MM-YYYY HH:mm:ss.SSS')) + '] [' + type + '] ' + message + ' ' + context; if (process.env.LOGGER_LEVEL === '4') { console.log(str[color]); } else { @@ -76,7 +74,7 @@ class Logger { alertGui = false; } if (process.env.LOGGER_LEVEL >= LEVEL_INFO) { - return this.stdout(message, context, "INFO", "blue"); + return this.stdout(message, context, 'INFO', 'blue'); } if (alertGui){ //todo: if alertGui is activated on frontend and websocketcontroller, insert emit here @@ -96,9 +94,9 @@ class Logger { alertGui = false; } if (process.env.LOGGER_LEVEL >= LEVEL_WARN) { - return this.stdout(message, context, "WARN", "orange"); + return this.stdout(message, context, 'WARN', 'orange'); } - if (alertGui){ + if (alertGui) { //todo: if alertGui is activated on frontend and websocketcontroller, insert emit here } } @@ -116,7 +114,7 @@ class Logger { alertGui = false; } if (process.env.LOGGER_LEVEL >= LEVEL_DEBUG) { - return this.stdout(message, context, "DEBUG", "yellow"); + return this.stdout(message, context, 'DEBUG', 'yellow'); } if (alertGui){ //todo: if alertGui is activated on frontend and websocketcontroller, insert emit here @@ -137,7 +135,7 @@ class Logger { alertGui = false; } if (process.env.LOGGER_LEVEL >= LEVEL_ERROR) { - return this.stdout(message, context, "ERROR", "red"); + return this.stdout(message, context, 'ERROR', 'red'); } if (alertGui){ //todo: if alertGui is activated on frontend and websocketcontroller, insert emit here diff --git a/src/classes/Restreamer.js b/src/classes/Restreamer.js index cca0497..736d157 100644 --- a/src/classes/Restreamer.js +++ b/src/classes/Restreamer.js @@ -5,34 +5,25 @@ * @license Apache-2.0 */ -const config = require("../../conf/live.json"); -const Logger = require("./Logger"); -const logger = new Logger("Restreamer"); -const WebsocketsController = require("./WebsocketController"); +const config = require('../../conf/live.json'); +const Logger = require('./Logger'); +const logger = new Logger('Restreamer'); +const WebsocketsController = require('./WebsocketController'); const FfmpegCommand = require('fluent-ffmpeg'); -const Q = require("q"); +const Q = require('q'); /** * class Restreamer creates and manages streams through ffmpeg */ class Restreamer{ - /** - * generate output rtmp-path from config-file - * @returns {string} - */ - static generateOutputRTMPPath (){ - var nginx = config.nginx.streaming; - return "rtmp://" + nginx.ip + ":" + nginx.rtmp_port + nginx.rtmp_path + "live.stream"; - } - /** * generate output hls-path from config-file * @returns {string} */ static generateOutputHLSPath (){ var nginx = config.nginx.streaming; - return "rtmp://" + nginx.ip + ":" + nginx.rtmp_port + nginx.hls_path + "live.stream"; + return 'rtmp://' + nginx.ip + ':' + nginx.rtmp_port + nginx.rtmp_hls_path + 'live.stream'; } /** @@ -40,8 +31,8 @@ class Restreamer{ * @returns {string} */ static generateSnapshotPath (){ - const path = require("path"); - return path.join(__dirname, "..", "webserver", "public", "images", "live.jpg"); + const path = require('path'); + return path.join(__dirname, '..', 'webserver', 'public', 'images', 'live.jpg'); } /** @@ -51,14 +42,14 @@ class Restreamer{ static fetchSnapshot(firstSnapshot){ if (Restreamer.data.states.repeatToLocalNginx.type === 'connected' || firstSnapshot){ - var command = new FfmpegCommand(Restreamer.generateOutputRTMPPath()); + var command = new FfmpegCommand(Restreamer.generateOutputHLSPath()); command.output(Restreamer.generateSnapshotPath()); command.outputOption(config.ffmpeg.options.snapshot); command.on('error', (error)=> { - logger.error("Error on fetching snapshot: " + error.toString()); + logger.error('Error on fetching snapshot: ' + error.toString()); }); - command.on("end", () =>{ - logger.info("updated snapshot"); + command.on('end', () =>{ + logger.info('updated snapshot'); Q.delay(process.env.SNAPSHOT_REFRESH_INTERVAL).then(function(){ Restreamer.fetchSnapshot(false); }); @@ -72,13 +63,13 @@ class Restreamer{ * @param {string} processName */ static stopStream(processName){ - logger.info("stopStream " + processName); - Restreamer.updateState(processName, "stopped"); + logger.info('stopStream ' + processName); + Restreamer.updateState(processName, 'stopped'); var processHasBeenSpawned = typeof Restreamer.data.processes[processName].kill === 'function'; if(processHasBeenSpawned){ Restreamer.data.processes[processName].kill(); Restreamer.data.processes[processName] = { - state: "not_connected" + state: 'not_connected' }; } } @@ -88,26 +79,26 @@ class Restreamer{ * after the applicatoin has been killed or stuff */ static restoreFFMpegProcesses(){ - var JsonDB = require("node-json-db"); + var JsonDB = require('node-json-db'); var db = new JsonDB(config.jsondb, true, false); try { - Restreamer.data.addresses = db.getData("/addresses"); - Restreamer.data.states = db.getData("/states"); - Restreamer.data.userActions = db.getData("/userActions"); + Restreamer.data.addresses = db.getData('/addresses'); + Restreamer.data.states = db.getData('/states'); + Restreamer.data.userActions = db.getData('/userActions'); //check if the srcAddress has been repeated to Local Nginx var repeatToLocalNginxIsConnected = Restreamer.data.states.repeatToLocalNginx.type === 'connected'; var repeatToLocalNginxIsConnecting = Restreamer.data.states.repeatToLocalNginx.type === 'connecting'; var repeatToOptionalOutputIsConnected = Restreamer.data.states.repeatToOptionalOutput.type === 'connected'; var repeatToOptionalOutputIsConnecting = Restreamer.data.states.repeatToOptionalOutput.type === 'connecting'; if (Restreamer.data.addresses.srcAddress && (!!repeatToLocalNginxIsConnected || !!repeatToLocalNginxIsConnecting)) { - Restreamer.startStream(Restreamer.data.addresses.srcAddress, "repeatToLocalNginx"); + Restreamer.startStream(Restreamer.data.addresses.srcAddress, 'repeatToLocalNginx'); } if (Restreamer.data.addresses.optionalOutputAddress && (!!repeatToOptionalOutputIsConnected || !!repeatToOptionalOutputIsConnecting)) { - Restreamer.startStream(Restreamer.data.addresses.srcAddress, "repeatToOptionalOutput", Restreamer.data.addresses.optionalOutputAddress); + Restreamer.startStream(Restreamer.data.addresses.srcAddress, 'repeatToOptionalOutput', Restreamer.data.addresses.optionalOutputAddress); } } catch(error){ - logger.error("error restoring ffmpeg process: " + error); + logger.error('error restoring ffmpeg process: ' + error); } } @@ -115,23 +106,23 @@ class Restreamer{ * write JSON file for persistency */ static writeToDB(){ - var JsonDB = require("node-json-db"); + var JsonDB = require('node-json-db'); var db = new JsonDB(config.jsondb, true, false); - db.push("/", Restreamer.extractDataOfStreams()); + db.push('/', Restreamer.extractDataOfStreams()); } /** * send websocket event to GUI to update the state of the streams */ static updateStreamDataOnGui(){ - WebsocketsController.emitToNamespace("/", "updateStreamData", Restreamer.extractDataOfStreams()); + WebsocketsController.emitToNamespace('/', 'updateStreamData', Restreamer.extractDataOfStreams()); } /** * send websocket event to GUI to update the state of the streams */ static updateProgressOnGui(){ - WebsocketsController.emitToNamespace("/", "updateProgress", Restreamer.data.progresses); + WebsocketsController.emitToNamespace('/', 'updateProgress', Restreamer.data.progresses); } /** @@ -159,10 +150,10 @@ class Restreamer{ var ffmpegOptions; if(data.streams.length > 1) { ffmpegOptions = config.ffmpeg.options.native_h264; - logger.debug("Selected ffmpeg.option: native_h264"); + logger.debug(`Selected ffmpeg.option: native_h264`); }else{ ffmpegOptions = config.ffmpeg.options.native_h264_soundless_aac; - logger.debug("Selected ffmpeg.option: native_h264_soundless_aac"); + logger.debug(`Selected ffmpeg.option: native_h264_soundless_aac`); } for (let option of ffmpegOptions){ ffmpegCommand.outputOption(option); @@ -181,7 +172,7 @@ class Restreamer{ * @return {string} name of the new state */ static updateState(processName, state, message){ - logger.debug("Update state of '" + processName + "' from state '" + Restreamer.data.states[processName].type + "' to state '" + state + "'"); + logger.debug(`Update state of "${processName}" from state "${Restreamer.data.states[processName].type}" to state "${state}"`); Restreamer.data.states[processName] = { type: state, message: message @@ -198,7 +189,7 @@ class Restreamer{ * @return {string} name of the new user action */ static updateUserAction(processName, action){ - logger.debug("Set useraction of '" + processName + "' from '" + Restreamer.data.userActions[processName] + "' to '" + action + "'"); + logger.debug(`Set useraction of "${processName}" from "${Restreamer.data.userActions[processName]}" to "${action}"`); Restreamer.data.userActions[processName] = action; Restreamer.writeToDB(); Restreamer.updateStreamDataOnGui(); @@ -214,7 +205,7 @@ class Restreamer{ * @param {string} retryCounter current value of the retry counter (startStream retries automatically if anything fails) */ static startStream(src, streamType, optionalOutput, retryCounter){ - logger.info("start stream " + streamType); + logger.info(`Start stream "${streamType}"`); //update the retry counter for the streamType Restreamer.data.retryCounter[streamType] = typeof retryCounter === 'undefined' ? 0 : retryCounter; @@ -233,34 +224,32 @@ class Restreamer{ // check if the user has clicked 'stop' meanwhile, so the startStream process has to be skipped if (Restreamer.data.userActions[streamType] === 'stop'){ - logger.debug("skipping 'startStream' since 'stopped' has been clicked"); + logger.debug(`Skipping "startStream" since "stopped" has been clicked`); return; } - // update the state on the frontend - Restreamer.updateState(streamType, "connecting"); + // update the state and src address on the frontend + Restreamer.data.addresses.srcAddress = src; + Restreamer.updateState(streamType, 'connecting'); //repeat to local nginx server if (repeatToLocalNginx){ command = new FfmpegCommand(src, { - outputLineLimit: 50 + outputLineLimit: 1 }); //add outputs to the ffmpeg stream - addOutputPromise = Restreamer.addOutput(command, Restreamer.generateOutputRTMPPath()) - .then(function(){ - return Restreamer.addOutput(command, Restreamer.generateOutputHLSPath()); - }) + addOutputPromise = Restreamer.addOutput(command, Restreamer.generateOutputHLSPath()) .catch(function(error){ - logger.error("error adding one or more outputs: " + error.toString); + logger.error(`Error adding one or more outputs: ${error.toString}`); }); //repeat to optional output }else if (repeatToOptionalOutput){ - command = new FfmpegCommand(Restreamer.generateOutputRTMPPath(src, { - outputLineLimit: 50 - })); + command = new FfmpegCommand(Restreamer.generateOutputHLSPath(), { + outputLineLimit: 1 + }); Restreamer.data.addresses.optionalOutputAddress = optionalOutput; addOutputPromise = Restreamer.addOutput(command, optionalOutput); } @@ -273,12 +262,11 @@ class Restreamer{ */ .on('start', function(commandLine){ if (Restreamer.data.userActions[streamType] === 'stop'){ - logger.debug("skipping on 'start' event of ffmpeg command since 'stopped' has been clicked"); + logger.debug(`Skipping on "start" event of FFmpeg command since "stopped" has been clicked`); return; }else{ - logger.debug("FFMPEG spawned: " + commandLine); + logger.debug(`FFmpeg spawned: ${commandLine}`); Restreamer.data.processes[streamType] = command; - Restreamer.data.addresses.srcAddress = src; //fetch snapshot only, if repeated to local nginx if (repeatToLocalNginx){ Restreamer.fetchSnapshot(true); @@ -290,20 +278,20 @@ class Restreamer{ ERROR HANDLER */ .on('error', (error)=>{ - if (error.toString().indexOf("SIGKILL") > -1) { - Restreamer.updateState(streamType, "disconnected"); - logger.info("FFMPEG streaming stopped for " + streamType); + if (error.toString().indexOf('SIGKILL') > -1) { + Restreamer.updateState(streamType, 'disconnected'); + logger.info(`FFmpeg streaming stopped for "${streamType}"`); }else{ Restreamer.data.retryCounter[streamType]++; if (Restreamer.data.retryCounter[streamType] <= config.ffmpeg.monitor.retries) { if (Restreamer.data.userActions[streamType] === 'stop'){ - logger.debug("skipping retry since 'stopped' has been clicked"); + logger.debug(`Skipping retry since "stopped" has been clicked`); return; }else{ - Restreamer.updateState(streamType, "error", error.toString()); - logger.info("Retrying ffmpeg connection to " + src + " after " + config.ffmpeg.monitor.restart_wait + "ms"); + Restreamer.updateState(streamType, 'error', error.toString()); + logger.info(`Retrying FFmpeg connection to "${src}" after "${config.ffmpeg.monitor.restart_wait} ms`); Q.delay(config.ffmpeg.monitor.restart_wait).then(function () { - logger.info("Retry ffmpeg connection to " + src + " retrycounter:" + Restreamer.data.retryCounter[streamType]); + logger.info(`Retry FFmpeg connection to "${src}" retrycounter: ${Restreamer.data.retryCounter[streamType]}`); Restreamer.startStream(src, streamType, optionalOutput, Restreamer.data.retryCounter[streamType]); }); } @@ -315,16 +303,16 @@ class Restreamer{ STREAMING ENDED */ .on('end',()=>{ - Restreamer.updateState(streamType, "disconnected"); + Restreamer.updateState(streamType, 'disconnected'); Restreamer.data.retryCounter[streamType]++; if (Restreamer.data.retryCounter[streamType] <= config.ffmpeg.monitor.retries) { if (Restreamer.data.userActions[streamType] === 'stop'){ - logger.debug("skipping retry since 'stopped' has been clicked"); + logger.debug(`Skipping retry since "stopped" has been clicked`); return; }else{ - logger.info("Retrying ffmpeg connection to " + src + " after " + config.ffmpeg.monitor.restart_wait + "ms"); + logger.info(`Retrying FFmpeg connection to "${src}" after "${config.ffmpeg.monitor.restart_wait}" ms`); Q.delay(config.ffmpeg.monitor.restart_wait).then(function () { - logger.info("Retry ffmpeg connection to " + src + " retrycounter:" + Restreamer.data.retryCounter[streamType]); + logger.info(`Retry FFmpeg connection to "${src}" retrycounter: ${Restreamer.data.retryCounter[streamType]}`); Restreamer.startStream(src, streamType, optionalOutput, Restreamer.data.retryCounter[streamType]); }); } @@ -336,21 +324,21 @@ class Restreamer{ */ var progressMethod = function (progress){ if (Restreamer.data.states[streamType].type === 'connecting'){ - Restreamer.updateState(streamType, "connected"); + Restreamer.updateState(streamType, 'connected'); } Restreamer.data.progresses[streamType] = progress; Restreamer.updateProgressOnGui(); - command.removeAllListeners("progress"); + command.removeAllListeners('progress'); }; command.on('progress', progressMethod); setInterval(()=>{ - if(command.listeners("progress").length === 0) { + if(command.listeners('progress').length === 0) { command.on('progress', progressMethod); } }, 1000); command.exec(); }).catch(function(error){ - logger.error("Error starting ffmpeg command: " + error.toString()); + logger.error(`Error starting FFmpeg command: ${error.toString()}`); }); } @@ -358,20 +346,20 @@ class Restreamer{ * binded on app-start to bind websocketevents of Restreamer */ static bindWebsocketEvents(){ - WebsocketsController.addOnConnectionEventToNamespace("/", function(socket){ - socket.on("startStream", (options)=> { - Restreamer.updateUserAction(options.streamType, "start"); + WebsocketsController.addOnConnectionEventToNamespace('/', function(socket){ + socket.on('startStream', (options)=> { + Restreamer.updateUserAction(options.streamType, 'start'); Restreamer.startStream(options.src, options.streamType, options.optionalOutput); }); - socket.on("stopStream", (streamType)=>{ - Restreamer.updateUserAction(streamType, "stop"); + socket.on('stopStream', (streamType)=>{ + Restreamer.updateUserAction(streamType, 'stop'); Restreamer.stopStream(streamType); }); - socket.on("checkForAppUpdates", ()=>{ - const app = require("../webserver/app"); - socket.emit("checkForAppUpdatesResult", app.get("updateAvailable")); + socket.on('checkForAppUpdates', ()=>{ + const app = require('../webserver/app'); + socket.emit('checkForAppUpdatesResult', app.get('updateAvailable')); }); - socket.on("checkStates", Restreamer.updateStreamDataOnGui); + socket.on('checkStates', Restreamer.updateStreamDataOnGui); }); } @@ -400,26 +388,26 @@ Restreamer.data = { }, states: { repeatToLocalNginx: { - type: "disconnected", - message: "" + type: 'disconnected', + message: '' }, repeatToOptionalOutput: { - type: "disconnected", - message: "" + type: 'disconnected', + message: '' } }, - userActions: { - repeatToLocalNginx: "start", - repeatToOptionalOutput: "start" + userActions: { + repeatToLocalNginx: 'start', + repeatToOptionalOutput: 'start' }, processes: { //overwritten with ffmpeg process if stream has been started repeatToLocalNginx: { - state: "not_connected" + state: 'not_connected' }, //overwritten with ffmpeg process if stream has been started repeatToOptionalOutput: { - state: "not_connected" + state: 'not_connected' } }, progresses: { @@ -429,8 +417,8 @@ Restreamer.data = { repeatToOptionalOutput: {} }, addresses: { - srcAddress: "", - optionalOutputAddress: "" + srcAddress: '', + optionalOutputAddress: '' } }; diff --git a/src/classes/WebsocketController.js b/src/classes/WebsocketController.js index 89be336..7e57f6d 100644 --- a/src/classes/WebsocketController.js +++ b/src/classes/WebsocketController.js @@ -6,10 +6,8 @@ */ 'use strict'; - -const async = require("async"); -const Logger = require("../classes/Logger"); -const logger = new Logger("WebsocketsController"); +const Logger = require('../classes/Logger'); +const logger = new Logger('WebsocketsController'); /** @@ -26,9 +24,9 @@ class WebsocketsController { * @param {object} data data to emit to the client event listener */ static emitToNamespace(namespace, event, data) { - var app = require("../webserver/app"); - app.get("websocketsReady").promise.then(function (io) { - logger.debug("websocket got event " + event + " to namespace " + namespace + "","Websockets"); + var app = require('../webserver/app'); + app.get('websocketsReady').promise.then(function (io) { + logger.debug('websocket got event ' + event + ' to namespace ' + namespace + '','Websockets'); io.of(namespace).emit(event, data); }); } @@ -39,10 +37,10 @@ class WebsocketsController { * @param {function} callback */ static addOnConnectionEventToNamespace(namespace, callback) { - var app = require("../webserver/app"); - app.get("websocketsReady").promise.then(function (io) { + var app = require('../webserver/app'); + app.get('websocketsReady').promise.then(function (io) { var nsp = io.of(namespace); - nsp.on("connection", function (socket) { + nsp.on('connection', function (socket) { callback(socket); }); }); @@ -52,15 +50,15 @@ class WebsocketsController { * bind default events of all classes that are using websocketevents */ static bindDefaultEvents() { - WebsocketsController.addOnConnectionEventToNamespace("/", function (socket) { - socket.on("testConnection", (options)=> { - var packageJson = require("../../package.json"); - socket.emit("connection", packageJson.version); + WebsocketsController.addOnConnectionEventToNamespace('/', function (socket) { + socket.on('getVersion', (options)=> { + var packageJson = require('../../package.json'); + socket.emit('version', packageJson.version); }); - var app = require("../webserver/app"); - socket.emit("publicIp", app.get("publicIp")); + var app = require('../webserver/app'); + socket.emit('publicIp', app.get('publicIp')); }); - require("./Restreamer").bindWebsocketEvents(); + require('./Restreamer').bindWebsocketEvents(); } } diff --git a/src/start.js b/src/start.js index 2ebd5ca..e536af1 100644 --- a/src/start.js +++ b/src/start.js @@ -10,59 +10,60 @@ /* requirements */ -const Logger = require("./classes/Logger"); -const logger = new Logger("start"); -const EnvVar = require("./classes/EnvVar"); -const packageJson = require("../package.json"); +const Logger = require('./classes/Logger'); +const logger = new Logger('start'); +const EnvVar = require('./classes/EnvVar'); +const packageJson = require('../package.json'); const app = require('./webserver/app'); const config = require('../conf/live.json'); -const Q = require("q"); +const Q = require('q'); if(process.env.CREATE_HEAPDUMPS === 'true'){ const heapdump = require('heapdump'); setInterval(function(){ - heapdump.writeSnapshot('heapdump/' + Date.now() + '.heapsnapshot'); + logger.info(`CREATE HEAPDUMP`); + heapdump.writeSnapshot('/restreamer/heapdump/' + Date.now() + '.heapsnapshot'); }, 60000); } if (typeof process.env.LOGGER_LEVEL === 'undefined'){ - process.env.LOGGER_LEVEL = "3"; + process.env.LOGGER_LEVEL = '3'; } /* init simple_streamer with environments */ -logger.info(" _ _ _ _ ", false); -logger.info(" __| | __ _| |_ __ _ _ __| |___ ___(_)", false); -logger.info(" / _ |/ _ | __/ _ | __| _ |/ _ | |", false); -logger.info("| (_| | (_| | || (_| | | | | | | __/| |", false); -logger.info("|_____|_____|_||_____|_| |_| |_|____||_|", false); -logger.info("", false); -logger.info("Restreamer v" + packageJson.version, false); -logger.info("", false); -logger.info("ENVIRONMENTS", false); -logger.info("More informations in our Docs", false); -logger.info("", false); +logger.info(' _ _ _ _ ', false); +logger.info(' __| | __ _| |_ __ _ _ __| |___ ___(_)', false); +logger.info(' / _ |/ _ | __/ _ | __| _ |/ _ | |', false); +logger.info('| (_| | (_| | || (_| | | | | | | __/| |', false); +logger.info('|_____|_____|_||_____|_| |_| |_|____||_|', false); +logger.info('', false); +logger.info('Restreamer v' + packageJson.version, false); +logger.info('', false); +logger.info('ENVIRONMENTS', false); +logger.info('More informations in our Docs', false); +logger.info('', false); // define environment variables var env_vars = []; -env_vars.push(new EnvVar("NODEJS_PORT", false, 3000, "Webserver port of application")); -env_vars.push(new EnvVar("LOGGER_LEVEL", true, "3", "Logger level to defined, what should be logged")); -env_vars.push(new EnvVar("TIMEZONE", true, "Europe/Berlin", "Set the timezone")); -env_vars.push(new EnvVar("SNAPSHOT_REFRESH_INTERVAL", false, 60000, "Interval to create a new Snapshot")); -env_vars.push(new EnvVar("CREATE_HEAPDUMPS", false, "false", "Create Heapdumps of application")); +env_vars.push(new EnvVar('NODEJS_PORT', false, 3000, 'Webserver port of application')); +env_vars.push(new EnvVar('LOGGER_LEVEL', true, '3', 'Logger level to defined, what should be logged')); +env_vars.push(new EnvVar('TIMEZONE', true, 'Europe/Berlin', 'Set the timezone')); +env_vars.push(new EnvVar('SNAPSHOT_REFRESH_INTERVAL', false, 60000, 'Interval to create a new Snapshot')); +env_vars.push(new EnvVar('CREATE_HEAPDUMPS', false, 'false', 'Create Heapdumps of application')); // manage all environments var killProcess = false; for (let e of env_vars){ if(typeof process.env[e.name] !== 'undefined'){ - logger.info("ENV \"" + e.name + "=" + process.env[e.name] + "\", " + e.description); + logger.info(`ENV "${e.name}=${process.env[e.name]}"`, e.description); }else if(e.required === true){ - logger.error("No value set for env " + e.name + ", but it is required"); + logger.error(`No value set for env "${e.name}", but it is required`); killProcess = true; }else{ process.env[e.name] = e.defaultValue; - logger.info("ENV \"" + e.name + "=" + process.env[e.name] + "\", set to default-value!, " + e.description); + logger.info(`ENV "${e.name}=${process.env[e.name]}", set to default-value!`, e.description); } } @@ -72,68 +73,68 @@ if(killProcess === true){ process.exit(); }, 500); } -logger.info("", false); +logger.info('', false); /** * check if the data from jsondb is valid against the Restreamer jsondb schema * @returns {promise} */ const checkJsonDb = function(){ - logger.info("checking jsondb file..."); + logger.info(`Checking jsondb file...`); var Validator = require('jsonschema').Validator; - var fs = require("fs"); - var path = require("path"); + var fs = require('fs'); + var path = require('path'); var schemadata; var dbdata; var deferred = Q.defer(); - var readSchema = Q.nfcall(fs.readFile, path.join(__dirname, "../", "conf", "jsondb_v1_schema.json")); - var readDBFile = Q.nfcall(fs.readFile, path.join(__dirname, "../", "db", "v1.json")); + var readSchema = Q.nfcall(fs.readFile, path.join(__dirname, '../', 'conf', 'jsondb_v1_schema.json')); + var readDBFile = Q.nfcall(fs.readFile, path.join(__dirname, '../', 'db', 'v1.json')); readSchema - .then(function(s){ - schemadata = JSON.parse(s.toString("utf8")); - return readDBFile; - }) - .then(function(d){ - dbdata = JSON.parse(d.toString("utf8")); - var v = new Validator(); - var instance = dbdata; - var schema = schemadata; - var validateResult = v.validate(instance, schema); - if (validateResult.errors.length > 0){ - logger.debug("validation error of v1.db: " + JSON.stringify(validateResult.errors)); + .then(function(s){ + schemadata = JSON.parse(s.toString('utf8')); + return readDBFile; + }) + .then(function(d){ + dbdata = JSON.parse(d.toString('utf8')); + var v = new Validator(); + var instance = dbdata; + var schema = schemadata; + var validateResult = v.validate(instance, schema); + if (validateResult.errors.length > 0){ + logger.debug(`Validation error of v1.db: ${JSON.stringify(validateResult.errors)}`); throw new Error(JSON.stringify(validateResult.errors)); - }else{ - logger.debug("v1.db is valid"); + }else{ + logger.debug(`"v1.db" is valid`); deferred.resolve(); - } + } }).catch(function(error){ - logger.debug("error reading v1.db:" + error.toString()); + logger.debug(`Error reading "v1.db": ${error.toString()}`); var defaultStructure = { addresses: { - srcAddress: "", - optionalOutputAddress: "" + srcAddress: '', + optionalOutputAddress: '' }, states: { repeatToLocalNginx: { - type: "stopped" + type: 'stopped' }, repeatToOptionalOutput: { - type: "stopped" + type: 'stopped' } }, userActions:{ - repeatToLocalNginx: "stop", - repeatToOptionalOutput: "stop" + repeatToLocalNginx: 'stop', + repeatToOptionalOutput: 'stop' }, progresses: { repeatToLocalNginx: {}, repeatToOptionalOutput: {} } }; - fs.writeFileSync(path.join(__dirname, "../", "db", "v1.json"), JSON.stringify(defaultStructure)); + fs.writeFileSync(path.join(__dirname, '../', 'db', 'v1.json'), JSON.stringify(defaultStructure)); deferred.resolve(); }); return deferred.promise; @@ -144,7 +145,7 @@ const checkJsonDb = function(){ * @returns {promise} */ const startNginxRTMPServer = function startNginxRTMPServer(){ - logger.info("starting nginx server....", "start.nginx"); + logger.info(`Starting nginx server...`, 'start.nginx'); var deferred = Q.defer(); const command = config.nginx.exec; const spawn = require('child_process').spawn; @@ -158,15 +159,15 @@ const startNginxRTMPServer = function startNginxRTMPServer(){ * @returns {promise} */ const startWebserver = function startWebserver(){ - logger.info("starting webserver..."); + logger.info(`Starting webserver...`); var deferred = Q.defer(); app.set('port', process.env.NODEJS_PORT); var server = app.listen(app.get('port'), function () { - require("./classes/WebsocketController").bindDefaultEvents(); - app.set("io", require('socket.io')(server)); - app.set("server", server.address()); - app.get("websocketsReady").resolve(app.get("io")); //promise to determine if the webserver has been started to avoid ws binding before - logger.info("Webserver running on port " + process.env.NODEJS_PORT, "start.webserver"); + require('./classes/WebsocketController').bindDefaultEvents(); + app.set('io', require('socket.io')(server)); + app.set('server', server.address()); + app.get('websocketsReady').resolve(app.get('io')); //promise to determine if the webserver has been started to avoid ws binding before + logger.info(`Webserver running on port ${process.env.NODEJS_PORT}`, 'start.webserver'); deferred.resolve(server.address().port); }); return deferred.promise; @@ -176,13 +177,13 @@ const startWebserver = function startWebserver(){ * get the public ip of the server, on that the Restreamer is running */ const getPublicIp = function(){ - logger.info("Getting public ip...", "start.publicip"); - var exec = require("child_process").exec; - exec("public-ip", (err, stdout, stderr)=> { + logger.info(`Getting public ip...`, 'start.publicip'); + var exec = require('child_process').exec; + exec('public-ip', (err, stdout, stderr)=> { if (err){ - console.log(err); + logger.error(err); } - app.set("publicIp", stdout.split("\n")[0] ); + app.set('publicIp', stdout.split('\n')[0] ); }); }; @@ -191,9 +192,9 @@ const getPublicIp = function(){ * @returns {promise} */ const restoreFFMPEGProcesses = function(){ - logger.info("Restoring ffmpeg processes...", "start.restore"); + logger.info(`Restoring FFmpeg processes...`, 'start.restore'); var deferred = Q.defer(); - const Restreamer = require("./classes/Restreamer"); + const Restreamer = require('./classes/Restreamer'); Restreamer.restoreFFMpegProcesses(); deferred.resolve(); return deferred.promise; @@ -209,7 +210,7 @@ startNginxRTMPServer() .then(restoreFFMPEGProcesses) .then(getPublicIp) .catch(function(error){ - logger.error("error starting webserver and nginx for application: " + error); + logger.error(`Error starting webserver and nginx for application: ${error}`); setTimeout(()=> { process.exit(); }, 500); diff --git a/src/webserver/app.js b/src/webserver/app.js index 8124f42..ce97fb4 100644 --- a/src/webserver/app.js +++ b/src/webserver/app.js @@ -17,26 +17,25 @@ const flash = require('connect-flash'); //express const express = require('express'); const session = require('express-session'); -const i18n = require('i18n'); const favicon = require('serve-favicon'); const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); -const compression = require("compression"); +const compression = require('compression'); //other const path = require('path'); -const Q = require("q"); -const request = require("request"); -const crypto = require("crypto"); +const Q = require('q'); +const request = require('request'); +const crypto = require('crypto'); /* modules */ -const packageJson = require("../../package.json"); -const Logger = require("../classes/Logger"); -const logger = new Logger("Webserver"); +const packageJson = require('../../package.json'); +const Logger = require('../classes/Logger'); +const logger = new Logger('Webserver'); //middlewares -const expressLogger = require("./middlewares/expressLogger"); +const expressLogger = require('./middlewares/expressLogger'); //create express app const app = express(); @@ -49,27 +48,17 @@ app.use(session({ resave: false, saveUninitialized: true})); // session secret -//create promise for "websockets ready" -app.set("websocketsReady", Q.defer()); +//create promise for 'websockets ready' +app.set('websocketsReady', Q.defer()); //add passport auth app.use(passport.initialize()); app.use(flash()); // use connect-flash for flash messages stored in session app.use(passport.session()); // persistent login sessions -require("./config/passport")(passport); - -//configure i18n -i18n.configure({ - locales:['en','de'], - directory: __dirname + '/locales', - defaultLocale: 'en', - cookie: 'locale', - updateFiles: false -}); +require('./config/passport')(passport); //configure express app app.use(favicon(__dirname + '/public/images/favicon.ico')); -app.use(i18n.init); app.use(bodyParser.json()); app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); @@ -78,7 +67,7 @@ app.use(cookieParser()); app.use(compression()); app.set('json spaces', 4); -require("./controllers/index")(app, passport); +require('./controllers/index')(app, passport); app.use('/', expressLogger); // catch 404 and forward to error handler @@ -98,7 +87,7 @@ app.use(function(err, req, res, next) { }); var checkForAppUpdates = function(){ - logger.debug("checking app for updates..."); + logger.debug(`Checking app for updates...`); const url = 'http://datarhei.org/apps.json'; request(url, function (error, response, body) { if (!error && response.statusCode === 200) { @@ -106,15 +95,15 @@ var checkForAppUpdates = function(){ var updateAvailable = false; if (updateCheck.restreamer.version === packageJson.version){ updateAvailable = false; - logger.debug("checking app for updates successful. update is not available (remote: " + updateCheck.restreamer.version + ", local: " + packageJson.version + ")"); + logger.debug(`Checking app for updates successful. Update is not available (remote: ${updateCheck.restreamer.version}, local: ${packageJson.version})`); }else{ updateAvailable = updateCheck.restreamer.version; - logger.debug("checking app for updates successful. update is available (remote: " + updateCheck.restreamer.version + ", local: " + packageJson.version + ")"); + logger.debug(`Checking app for updates successful. Update is available (remote: ${updateCheck.restreamer.version}, local: ${packageJson.version})`); } - logger.info("checking app for updates successful."); - app.set("updateAvailable", updateAvailable); + logger.info(`Checking app for updates successful`); + app.set('updateAvailable', updateAvailable); } else { - logger.info("Update check failed", false); + logger.info(`Update check failed`, false); } }); }; diff --git a/src/webserver/config/passport.js b/src/webserver/config/passport.js index aad4bc8..a836d66 100644 --- a/src/webserver/config/passport.js +++ b/src/webserver/config/passport.js @@ -6,7 +6,7 @@ */ var LocalStrategy = require('passport-local').Strategy; -var auth = require("../../../conf/live.json").auth; +var auth = require('../../../conf/live.json').auth; if (process.env.RESTREAMER_USERNAME) { var username = process.env.RESTREAMER_USERNAME; @@ -30,19 +30,19 @@ module.exports = (passport) => { done(null, user); }); passport.use('local-login', new LocalStrategy({ - usernameField : 'user', - passwordField : 'pass', - passReqToCallback : true // allows us to pass back the entire request to the callback - }, - function(req, user, pass, done) { // callback with user and pass from our form - if (user === username && pass === password){ - //login success - /* - WEBSOCKET SECURITY HERE - */ - done(null, auth); - }else{ - done(null, false, req.flash("wrong password or wrong user")); - } - })); + usernameField: 'user', + passwordField: 'pass', + passReqToCallback: true // allows us to pass back the entire request to the callback + }, + function(req, user, pass, done) { // callback with user and pass from our form + if (user === username && pass === password){ + //login success + /* + WEBSOCKET SECURITY HERE + */ + done(null, auth); + }else{ + done(null, false, req.flash('wrong password or wrong user')); + } + })); }; diff --git a/src/webserver/controllers/index.js b/src/webserver/controllers/index.js index a1a06a5..a6fc337 100644 --- a/src/webserver/controllers/index.js +++ b/src/webserver/controllers/index.js @@ -5,28 +5,28 @@ * @license Apache-2.0 */ -const express = require("express"); -const path = require("path"); -const Restreamer = require("../../classes/Restreamer"); +const express = require('express'); +const path = require('path'); +const Restreamer = require('../../classes/Restreamer'); module.exports = (app, passport) => { //static paths - app.use("/css", express.static(path.join(__dirname, '../', 'public', 'css'))); - app.use("/libs", express.static(path.join(__dirname, '../', 'public', 'libs'))); - app.use("/dist", express.static(path.join(__dirname, '../', 'public', 'dist'))); - app.use("/help", express.static( path.join(__dirname, '../', 'public', 'help'))); - app.use("/images", express.static( path.join(__dirname, '../', 'public', 'images'))); - app.use("/locales", express.static(path.join(__dirname, '../', 'public', 'locales'))); - app.use("/crossdomain.xml",express.static( path.join(__dirname, '../', 'public', 'crossdomain.xml'))); - app.use("/player.html", express.static(path.join(__dirname, '../', 'public', 'player.html'))); - app.get("/main.html", (req, res)=>{ + app.use('/css', express.static(path.join(__dirname, '../', 'public', 'css'))); + app.use('/libs', express.static(path.join(__dirname, '../', 'public', 'libs'))); + app.use('/dist', express.static(path.join(__dirname, '../', 'public', 'dist'))); + app.use('/help', express.static( path.join(__dirname, '../', 'public', 'help'))); + app.use('/images', express.static( path.join(__dirname, '../', 'public', 'images'))); + app.use('/locales', express.static(path.join(__dirname, '../', 'public', 'locales'))); + app.use('/crossdomain.xml',express.static( path.join(__dirname, '../', 'public', 'crossdomain.xml'))); + app.use('/player.html', express.static(path.join(__dirname, '../', 'public', 'player.html'))); + app.get('/main.html', (req, res)=>{ if (req.isAuthenticated()){ res.sendFile(path.join(__dirname, '../', 'public', 'main.html')); } else { res.sendFile(path.join(__dirname, '../', 'public', 'login.html')); } }); - app.get("/", (req, res)=>{ + app.get('/', (req, res)=>{ res.sendFile(path.join(__dirname, '../', 'public', 'index.html')); }); /* Handle Login POST */ @@ -37,19 +37,19 @@ module.exports = (app, passport) => { failureFlash : true }) ); - app.get("/logout", (req, res)=>{ + app.get('/logout', (req, res)=>{ req.logout(); - res.redirect("/"); + res.redirect('/'); }); //small get.api - app.get("/v1/states", (req, res)=>{ + app.get('/v1/states', (req, res)=>{ var states = Restreamer.data.states; res.json({ repeat_to_local_nginx: states.repeatToLocalNginx, repeat_to_optional_output: states.repeatToOptionalOutput }); }); - app.get("/v1/progresses", (req, res)=>{ + app.get('/v1/progresses', (req, res)=>{ var progresses = Restreamer.data.progresses; res.json({ repeat_to_local_nginx: { diff --git a/src/webserver/middlewares/expressLogger.js b/src/webserver/middlewares/expressLogger.js index 2dc7f42..73dec2e 100644 --- a/src/webserver/middlewares/expressLogger.js +++ b/src/webserver/middlewares/expressLogger.js @@ -8,8 +8,8 @@ 'use strict'; const bytes = require('bytes'); -const Logger = require("../../classes/Logger"); -const logger = new Logger("webserver"); +const Logger = require('../../classes/Logger'); +const logger = new Logger('webserver'); module.exports = (req, res, next)=>{ req._startTime = new Date(); @@ -24,9 +24,9 @@ module.exports = (req, res, next)=>{ var duration = ('new Date' - 'req._startTime'); var url = (req.originalUrl || req.url); var method = req.method; - logger.debug(method + " \"" + url + "\" " + code + " " + duration + " " + req.ip + " " + len, "Webserver"); + logger.debug(method + ' \'' + url + '\' ' + code + ' ' + duration + ' ' + req.ip + ' ' + len, 'Webserver'); }; - res.on("finish", log); - res.on("close", log); + res.on('finish', log); + res.on('close', log); next(); }; diff --git a/src/webserver/public/scripts/apps/datarhei.js b/src/webserver/public/scripts/apps/datarhei.js index aa57cd7..2feaaca 100644 --- a/src/webserver/public/scripts/apps/datarhei.js +++ b/src/webserver/public/scripts/apps/datarhei.js @@ -17,12 +17,12 @@ datarheiApp.config(function ($translateProvider) { }); $translateProvider.useSanitizeValueStrategy('escape'); - $translateProvider.preferredLanguage("en_US"); + $translateProvider.preferredLanguage('en_US'); }); datarheiApp.config(function($stateProvider, $urlRouterProvider){ // For any unmatched url, redirect to / - $urlRouterProvider.otherwise("/"); + $urlRouterProvider.otherwise('/'); $stateProvider .state('main',{ @@ -43,7 +43,7 @@ datarheiApp.config(function($stateProvider, $urlRouterProvider){ datarheiApp.filter('inArray', function($filter){ return function(list, arrayFilter, element){ if(arrayFilter){ - return $filter("filter")(list, function(listItem){ + return $filter('filter')(list, function(listItem){ return arrayFilter.indexOf(listItem[element]) !== -1; }); } diff --git a/src/webserver/public/scripts/controllers/languageCtrl.js b/src/webserver/public/scripts/controllers/languageCtrl.js index 3512697..653f1d7 100644 --- a/src/webserver/public/scripts/controllers/languageCtrl.js +++ b/src/webserver/public/scripts/controllers/languageCtrl.js @@ -10,9 +10,9 @@ window.datarheiApp.controller('languageCtrl',['$scope','$translate', function($s $scope.switchLanguage = function(locale){ $scope.currentLocale = locale; $translate.use(locale).then(function(){ - window.Logger.log("INFO", "Switched language to " + locale); + window.Logger.log('INFO', 'Switched language to ' + locale); }, function(error){ - window.Logger.error("INFO", "Switching language to " + locale + " failed: " + error); + window.Logger.error('INFO', 'Switching language to ' + locale + ' failed: ' + error); }); }; $scope.langIs = function(locale){ diff --git a/src/webserver/public/scripts/controllers/mainCtrl.js b/src/webserver/public/scripts/controllers/mainCtrl.js index a598971..09b2f50 100644 --- a/src/webserver/public/scripts/controllers/mainCtrl.js +++ b/src/webserver/public/scripts/controllers/mainCtrl.js @@ -14,109 +14,133 @@ window.datarheiApp.controller('mainCtrl',['ws', '$scope', '$location', '$rootScope', '$translate', function(ws, $scope, $location, $rootScope, $translate) { //binding just once var setup = false; - $translate.use("en_US"); + var player = null; + + const initClappr = function() { + player = new Clappr.Player({ + source: "http://" + window.location.hostname + ":" + window.location.port + "/hls/live.stream.m3u8", + parentId: "#player", + baseUrl: '/libs/clappr/dist/', + poster: "images/live.jpg", + mediacontrol: {seekbar: "#3daa48", buttons: "#3daa48"}, + height: "100%", + width: "100%" + }); + }; + + $translate.use('en_US'); $scope.reStreamerData = { - states: { - repeatToLocalNginx: { - type: "" - }, - repeatToOptionalOutput: { - type: "" - } - }, - userActions: { - repeatToLocalNginx: "", - repeatToOptionalOutput: "" - }, - addresses: { - optionalOutputAddress: "", - srcAddress: "" - } + states: { + repeatToLocalNginx: { + type: '' + }, + repeatToOptionalOutput: { + type: '' + } + }, + userActions: { + repeatToLocalNginx: '', + repeatToOptionalOutput: '' + }, + addresses: { + optionalOutputAddress: '', + srcAddress: '' + } }; $rootScope.windowLocationPort = $location.port(); - $scope.optionalOutput = ""; + $scope.optionalOutput = ''; $scope.showStopButton = function(streamType){ - return $scope.reStreamerData.userActions[streamType] === "start"; + return $scope.reStreamerData.userActions[streamType] === 'start'; }; $scope.showStartButton = function(streamType){ - return $scope.reStreamerData.userActions[streamType] === "stop"; + return $scope.reStreamerData.userActions[streamType] === 'stop'; }; $scope.nginxRepeatStreamConnecting = function(){ - return $scope.reStreamerData.states.repeatToLocalNginx.type === "connecting"; + return $scope.reStreamerData.states.repeatToLocalNginx.type === 'connecting'; }; $scope.nginxRepeatStreamConnected = function(){ - return $scope.reStreamerData.states.repeatToLocalNginx.type === "connected"; + return $scope.reStreamerData.states.repeatToLocalNginx.type === 'connected'; }; $scope.nginxRepeatStreamError = function(){ - return $scope.reStreamerData.states.repeatToLocalNginx.type === "error"; + return $scope.reStreamerData.states.repeatToLocalNginx.type === 'error'; }; $scope.optionalOutputConnecting = function(){ - return $scope.reStreamerData.states.repeatToOptionalOutput.type === "connecting"; + return $scope.reStreamerData.states.repeatToOptionalOutput.type === 'connecting'; }; $scope.optionalOutputConnected = function(){ - return $scope.reStreamerData.states.repeatToOptionalOutput.type === "connected"; + return $scope.reStreamerData.states.repeatToOptionalOutput.type === 'connected'; }; $scope.optionalOutputError = function(){ - return $scope.reStreamerData.states.repeatToOptionalOutput.type === "error"; + return $scope.reStreamerData.states.repeatToOptionalOutput.type === 'error'; }; + $scope.openPlayer = function(){ + if (player === null) { + initClappr(); + } + $("#player-modal").modal("show"); + $('#player-modal').on('hide.bs.modal', function (e) { + player.stop(); + $('#player-modal').off('hide.bs.modal'); + $("#player-modal").modal("hide"); + return e.preventDefault(); + }) + }; + + + + /* Configure Websockets */ //connect to namespace / - ws = ws("/"); + ws = ws('/'); - ws.emit('testConnection'); + ws.emit("getVersion"); //check states of hls and rtmp stream ws.emit('checkStates'); + //check for app updates ws.emit('checkForAppUpdates'); //prohibit double binding of events if (!setup) { + /** * test websockets connection (should print below message to browser console if it works) */ - ws.on("connection", function (version) { + ws.on('version', function (version) { $rootScope.version = version; - window.Logger.log("INFO", "Datarhei " + version + " websockets connected"); - var player = new Clappr.Player({ - source: "http://" + window.location.hostname + ":" + window.location.port + "/hls/live.stream.m3u8", - parentId: "#player", - baseUrl: '/libs/clappr/dist/', - poster: "images/live.jpg", - mediacontrol: {seekbar: "#3daa48", buttons: "#3daa48"}, - height: "100%", - width: "100%" - }); + window.Logger.log('INFO', 'Datarhei ' + version + ' websockets connected'); }); - ws.on("updateProgress", function(progresses){ - $scope.reStreamerData.progresses = progresses; + + ws.on('updateProgress', function(progresses){ + $scope.reStreamerData.progresses = progresses; }); - ws.on("publicIp", function(publicIp){ + ws.on('publicIp', function(publicIp){ $rootScope.publicIp = publicIp; }); - ws.on("updateStreamData", function(reStreamerData) { + ws.on('updateStreamData', function(reStreamerData) { $scope.reStreamerData = reStreamerData; if ($scope.showStopButton('repeatToOptionalOutput')) { $scope.activateOptionalOutput = true; //checkbox; } }); - ws.on("checkForAppUpdatesResult", function(result){ + ws.on('checkForAppUpdatesResult', function(result){ $rootScope.checkForAppUpdatesResult = result; }); } @@ -126,14 +150,14 @@ window.datarheiApp.controller('mainCtrl',['ws', '$scope', '$location', '$rootSco if($scope.activateOptionalOutput === true){ optionalOutput = $scope.reStreamerData.addresses.optionalOutputAddress; } - ws.emit("startStream", { - src: $scope.reStreamerData.addresses.srcAddress, - streamType: streamType, - optionalOutput: optionalOutput + ws.emit('startStream', { + src: $scope.reStreamerData.addresses.srcAddress, + streamType: streamType, + optionalOutput: optionalOutput }); }; $scope.stopStream = function(streamType){ - ws.emit("stopStream", streamType); + ws.emit('stopStream', streamType); }; }]); diff --git a/src/webserver/public/scripts/factories/websockets.js b/src/webserver/public/scripts/factories/websockets.js index 228f3d0..bd1ab8b 100644 --- a/src/webserver/public/scripts/factories/websockets.js +++ b/src/webserver/public/scripts/factories/websockets.js @@ -13,21 +13,21 @@ window.datarheiApp.factory('ws', [ '$rootScope', 'alertService', function ($root var ws = function(namespace){ var wsHandler = {}; - window.Logger.log ("WEBSOCKETS_NAMESPACE", "connect to namespace " + namespace); + window.Logger.log ('WEBSOCKETS_NAMESPACE', `connect to namespace ${namespace}`); var socket; - if (namespace === "/"){ + if (namespace === '/'){ socket = io.connect(); }else{ socket = io.connect(namespace); } wsHandler.emit = function (event, data, callback) { - window.Logger.log("WEBSOCKETS_OUT", "emit event '" + event + "'"); + window.Logger.log('WEBSOCKETS_OUT', `emit event "${event}"`); socket.emit(event, data); return wsHandler; }; wsHandler.on = function (event, callback) { socket.on(event, function () { - window.Logger.log("WEBSOCKETS_IN", "got event '" + event + "'"); + window.Logger.log('WEBSOCKETS_IN', `got event "${event}"`); var args = arguments; $rootScope.$apply(function () { callback.apply(null, args); @@ -39,7 +39,7 @@ window.datarheiApp.factory('ws', [ '$rootScope', 'alertService', function ($root socket.removeListener(event, callback); }; wsHandler - .on("alert", function(alert) { + .on('alert', function(alert) { return alertService.add(alert); }); return wsHandler; diff --git a/src/webserver/public/scripts/index.js b/src/webserver/public/scripts/index.js index cf202b7..0a9fb94 100644 --- a/src/webserver/public/scripts/index.js +++ b/src/webserver/public/scripts/index.js @@ -16,6 +16,6 @@ window.Logger = { WEBSOCKETS_NAMESPACE: 'color: #00BF00; font-weight: bold' }, log: function(level, message){ - console.log("%c " +"[" + level + "] " + message, this.level[level]); + console.log('%c ' +'[' + level + '] ' + message, this.level[level]); } }; diff --git a/static/webserver/public/index.html b/static/webserver/public/index.html index a09a7b0..1f3ddc0 100644 --- a/static/webserver/public/index.html +++ b/static/webserver/public/index.html @@ -59,7 +59,7 @@ -