]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server.ts
Translated using Weblate (Spanish)
[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'
df66d815 120import { isHTTPSignatureDigestValid } from './server/helpers/peertube-crypto'
cef534ed 121import { PeerTubeSocket } from './server/lib/peertube-socket'
ae9bbed4 122import { updateStreamingPlaylistsInfohashesIfNeeded } from './server/lib/hls'
e0ce715a 123import { PluginsCheckScheduler } from './server/lib/schedulers/plugins-check-scheduler'
32a18cbf 124import { PeerTubeVersionCheckScheduler } from './server/lib/schedulers/peertube-version-check-scheduler'
89cd1275 125import { Hooks } from './server/lib/plugins/hooks'
464687bb 126import { PluginManager } from './server/lib/plugins/plugin-manager'
8ebf2a5d 127import { LiveManager } from './server/lib/live'
c0e8b12e 128import { HttpStatusCode } from './shared/models/http/http-error-codes'
90a8bd30 129import { VideosTorrentCache } from '@server/lib/files-cache/videos-torrent-cache'
2539932e 130import { ServerConfigManager } from '@server/lib/server-config-manager'
a030a9b2 131
a030a9b2
C
132// ----------- Command line -----------
133
b83b8dd5
RK
134cli
135 .option('--no-client', 'Start PeerTube without client interface')
66e001c8 136 .option('--no-plugins', 'Start PeerTube without plugins/themes enabled')
b83b8dd5
RK
137 .parse(process.argv)
138
a030a9b2
C
139// ----------- App -----------
140
12daa837
WL
141// Enable CORS for develop
142if (isTestInstance()) {
62945f06
C
143 app.use(cors({
144 origin: '*',
145 exposedHeaders: 'Retry-After',
146 credentials: true
147 }))
12daa837 148}
74dc3bca 149
a030a9b2 150// For the logger
41fb13c3 151token('remote-addr', (req: express.Request) => {
2f6b5e2d 152 if (CONFIG.LOG.ANONYMIZE_IP === true || req.get('DNT') === '1') {
74dc3bca
C
153 return anonymize(req.ip, 16, 16)
154 }
155
156 return req.ip
157})
41fb13c3 158token('user-agent', (req: express.Request) => {
74dc3bca 159 if (req.get('DNT') === '1') {
41fb13c3 160 return parse(req.get('user-agent')).family
74dc3bca
C
161 }
162
163 return req.get('user-agent')
aad0ec24 164})
e02643f3 165app.use(morgan('combined', {
452b3bea 166 stream: {
943dc182 167 write: (str: string) => logger.info(str.trim(), { tags: [ 'http' ] })
452b3bea 168 },
78d62f4d 169 skip: req => CONFIG.LOG.LOG_PING_REQUESTS === false && req.originalUrl === '/api/v1/ping'
e02643f3 170}))
74dc3bca 171
e030bfb5
C
172// Add .fail() helper to response
173app.use(apiFailMiddleware)
1cfbdd30 174
a030a9b2 175// For body requests
1cfbdd30
RK
176app.use(express.urlencoded({ extended: false }))
177app.use(express.json({
86d13ec2 178 type: [ 'application/json', 'application/*+json' ],
df66d815 179 limit: '500kb',
1cfbdd30 180 verify: (req: express.Request, res: express.Response, buf: Buffer) => {
df66d815 181 const valid = isHTTPSignatureDigestValid(buf, req)
e030bfb5 182
1cfbdd30
RK
183 if (valid !== true) {
184 res.fail({
185 status: HttpStatusCode.FORBIDDEN_403,
186 message: 'Invalid digest'
187 })
188 }
df66d815 189 }
165cdc75 190}))
74dc3bca 191
8afc19a6
C
192// Cookies
193app.use(cookieParser())
74dc3bca 194
aad0ec24
RK
195// W3C DNT Tracking Status
196app.use(advertiseDoNotTrack)
a030a9b2 197
a96aed15
C
198// ----------- Views, routes and static files -----------
199
200// API
201const apiRoute = '/api/' + API_VERSION
202app.use(apiRoute, apiRouter)
203
204// Services (oembed...)
205app.use('/services', servicesRouter)
206
c6c0fa6c
C
207// Live streaming
208app.use('/live', liveRouter)
209
345da516 210// Plugins & themes
b5f919ac 211app.use('/', pluginsRouter)
345da516 212
350e31d6 213app.use('/', activityPubRouter)
244e76a5
RK
214app.use('/', feedsRouter)
215app.use('/', webfingerRouter)
9b67da3d 216app.use('/', trackerRouter)
2feebf3e 217app.use('/', botsRouter)
350e31d6 218
a96aed15
C
219// Static files
220app.use('/', staticRouter)
90a8bd30 221app.use('/', downloadRouter)
557b13ae 222app.use('/', lazyStaticRouter)
a96aed15 223
989e526a 224// Client files, last valid routes!
ba5a8d89
C
225const cliOptions = cli.opts()
226if (cliOptions.client) app.use('/', clientsRouter)
a96aed15 227
a030a9b2
C
228// ----------- Errors -----------
229
1cfbdd30
RK
230// Catch unmatched routes
231app.use((req, res: express.Response) => {
232 res.status(HttpStatusCode.NOT_FOUND_404).end()
a030a9b2
C
233})
234
1cfbdd30
RK
235// Catch thrown errors
236app.use((err, req, res: express.Response, next) => {
237 // Format error to be logged
e3a682a8
C
238 let error = 'Unknown error.'
239 if (err) {
240 error = err.stack || err.message || err
241 }
1cfbdd30 242 // Handling Sequelize error traces
328e607d 243 const sql = err.parent ? err.parent.sql : undefined
328e607d 244 logger.error('Error in controller.', { err: error, sql })
1cfbdd30 245
76148b27
RK
246 return res.fail({
247 status: err.status || HttpStatusCode.INTERNAL_SERVER_ERROR_500,
248 message: err.message,
249 type: err.name
250 })
6f4e2522 251})
a030a9b2 252
cef534ed 253const server = createWebsocketTrackerServer(app)
9b67da3d 254
79530164
C
255// ----------- Run -----------
256
3d3441d6 257async function startApplication () {
65fcc311 258 const port = CONFIG.LISTEN.PORT
cff8b272 259 const hostname = CONFIG.LISTEN.HOSTNAME
91fea9fc 260
3d3441d6
C
261 await installApplication()
262
23687332
C
263 // Check activity pub urls are valid
264 checkActivityPubUrls()
265 .catch(err => {
266 logger.error('Error in ActivityPub URLs checker.', { err })
267 process.exit(-1)
268 })
269
ae71acca
C
270 checkFFmpegVersion()
271 .catch(err => logger.error('Cannot check ffmpeg version', { err }))
272
3d3441d6
C
273 // Email initialization
274 Emailer.Instance.init()
3d3441d6 275
0b2f03d3 276 await Promise.all([
75594f47 277 Emailer.Instance.checkConnection(),
2539932e
C
278 JobQueue.Instance.init(),
279 ServerConfigManager.Instance.init()
0b2f03d3 280 ])
3d3441d6
C
281
282 // Caches initializations
d74d29ad
C
283 VideosPreviewCache.Instance.init(CONFIG.CACHE.PREVIEWS.SIZE, FILES_CACHE.PREVIEWS.MAX_AGE)
284 VideosCaptionCache.Instance.init(CONFIG.CACHE.VIDEO_CAPTIONS.SIZE, FILES_CACHE.VIDEO_CAPTIONS.MAX_AGE)
90a8bd30 285 VideosTorrentCache.Instance.init(CONFIG.CACHE.TORRENTS.SIZE, FILES_CACHE.TORRENTS.MAX_AGE)
3d3441d6
C
286
287 // Enable Schedulers
2f5c6b2f 288 ActorFollowScheduler.Instance.enable()
3d3441d6 289 RemoveOldJobsScheduler.Instance.enable()
2baea0c7 290 UpdateVideosScheduler.Instance.enable()
ce32426b 291 YoutubeDlUpdateScheduler.Instance.enable()
c48e82b5 292 VideosRedundancyScheduler.Instance.enable()
8f0bc73d 293 RemoveOldHistoryScheduler.Instance.enable()
cda03765 294 RemoveOldViewsScheduler.Instance.enable()
e0ce715a 295 PluginsCheckScheduler.Instance.enable()
32a18cbf 296 PeerTubeVersionCheckScheduler.Instance.enable()
6f1b4fa4 297 AutoFollowIndexInstances.Instance.enable()
f6d6e7f8 298 RemoveDanglingResumableUploadsScheduler.Instance.enable()
3d3441d6
C
299
300 // Redis initialization
301 Redis.Instance.init()
302
cef534ed
C
303 PeerTubeSocket.Instance.init(server)
304
ae9bbed4
C
305 updateStreamingPlaylistsInfohashesIfNeeded()
306 .catch(err => logger.error('Cannot update streaming playlist infohashes.', { err }))
307
c6c0fa6c 308 LiveManager.Instance.init()
df1db951 309 if (CONFIG.LIVE.ENABLED) await LiveManager.Instance.run()
c6c0fa6c 310
3d3441d6 311 // Make server listening
e19fdf57
C
312 server.listen(port, hostname, async () => {
313 if (cliOptions.plugins) {
314 try {
315 await PluginManager.Instance.registerPluginsAndThemes()
316 } catch (err) {
317 logger.error('Cannot register plugins and themes.', { err })
318 }
319 }
320
c2b82382 321 logger.info('HTTP server listening on %s:%d', hostname, port)
74dc3bca 322 logger.info('Web server: %s', WEBSERVER.URL)
8d76959e 323
89cd1275 324 Hooks.runAction('action:application.listening')
f55e5a7b 325 })
14f2b3ad
C
326
327 process.on('exit', () => {
328 JobQueue.Instance.terminate()
329 })
330
331 process.on('SIGINT', () => process.exit(0))
5804c0db 332}