2018-06-06 03:35:19 +02:00
// load modules
2018-04-17 23:54:10 +02:00
const express = require ( 'express' ) ;
const bodyParser = require ( 'body-parser' ) ;
const expressHandlebars = require ( 'express-handlebars' ) ;
const helmet = require ( 'helmet' ) ;
const cookieSession = require ( 'cookie-session' ) ;
const http = require ( 'http' ) ;
const logger = require ( 'winston' ) ;
const Path = require ( 'path' ) ;
2018-09-28 05:56:10 +02:00
const httpContext = require ( 'express-http-context' ) ;
2018-06-06 03:35:19 +02:00
// load local modules
2018-09-03 01:48:35 +02:00
const db = require ( './models' ) ;
2018-08-01 01:01:16 +02:00
const requestLogger = require ( './middleware/requestLogger.js' ) ;
const createDatabaseIfNotExists = require ( './models/utils/createDatabaseIfNotExists.js' ) ;
const { getWalletBalance } = require ( './lbrynet/index' ) ;
const configureLogging = require ( './utils/configureLogging.js' ) ;
const configureSlack = require ( './utils/configureSlack.js' ) ;
const speechPassport = require ( './speechPassport/index' ) ;
2018-06-06 03:55:44 +02:00
2018-06-07 00:12:07 +02:00
const {
details : { port : PORT } ,
auth : { sessionKey } ,
2018-06-28 20:31:21 +02:00
startup : {
performChecks ,
performUpdates ,
} ,
2018-06-07 00:12:07 +02:00
} = require ( '@config/siteConfig' ) ;
2018-04-17 23:54:10 +02:00
2018-10-09 02:02:05 +02:00
function logMetricsMiddleware ( req , res , next ) {
res . on ( 'finish' , ( ) => {
const userAgent = req . get ( 'user-agent' ) ;
2018-10-09 20:10:06 +02:00
const routePath = httpContext . get ( 'routePath' ) ;
2018-10-09 02:02:05 +02:00
2018-10-09 02:15:44 +02:00
db . Metrics . create ( {
2018-10-09 02:02:05 +02:00
isInternal : /node\-fetch/ . test ( userAgent ) ,
2018-10-09 20:10:06 +02:00
isChannel : res . isChannel ,
claimId : res . claimId ,
2018-10-09 02:02:05 +02:00
routePath : httpContext . get ( 'routePath' ) ,
params : JSON . stringify ( req . params ) ,
ip : req . headers [ 'x-forwarded-for' ] || req . connection . remoteAddress ,
request : req . url ,
routeData : JSON . stringify ( httpContext . get ( 'routeData' ) ) ,
referrer : req . get ( 'referrer' ) ,
userAgent ,
} ) ;
} ) ;
next ( ) ;
}
2018-09-28 05:56:10 +02:00
function setRouteDataInContextMiddleware ( routePath , routeData ) {
return function ( req , res , next ) {
httpContext . set ( 'routePath' , routePath ) ;
httpContext . set ( 'routeData' , routeData ) ;
next ( ) ;
} ;
}
2018-04-17 23:54:10 +02:00
function Server ( ) {
2018-06-06 21:01:11 +02:00
this . initialize = ( ) => {
// configure logging
configureLogging ( ) ;
// configure slack logging
configureSlack ( ) ;
} ;
2018-04-17 23:54:10 +02:00
this . createApp = ( ) => {
2018-06-06 21:01:11 +02:00
/* create app */
2018-04-17 23:54:10 +02:00
const app = express ( ) ;
// trust the proxy to get ip address for us
app . enable ( 'trust proxy' ) ;
2018-10-18 19:05:01 +02:00
app . use ( ( req , res , next ) => {
if ( req . get ( 'User-Agent' ) === 'Mozilla/5.0 (Windows NT 5.1; rv:14.0) Gecko/20120405 Firefox/14.0a1' ) {
res . status ( 403 ) . send ( '<h1>Forbidden</h1>If you are seeing this by mistake, please contact us using <a href="https://chat.lbry.io/">https://chat.lbry.io/</a>' ) ;
res . end ( ) ;
} else {
next ( ) ;
}
} ) ;
2018-04-17 23:54:10 +02:00
// set HTTP headers to protect against well-known web vulnerabilties
app . use ( helmet ( ) ) ;
2018-05-02 22:08:25 +02:00
2018-09-28 05:56:10 +02:00
// Support per-request http-context
app . use ( httpContext . middleware ) ;
2018-04-17 23:54:10 +02:00
// 'express.static' to serve static files from public directory
2018-05-02 22:08:25 +02:00
const publicPath = Path . resolve ( process . cwd ( ) , 'public' ) ;
app . use ( express . static ( publicPath ) ) ;
logger . info ( ` serving static files from default static path at ${ publicPath } . ` ) ;
2018-04-17 23:54:10 +02:00
// 'body parser' for parsing application/json
app . use ( bodyParser . json ( ) ) ;
2018-05-02 22:08:25 +02:00
2018-04-17 23:54:10 +02:00
// 'body parser' for parsing application/x-www-form-urlencoded
app . use ( bodyParser . urlencoded ( { extended : true } ) ) ;
// add custom middleware (note: build out to accept dynamically use what is in server/middleware/
app . use ( requestLogger ) ;
// initialize passport
app . use ( cookieSession ( {
2018-08-01 01:43:08 +02:00
name : 'session' ,
keys : [ sessionKey ] ,
2018-04-17 23:54:10 +02:00
} ) ) ;
app . use ( speechPassport . initialize ( ) ) ;
app . use ( speechPassport . session ( ) ) ;
// configure handlebars & register it with express app
2018-10-11 07:50:04 +02:00
const viewsPath = Path . resolve ( process . cwd ( ) , 'server/views' ) ;
2018-07-03 03:22:06 +02:00
app . engine ( 'handlebars' , expressHandlebars ( {
2018-08-01 01:43:08 +02:00
async : false ,
dataType : 'text' ,
2018-04-17 23:54:10 +02:00
defaultLayout : 'embed' ,
2018-08-01 01:43:08 +02:00
partialsDir : Path . join ( viewsPath , '/partials' ) ,
layoutsDir : Path . join ( viewsPath , '/layouts' ) ,
2018-07-03 03:22:06 +02:00
} ) ) ;
app . set ( 'views' , viewsPath ) ;
2018-04-17 23:54:10 +02:00
app . set ( 'view engine' , 'handlebars' ) ;
// set the routes on the app
2018-09-28 05:56:10 +02:00
const routes = require ( './routes' ) ;
Object . keys ( routes ) . map ( ( routePath ) => {
let routeData = routes [ routePath ] ;
let routeMethod = routeData . hasOwnProperty ( 'method' ) ? routeData . method : 'get' ;
let controllers = Array . isArray ( routeData . controller ) ? routeData . controller : [ routeData . controller ] ;
2018-10-09 02:02:05 +02:00
app [ routeMethod ] (
routePath ,
logMetricsMiddleware ,
setRouteDataInContextMiddleware ( routePath , routeData ) ,
... controllers ,
) ;
2018-09-28 05:56:10 +02:00
} ) ;
2018-04-17 23:54:10 +02:00
this . app = app ;
} ;
2018-06-06 21:01:11 +02:00
this . createServer = ( ) => {
/* create server */
2018-04-17 23:54:10 +02:00
this . server = http . Server ( this . app ) ;
} ;
2018-06-28 20:19:24 +02:00
this . startServerListening = ( ) => {
logger . info ( ` Starting server on ${ PORT } ... ` ) ;
return new Promise ( ( resolve , reject ) => {
this . server . listen ( PORT , ( ) => {
logger . info ( ` Server is listening on PORT ${ PORT } ` ) ;
resolve ( ) ;
2018-08-01 01:43:08 +02:00
} ) ;
2018-06-28 20:19:24 +02:00
} ) ;
} ;
2018-06-06 21:01:11 +02:00
this . syncDatabase = ( ) => {
2018-06-28 20:19:24 +02:00
logger . info ( ` Syncing database... ` ) ;
2018-06-06 21:01:11 +02:00
return createDatabaseIfNotExists ( )
2018-05-17 23:42:58 +02:00
. then ( ( ) => {
2018-05-18 04:01:35 +02:00
db . sequelize . sync ( ) ;
2018-08-01 01:43:08 +02:00
} ) ;
2018-06-06 21:01:11 +02:00
} ;
2018-06-28 20:31:21 +02:00
this . performChecks = ( ) => {
if ( ! performChecks ) {
return ;
}
logger . info ( ` Performing checks... ` ) ;
2018-06-28 20:19:24 +02:00
return Promise . all ( [
getWalletBalance ( ) ,
2018-06-28 20:31:21 +02:00
] )
. then ( ( [ walletBalance ] ) => {
logger . info ( 'Starting LBC balance:' , walletBalance ) ;
2018-08-01 01:43:08 +02:00
} ) ;
2018-06-28 20:31:21 +02:00
} ;
this . performUpdates = ( ) => {
if ( ! performUpdates ) {
return ;
}
logger . info ( ` Peforming updates... ` ) ;
return Promise . all ( [
2018-07-03 00:27:42 +02:00
db . Blocked . refreshTable ( ) ,
2018-06-28 20:19:24 +02:00
db . Tor . refreshTable ( ) ,
] )
2018-06-28 20:31:21 +02:00
. then ( ( [ updatedBlockedList , updatedTorList ] ) => {
logger . info ( 'Blocked list updated, length:' , updatedBlockedList . length ) ;
logger . info ( 'Tor list updated, length:' , updatedTorList . length ) ;
2018-08-01 01:43:08 +02:00
} ) ;
2018-06-28 20:19:24 +02:00
} ;
2018-06-06 21:01:11 +02:00
this . start = ( ) => {
this . initialize ( ) ;
this . createApp ( ) ;
this . createServer ( ) ;
2018-06-28 19:39:46 +02:00
this . syncDatabase ( )
. then ( ( ) => {
2018-06-28 20:19:24 +02:00
return this . startServerListening ( ) ;
2018-04-17 23:54:10 +02:00
} )
2018-06-28 19:39:46 +02:00
. then ( ( ) => {
2018-06-28 20:31:21 +02:00
return Promise . all ( [
this . performChecks ( ) ,
this . performUpdates ( ) ,
2018-08-01 01:43:08 +02:00
] ) ;
2018-06-28 19:39:46 +02:00
} )
2018-06-28 20:19:24 +02:00
. then ( ( ) => {
2018-06-28 20:31:21 +02:00
logger . info ( 'Spee.ch startup is complete' ) ;
2018-06-28 19:39:46 +02:00
} )
2018-05-18 03:11:22 +02:00
. catch ( error => {
if ( error . code === 'ECONNREFUSED' ) {
2018-08-01 01:43:08 +02:00
return logger . error ( 'Connection refused. The daemon may not be running.' ) ;
2018-06-28 20:19:24 +02:00
} else if ( error . code === 'EADDRINUSE' ) {
return logger . error ( 'Server could not start listening. The port is already in use.' ) ;
2018-05-18 03:11:22 +02:00
} else if ( error . message ) {
logger . error ( error . message ) ;
}
logger . error ( error ) ;
2018-04-17 23:54:10 +02:00
} ) ;
} ;
2018-06-06 21:01:11 +02:00
}
2018-04-17 23:54:10 +02:00
module . exports = Server ;