]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server.ts
Translated using Weblate (Albanian)
[github/Chocobozzz/PeerTube.git] / server.ts
CommitLineData
2aaa1a3f 1import { registerTSPaths } from './server/helpers/register-ts-paths'
2aaa1a3f 2registerTSPaths()
f023a19c 3
1840c2f7 4import { isTestInstance } from './server/helpers/core-utils'
1840c2f7 5if (isTestInstance()) {
e02643f3
C
6 require('source-map-support').install()
7}
8
a030a9b2 9// ----------- Node modules -----------
41fb13c3
C
10import express from 'express'
11import morgan, { token } from 'morgan'
12import cors from 'cors'
13import cookieParser from 'cookie-parser'
14import { frameguard } from 'helmet'
15import { parse } from 'useragent'
16import anonymize from 'ip-anonymize'
8cc61201 17import { program as cli } from 'commander'
a030a9b2 18
9f540774
C
19process.title = 'peertube'
20
a030a9b2 21// Create our main app
6c8c15f9 22const app = express().disable("x-powered-by")
a030a9b2 23
3482688c 24// ----------- Core checker -----------
51c35447 25import { checkMissedConfig, checkFFmpeg, checkNodeVersion } from './server/initializers/checker-before-init'
69b0a27c 26
d5b7d911 27// Do not use barrels because we don't want to load all modules here (we need to initialize database first)
74dc3bca 28import { CONFIG } from './server/initializers/config'
c1340a6a
C
29import { API_VERSION, FILES_CACHE, WEBSERVER, loadLanguages } from './server/initializers/constants'
30import { logger } from './server/helpers/logger'
d5b7d911 31
65fcc311 32const missed = checkMissedConfig()
b65c27aa 33if (missed.length !== 0) {
d5b7d911
C
34 logger.error('Your configuration files miss keys: ' + missed)
35 process.exit(-1)
b65c27aa 36}
3482688c 37
3482688c 38checkFFmpeg(CONFIG)
d5b7d911
C
39 .catch(err => {
40 logger.error('Error in ffmpeg check.', { err })
41 process.exit(-1)
42 })
b65c27aa 43
51c35447
C
44checkNodeVersion()
45
ae71acca 46import { checkConfig, checkActivityPubUrls, checkFFmpegVersion } from './server/initializers/checker-after-init'
e5565833 47
65fcc311 48const errorMessage = checkConfig()
b65c27aa
C
49if (errorMessage !== null) {
50 throw new Error(errorMessage)
69b0a27c
C
51}
52
490b595a
C
53// Trust our proxy (IP forwarding...)
54app.set('trust proxy', CONFIG.TRUST_PROXY)
55
57c36b27 56// Security middleware
418d092a 57import { baseCSP } from './server/middlewares/csp'
5e755fff 58
539d3f4f
C
59if (CONFIG.CSP.ENABLED) {
60 app.use(baseCSP)
8155db66
C
61}
62
63if (CONFIG.SECURITY.FRAMEGUARD.ENABLED) {
41fb13c3 64 app.use(frameguard({
8155db66 65 action: 'deny' // we only allow it for /videos/embed, see server/controllers/client.ts
539d3f4f
C
66 }))
67}
d00e2393 68
3482688c 69// ----------- Database -----------
91fea9fc 70
3482688c 71// Initialize database and models
74055dc8
C
72import { initDatabaseModels, checkDatabaseConnectionOrDie } from './server/initializers/database'
73checkDatabaseConnectionOrDie()
74
91fea9fc
C
75import { migrate } from './server/initializers/migrator'
76migrate()
77 .then(() => initDatabaseModels(false))
3d3441d6
C
78 .then(() => startApplication())
79 .catch(err => {
80 logger.error('Cannot start application.', { err })
81 process.exit(-1)
82 })
3482688c 83
74dc3bca
C
84// ----------- Initialize -----------
85loadLanguages()
86
00057e85 87// ----------- PeerTube modules -----------
80fdaf06 88import { installApplication } from './server/initializers/installer'
ecb4e35f 89import { Emailer } from './server/lib/emailer'
94a5ff8a 90import { JobQueue } from './server/lib/job-queue'
d74d29ad 91import { VideosPreviewCache, VideosCaptionCache } from './server/lib/files-cache'
244e76a5
RK
92import {
93 activityPubRouter,
94 apiRouter,
95 clientsRouter,
96 feedsRouter,
97 staticRouter,
557b13ae 98 lazyStaticRouter,
244e76a5 99 servicesRouter,
c6c0fa6c 100 liveRouter,
345da516 101 pluginsRouter,
9b67da3d
C
102 webfingerRouter,
103 trackerRouter,
c6c0fa6c 104 createWebsocketTrackerServer,
90a8bd30
C
105 botsRouter,
106 downloadRouter
244e76a5 107} from './server/controllers'
aad0ec24 108import { advertiseDoNotTrack } from './server/middlewares/dnt'
e030bfb5 109import { apiFailMiddleware } from './server/middlewares/error'
ecb4e35f 110import { Redis } from './server/lib/redis'
2f5c6b2f 111import { ActorFollowScheduler } from './server/lib/schedulers/actor-follow-scheduler'
cda03765 112import { RemoveOldViewsScheduler } from './server/lib/schedulers/remove-old-views-scheduler'
94a5ff8a 113import { RemoveOldJobsScheduler } from './server/lib/schedulers/remove-old-jobs-scheduler'
2baea0c7 114import { UpdateVideosScheduler } from './server/lib/schedulers/update-videos-scheduler'
ce32426b 115import { YoutubeDlUpdateScheduler } from './server/lib/schedulers/youtube-dl-update-scheduler'
c48e82b5 116import { VideosRedundancyScheduler } from './server/lib/schedulers/videos-redundancy-scheduler'
8f0bc73d 117import { RemoveOldHistoryScheduler } from './server/lib/schedulers/remove-old-history-scheduler'
6f1b4fa4 118import { AutoFollowIndexInstances } from './server/lib/schedulers/auto-follow-index-instances'
f6d6e7f8 119import { RemoveDanglingResumableUploadsScheduler } from './server/lib/schedulers/remove-dangling-resumable-uploads-scheduler'
51353d9a 120import { VideoViewsBufferScheduler } from './server/lib/schedulers/video-views-buffer-scheduler'
df66d815 121import { isHTTPSignatureDigestValid } from './server/helpers/peertube-crypto'
cef534ed 122import { PeerTubeSocket } from './server/lib/peertube-socket'
ae9bbed4 123import { updateStreamingPlaylistsInfohashesIfNeeded } from './server/lib/hls'
e0ce715a 124import { PluginsCheckScheduler } from './server/lib/schedulers/plugins-check-scheduler'
32a18cbf 125import { PeerTubeVersionCheckScheduler } from './server/lib/schedulers/peertube-version-check-scheduler'
89cd1275 126import { Hooks } from './server/lib/plugins/hooks'
464687bb 127import { PluginManager } from './server/lib/plugins/plugin-manager'
8ebf2a5d 128import { LiveManager } from './server/lib/live'
c0e8b12e 129import { HttpStatusCode } from './shared/models/http/http-error-codes'
90a8bd30 130import { VideosTorrentCache } from '@server/lib/files-cache/videos-torrent-cache'
2539932e 131import { ServerConfigManager } from '@server/lib/server-config-manager'
51353d9a 132import { VideoViews } from '@server/lib/video-views'
a030a9b2 133
a030a9b2
C
134// ----------- Command line -----------
135
b83b8dd5
RK
136cli
137 .option('--no-client', 'Start PeerTube without client interface')
66e001c8 138 .option('--no-plugins', 'Start PeerTube without plugins/themes enabled')
a9cd881b 139 .option('--benchmark-startup', 'Automatically stop server when initialized')
b83b8dd5
RK
140 .parse(process.argv)
141
a030a9b2
C
142// ----------- App -----------
143
12daa837
WL
144// Enable CORS for develop
145if (isTestInstance()) {
62945f06
C
146 app.use(cors({
147 origin: '*',
148 exposedHeaders: 'Retry-After',
149 credentials: true
150 }))
12daa837 151}
74dc3bca 152
a030a9b2 153// For the logger
41fb13c3 154token('remote-addr', (req: express.Request) => {
2f6b5e2d 155 if (CONFIG.LOG.ANONYMIZE_IP === true || req.get('DNT') === '1') {
74dc3bca
C
156 return anonymize(req.ip, 16, 16)
157 }
158
159 return req.ip
160})
41fb13c3 161token('user-agent', (req: express.Request) => {
74dc3bca 162 if (req.get('DNT') === '1') {
41fb13c3 163 return parse(req.get('user-agent')).family
74dc3bca
C
164 }
165
166 return req.get('user-agent')
aad0ec24 167})
e02643f3 168app.use(morgan('combined', {
452b3bea 169 stream: {
943dc182 170 write: (str: string) => logger.info(str.trim(), { tags: [ 'http' ] })
452b3bea 171 },
78d62f4d 172 skip: req => CONFIG.LOG.LOG_PING_REQUESTS === false && req.originalUrl === '/api/v1/ping'
e02643f3 173}))
74dc3bca 174
e030bfb5
C
175// Add .fail() helper to response
176app.use(apiFailMiddleware)
1cfbdd30 177
a030a9b2 178// For body requests
1cfbdd30
RK
179app.use(express.urlencoded({ extended: false }))
180app.use(express.json({
86d13ec2 181 type: [ 'application/json', 'application/*+json' ],
df66d815 182 limit: '500kb',
1cfbdd30 183 verify: (req: express.Request, res: express.Response, buf: Buffer) => {
df66d815 184 const valid = isHTTPSignatureDigestValid(buf, req)
e030bfb5 185
1cfbdd30
RK
186 if (valid !== true) {
187 res.fail({
188 status: HttpStatusCode.FORBIDDEN_403,
189 message: 'Invalid digest'
190 })
191 }
df66d815 192 }
165cdc75 193}))
74dc3bca 194
8afc19a6
C
195// Cookies
196app.use(cookieParser())
74dc3bca 197
aad0ec24
RK
198// W3C DNT Tracking Status
199app.use(advertiseDoNotTrack)
a030a9b2 200
a96aed15
C
201// ----------- Views, routes and static files -----------
202
203// API
204const apiRoute = '/api/' + API_VERSION
205app.use(apiRoute, apiRouter)
206
207// Services (oembed...)
208app.use('/services', servicesRouter)
209
c6c0fa6c
C
210// Live streaming
211app.use('/live', liveRouter)
212
345da516 213// Plugins & themes
b5f919ac 214app.use('/', pluginsRouter)
345da516 215
350e31d6 216app.use('/', activityPubRouter)
244e76a5
RK
217app.use('/', feedsRouter)
218app.use('/', webfingerRouter)
9b67da3d 219app.use('/', trackerRouter)
2feebf3e 220app.use('/', botsRouter)
350e31d6 221
a96aed15
C
222// Static files
223app.use('/', staticRouter)
90a8bd30 224app.use('/', downloadRouter)
557b13ae 225app.use('/', lazyStaticRouter)
a96aed15 226
989e526a 227// Client files, last valid routes!
ba5a8d89
C
228const cliOptions = cli.opts()
229if (cliOptions.client) app.use('/', clientsRouter)
a96aed15 230
a030a9b2
C
231// ----------- Errors -----------
232
1cfbdd30
RK
233// Catch unmatched routes
234app.use((req, res: express.Response) => {
235 res.status(HttpStatusCode.NOT_FOUND_404).end()
a030a9b2
C
236})
237
1cfbdd30
RK
238// Catch thrown errors
239app.use((err, req, res: express.Response, next) => {
240 // Format error to be logged
e3a682a8
C
241 let error = 'Unknown error.'
242 if (err) {
243 error = err.stack || err.message || err
244 }
1cfbdd30 245 // Handling Sequelize error traces
328e607d 246 const sql = err.parent ? err.parent.sql : undefined
328e607d 247 logger.error('Error in controller.', { err: error, sql })
1cfbdd30 248
76148b27
RK
249 return res.fail({
250 status: err.status || HttpStatusCode.INTERNAL_SERVER_ERROR_500,
251 message: err.message,
252 type: err.name
253 })
6f4e2522 254})
a030a9b2 255
cef534ed 256const server = createWebsocketTrackerServer(app)
9b67da3d 257
79530164
C
258// ----------- Run -----------
259
3d3441d6 260async function startApplication () {
65fcc311 261 const port = CONFIG.LISTEN.PORT
cff8b272 262 const hostname = CONFIG.LISTEN.HOSTNAME
91fea9fc 263
3d3441d6
C
264 await installApplication()
265
23687332
C
266 // Check activity pub urls are valid
267 checkActivityPubUrls()
268 .catch(err => {
269 logger.error('Error in ActivityPub URLs checker.', { err })
270 process.exit(-1)
271 })
272
ae71acca
C
273 checkFFmpegVersion()
274 .catch(err => logger.error('Cannot check ffmpeg version', { err }))
275
3d3441d6
C
276 // Email initialization
277 Emailer.Instance.init()
3d3441d6 278
0b2f03d3 279 await Promise.all([
75594f47 280 Emailer.Instance.checkConnection(),
2539932e
C
281 JobQueue.Instance.init(),
282 ServerConfigManager.Instance.init()
0b2f03d3 283 ])
3d3441d6
C
284
285 // Caches initializations
d74d29ad
C
286 VideosPreviewCache.Instance.init(CONFIG.CACHE.PREVIEWS.SIZE, FILES_CACHE.PREVIEWS.MAX_AGE)
287 VideosCaptionCache.Instance.init(CONFIG.CACHE.VIDEO_CAPTIONS.SIZE, FILES_CACHE.VIDEO_CAPTIONS.MAX_AGE)
90a8bd30 288 VideosTorrentCache.Instance.init(CONFIG.CACHE.TORRENTS.SIZE, FILES_CACHE.TORRENTS.MAX_AGE)
3d3441d6
C
289
290 // Enable Schedulers
2f5c6b2f 291 ActorFollowScheduler.Instance.enable()
3d3441d6 292 RemoveOldJobsScheduler.Instance.enable()
2baea0c7 293 UpdateVideosScheduler.Instance.enable()
ce32426b 294 YoutubeDlUpdateScheduler.Instance.enable()
c48e82b5 295 VideosRedundancyScheduler.Instance.enable()
8f0bc73d 296 RemoveOldHistoryScheduler.Instance.enable()
cda03765 297 RemoveOldViewsScheduler.Instance.enable()
e0ce715a 298 PluginsCheckScheduler.Instance.enable()
32a18cbf 299 PeerTubeVersionCheckScheduler.Instance.enable()
6f1b4fa4 300 AutoFollowIndexInstances.Instance.enable()
f6d6e7f8 301 RemoveDanglingResumableUploadsScheduler.Instance.enable()
51353d9a 302 VideoViewsBufferScheduler.Instance.enable()
3d3441d6 303
3d3441d6 304 Redis.Instance.init()
cef534ed 305 PeerTubeSocket.Instance.init(server)
51353d9a 306 VideoViews.Instance.init()
cef534ed 307
ae9bbed4
C
308 updateStreamingPlaylistsInfohashesIfNeeded()
309 .catch(err => logger.error('Cannot update streaming playlist infohashes.', { err }))
310
c6c0fa6c 311 LiveManager.Instance.init()
df1db951 312 if (CONFIG.LIVE.ENABLED) await LiveManager.Instance.run()
c6c0fa6c 313
3d3441d6 314 // Make server listening
e19fdf57
C
315 server.listen(port, hostname, async () => {
316 if (cliOptions.plugins) {
317 try {
318 await PluginManager.Instance.registerPluginsAndThemes()
319 } catch (err) {
320 logger.error('Cannot register plugins and themes.', { err })
321 }
322 }
323
c2b82382 324 logger.info('HTTP server listening on %s:%d', hostname, port)
74dc3bca 325 logger.info('Web server: %s', WEBSERVER.URL)
8d76959e 326
89cd1275 327 Hooks.runAction('action:application.listening')
a9cd881b
C
328
329 if (cliOptions['benchmarkStartup']) process.exit(0)
f55e5a7b 330 })
14f2b3ad
C
331
332 process.on('exit', () => {
333 JobQueue.Instance.terminate()
334 })
335
336 process.on('SIGINT', () => process.exit(0))
5804c0db 337}