server.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import { isTestInstance } from './server/helpers/core-utils'
  2. if (isTestInstance()) {
  3. require('source-map-support').install()
  4. }
  5. // ----------- Node modules -----------
  6. import * as bodyParser from 'body-parser'
  7. import * as express from 'express'
  8. import * as http from 'http'
  9. import * as morgan from 'morgan'
  10. import * as path from 'path'
  11. import * as bitTorrentTracker from 'bittorrent-tracker'
  12. import * as cors from 'cors'
  13. import { Server as WebSocketServer } from 'ws'
  14. const TrackerServer = bitTorrentTracker.Server
  15. process.title = 'peertube'
  16. // Create our main app
  17. const app = express()
  18. // ----------- Core checker -----------
  19. import { checkMissedConfig, checkFFmpeg, checkConfig } from './server/initializers/checker'
  20. const missed = checkMissedConfig()
  21. if (missed.length !== 0) {
  22. throw new Error('Your configuration files miss keys: ' + missed)
  23. }
  24. import { ACCEPT_HEADERS, API_VERSION, CONFIG, STATIC_PATHS } from './server/initializers/constants'
  25. checkFFmpeg(CONFIG)
  26. const errorMessage = checkConfig()
  27. if (errorMessage !== null) {
  28. throw new Error(errorMessage)
  29. }
  30. // ----------- Database -----------
  31. // Do not use barrels because we don't want to load all modules here (we need to initialize database first)
  32. import { logger } from './server/helpers/logger'
  33. // Initialize database and models
  34. import { initDatabaseModels } from './server/initializers/database'
  35. import { migrate } from './server/initializers/migrator'
  36. migrate()
  37. .then(() => initDatabaseModels(false))
  38. .then(() => onDatabaseInitDone())
  39. // ----------- PeerTube modules -----------
  40. import { installApplication } from './server/initializers'
  41. import { activitypubHttpJobScheduler, transcodingJobScheduler } from './server/lib/jobs'
  42. import { VideosPreviewCache } from './server/lib/cache'
  43. import { apiRouter, clientsRouter, staticRouter, servicesRouter, webfingerRouter, activityPubRouter } from './server/controllers'
  44. // ----------- Command line -----------
  45. // ----------- App -----------
  46. // Enable CORS for develop
  47. if (isTestInstance()) {
  48. app.use((req, res, next) => {
  49. // These routes have already cors
  50. if (
  51. req.path.indexOf(STATIC_PATHS.TORRENTS) === -1 &&
  52. req.path.indexOf(STATIC_PATHS.WEBSEED) === -1
  53. ) {
  54. return (cors({
  55. origin: 'http://localhost:3000',
  56. credentials: true
  57. }))(req, res, next)
  58. }
  59. return next()
  60. })
  61. }
  62. // For the logger
  63. app.use(morgan('combined', {
  64. stream: { write: logger.info }
  65. }))
  66. // For body requests
  67. app.use(bodyParser.json({
  68. type: [ 'application/json', 'application/*+json' ],
  69. limit: '500kb'
  70. }))
  71. app.use(bodyParser.urlencoded({ extended: false }))
  72. // ----------- Tracker -----------
  73. const trackerServer = new TrackerServer({
  74. http: false,
  75. udp: false,
  76. ws: false,
  77. dht: false
  78. })
  79. trackerServer.on('error', function (err) {
  80. logger.error(err)
  81. })
  82. trackerServer.on('warning', function (err) {
  83. logger.error(err)
  84. })
  85. const server = http.createServer(app)
  86. const wss = new WebSocketServer({ server: server, path: '/tracker/socket' })
  87. wss.on('connection', function (ws) {
  88. trackerServer.onWebSocketConnection(ws)
  89. })
  90. const onHttpRequest = trackerServer.onHttpRequest.bind(trackerServer)
  91. app.get('/tracker/announce', (req, res) => onHttpRequest(req, res, { action: 'announce' }))
  92. app.get('/tracker/scrape', (req, res) => onHttpRequest(req, res, { action: 'scrape' }))
  93. // ----------- Views, routes and static files -----------
  94. // API
  95. const apiRoute = '/api/' + API_VERSION
  96. app.use(apiRoute, apiRouter)
  97. // Services (oembed...)
  98. app.use('/services', servicesRouter)
  99. app.use('/', webfingerRouter)
  100. app.use('/', activityPubRouter)
  101. // Client files
  102. app.use('/', clientsRouter)
  103. // Static files
  104. app.use('/', staticRouter)
  105. // Always serve index client page (the client is a single page application, let it handle routing)
  106. app.use('/*', function (req, res) {
  107. if (req.accepts(ACCEPT_HEADERS) === 'html') {
  108. return res.sendFile(path.join(__dirname, '../client/dist/index.html'))
  109. }
  110. return res.status(404).end()
  111. })
  112. // ----------- Errors -----------
  113. // Catch 404 and forward to error handler
  114. app.use(function (req, res, next) {
  115. const err = new Error('Not Found')
  116. err['status'] = 404
  117. next(err)
  118. })
  119. app.use(function (err, req, res, next) {
  120. logger.error(err)
  121. res.sendStatus(err.status || 500)
  122. })
  123. // ----------- Run -----------
  124. function onDatabaseInitDone () {
  125. const port = CONFIG.LISTEN.PORT
  126. installApplication()
  127. .then(() => {
  128. // ----------- Make the server listening -----------
  129. server.listen(port, () => {
  130. VideosPreviewCache.Instance.init(CONFIG.CACHE.PREVIEWS.SIZE)
  131. activitypubHttpJobScheduler.activate()
  132. transcodingJobScheduler.activate()
  133. logger.info('Server listening on port %d', port)
  134. logger.info('Web server: %s', CONFIG.WEBSERVER.URL)
  135. })
  136. })
  137. }