]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server.ts
Fix start/count/sort params in documentation
[github/Chocobozzz/PeerTube.git] / server.ts
... / ...
CommitLineData
1// FIXME: https://github.com/nodejs/node/pull/16853
2import { VideosCaptionCache } from './server/lib/cache/videos-caption-cache'
3
4require('tls').DEFAULT_ECDH_CURVE = 'auto'
5
6import { isTestInstance } from './server/helpers/core-utils'
7
8if (isTestInstance()) {
9 require('source-map-support').install()
10}
11
12// ----------- Node modules -----------
13import * as bodyParser from 'body-parser'
14import * as express from 'express'
15import * as morgan from 'morgan'
16import * as cors from 'cors'
17import * as cookieParser from 'cookie-parser'
18import * as helmet from 'helmet'
19
20process.title = 'peertube'
21
22// Create our main app
23const app = express()
24
25// ----------- Core checker -----------
26import { checkMissedConfig, checkFFmpeg, checkConfig, checkActivityPubUrls } from './server/initializers/checker'
27
28// Do not use barrels because we don't want to load all modules here (we need to initialize database first)
29import { logger } from './server/helpers/logger'
30import { API_VERSION, CONFIG, STATIC_PATHS, CACHE } from './server/initializers/constants'
31
32const missed = checkMissedConfig()
33if (missed.length !== 0) {
34 logger.error('Your configuration files miss keys: ' + missed)
35 process.exit(-1)
36}
37
38checkFFmpeg(CONFIG)
39 .catch(err => {
40 logger.error('Error in ffmpeg check.', { err })
41 process.exit(-1)
42 })
43
44const errorMessage = checkConfig()
45if (errorMessage !== null) {
46 throw new Error(errorMessage)
47}
48
49// Trust our proxy (IP forwarding...)
50app.set('trust proxy', CONFIG.TRUST_PROXY)
51
52// Security middlewares
53app.use(helmet({
54 frameguard: {
55 action: 'deny' // we only allow it for /videos/embed, see server/controllers/client.ts
56 },
57 dnsPrefetchControl: {
58 allow: true
59 },
60 contentSecurityPolicy: {
61 directives: {
62 defaultSrc: ['*', 'data:', 'wss:', 'https:'],
63 fontSrc: ["'self'", 'data:'],
64 frameSrc: ["'none'"],
65 mediaSrc: ['*', 'https:'],
66 objectSrc: ["'none'"],
67 scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
68 styleSrc: ["'self'", "'unsafe-inline'"],
69 upgradeInsecureRequests: true
70 },
71 browserSniff: false // assumes a modern browser, but allows CDN in front
72 },
73 referrerPolicy: {
74 policy: 'strict-origin-when-cross-origin'
75 }
76}))
77app.use((_, res, next) => {
78 [
79 "vibrate 'none'",
80 "geolocation 'none'",
81 "camera 'none'",
82 "microphone 'none'",
83 "magnetometer 'none'",
84 "payment 'none'",
85 "accelerometer 'none'"
86 ].forEach(e => res.append('Feature-Policy', e + ';'))
87 next()
88})
89
90// ----------- Database -----------
91
92// Initialize database and models
93import { initDatabaseModels } from './server/initializers/database'
94import { migrate } from './server/initializers/migrator'
95migrate()
96 .then(() => initDatabaseModels(false))
97 .then(() => startApplication())
98 .catch(err => {
99 logger.error('Cannot start application.', { err })
100 process.exit(-1)
101 })
102
103// ----------- PeerTube modules -----------
104import { installApplication } from './server/initializers'
105import { Emailer } from './server/lib/emailer'
106import { JobQueue } from './server/lib/job-queue'
107import { VideosPreviewCache } from './server/lib/cache'
108import {
109 activityPubRouter,
110 apiRouter,
111 clientsRouter,
112 feedsRouter,
113 staticRouter,
114 servicesRouter,
115 webfingerRouter,
116 trackerRouter,
117 createWebsocketServer
118} from './server/controllers'
119import { Redis } from './server/lib/redis'
120import { BadActorFollowScheduler } from './server/lib/schedulers/bad-actor-follow-scheduler'
121import { RemoveOldJobsScheduler } from './server/lib/schedulers/remove-old-jobs-scheduler'
122import { UpdateVideosScheduler } from './server/lib/schedulers/update-videos-scheduler'
123
124// ----------- Command line -----------
125
126// ----------- App -----------
127
128// Enable CORS for develop
129if (isTestInstance()) {
130 app.use(cors({
131 origin: '*',
132 exposedHeaders: 'Retry-After',
133 credentials: true
134 }))
135}
136
137// For the logger
138app.use(morgan('combined', {
139 stream: { write: logger.info.bind(logger) }
140}))
141// For body requests
142app.use(bodyParser.urlencoded({ extended: false }))
143app.use(bodyParser.json({
144 type: [ 'application/json', 'application/*+json' ],
145 limit: '500kb'
146}))
147// Cookies
148app.use(cookieParser())
149
150// ----------- Views, routes and static files -----------
151
152// API
153const apiRoute = '/api/' + API_VERSION
154app.use(apiRoute, apiRouter)
155
156// Services (oembed...)
157app.use('/services', servicesRouter)
158
159app.use('/', activityPubRouter)
160app.use('/', feedsRouter)
161app.use('/', webfingerRouter)
162app.use('/', trackerRouter)
163
164// Static files
165app.use('/', staticRouter)
166
167// Client files, last valid routes!
168app.use('/', clientsRouter)
169
170// ----------- Errors -----------
171
172// Catch 404 and forward to error handler
173app.use(function (req, res, next) {
174 const err = new Error('Not Found')
175 err['status'] = 404
176 next(err)
177})
178
179app.use(function (err, req, res, next) {
180 let error = 'Unknown error.'
181 if (err) {
182 error = err.stack || err.message || err
183 }
184
185 logger.error('Error in controller.', { error })
186 return res.status(err.status || 500).end()
187})
188
189const server = createWebsocketServer(app)
190
191// ----------- Run -----------
192
193async function startApplication () {
194 const port = CONFIG.LISTEN.PORT
195 const hostname = CONFIG.LISTEN.HOSTNAME
196
197 await installApplication()
198
199 // Check activity pub urls are valid
200 checkActivityPubUrls()
201 .catch(err => {
202 logger.error('Error in ActivityPub URLs checker.', { err })
203 process.exit(-1)
204 })
205
206 // Email initialization
207 Emailer.Instance.init()
208 await Emailer.Instance.checkConnectionOrDie()
209
210 await JobQueue.Instance.init()
211
212 // Caches initializations
213 VideosPreviewCache.Instance.init(CONFIG.CACHE.PREVIEWS.SIZE, CACHE.PREVIEWS.MAX_AGE)
214 VideosCaptionCache.Instance.init(CONFIG.CACHE.VIDEO_CAPTIONS.SIZE, CACHE.VIDEO_CAPTIONS.MAX_AGE)
215
216 // Enable Schedulers
217 BadActorFollowScheduler.Instance.enable()
218 RemoveOldJobsScheduler.Instance.enable()
219 UpdateVideosScheduler.Instance.enable()
220
221 // Redis initialization
222 Redis.Instance.init()
223
224 // Make server listening
225 server.listen(port, hostname, () => {
226 logger.info('Server listening on %s:%d', hostname, port)
227 logger.info('Web server: %s', CONFIG.WEBSERVER.URL)
228 })
229}