aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/controllers/activitypub/client.ts5
-rw-r--r--server/controllers/feeds.ts6
-rw-r--r--server/controllers/static.ts85
-rw-r--r--server/helpers/utils.ts30
-rw-r--r--server/initializers/constants.ts6
-rw-r--r--server/middlewares/cache.ts13
-rw-r--r--server/models/nodeinfo/index.d.ts117
7 files changed, 246 insertions, 16 deletions
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts
index 3e6361906..ebb2c06a2 100644
--- a/server/controllers/activitypub/client.ts
+++ b/server/controllers/activitypub/client.ts
@@ -16,7 +16,7 @@ import { VideoModel } from '../../models/video/video'
16import { VideoChannelModel } from '../../models/video/video-channel' 16import { VideoChannelModel } from '../../models/video/video-channel'
17import { VideoCommentModel } from '../../models/video/video-comment' 17import { VideoCommentModel } from '../../models/video/video-comment'
18import { VideoShareModel } from '../../models/video/video-share' 18import { VideoShareModel } from '../../models/video/video-share'
19import { cacheRoute } from '../../middlewares/cache' 19import { cache } from '../../middlewares/cache'
20import { activityPubResponse } from './utils' 20import { activityPubResponse } from './utils'
21import { AccountVideoRateModel } from '../../models/account/account-video-rate' 21import { AccountVideoRateModel } from '../../models/account/account-video-rate'
22import { 22import {
@@ -25,7 +25,6 @@ import {
25 getVideoLikesActivityPubUrl, 25 getVideoLikesActivityPubUrl,
26 getVideoSharesActivityPubUrl 26 getVideoSharesActivityPubUrl
27} from '../../lib/activitypub' 27} from '../../lib/activitypub'
28import { VideoCaption } from '../../../shared/models/videos/video-caption.model'
29import { VideoCaptionModel } from '../../models/video/video-caption' 28import { VideoCaptionModel } from '../../models/video/video-caption'
30 29
31const activityPubClientRouter = express.Router() 30const activityPubClientRouter = express.Router()
@@ -44,7 +43,7 @@ activityPubClientRouter.get('/accounts?/:name/following',
44) 43)
45 44
46activityPubClientRouter.get('/videos/watch/:id', 45activityPubClientRouter.get('/videos/watch/:id',
47 executeIfActivityPub(asyncMiddleware(cacheRoute(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS))), 46 executeIfActivityPub(asyncMiddleware(cache(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS))),
48 executeIfActivityPub(asyncMiddleware(videosGetValidator)), 47 executeIfActivityPub(asyncMiddleware(videosGetValidator)),
49 executeIfActivityPub(asyncMiddleware(videoController)) 48 executeIfActivityPub(asyncMiddleware(videoController))
50) 49)
diff --git a/server/controllers/feeds.ts b/server/controllers/feeds.ts
index 682f4abda..6cbe42a2a 100644
--- a/server/controllers/feeds.ts
+++ b/server/controllers/feeds.ts
@@ -5,7 +5,7 @@ import { asyncMiddleware, setDefaultSort, videoCommentsFeedsValidator, videoFeed
5import { VideoModel } from '../models/video/video' 5import { VideoModel } from '../models/video/video'
6import * as Feed from 'pfeed' 6import * as Feed from 'pfeed'
7import { AccountModel } from '../models/account/account' 7import { AccountModel } from '../models/account/account'
8import { cacheRoute } from '../middlewares/cache' 8import { cache } from '../middlewares/cache'
9import { VideoChannelModel } from '../models/video/video-channel' 9import { VideoChannelModel } from '../models/video/video-channel'
10import { VideoCommentModel } from '../models/video/video-comment' 10import { VideoCommentModel } from '../models/video/video-comment'
11import { buildNSFWFilter } from '../helpers/express-utils' 11import { buildNSFWFilter } from '../helpers/express-utils'
@@ -13,7 +13,7 @@ import { buildNSFWFilter } from '../helpers/express-utils'
13const feedsRouter = express.Router() 13const feedsRouter = express.Router()
14 14
15feedsRouter.get('/feeds/video-comments.:format', 15feedsRouter.get('/feeds/video-comments.:format',
16 asyncMiddleware(cacheRoute(ROUTE_CACHE_LIFETIME.FEEDS)), 16 asyncMiddleware(cache(ROUTE_CACHE_LIFETIME.FEEDS)),
17 asyncMiddleware(videoCommentsFeedsValidator), 17 asyncMiddleware(videoCommentsFeedsValidator),
18 asyncMiddleware(generateVideoCommentsFeed) 18 asyncMiddleware(generateVideoCommentsFeed)
19) 19)
@@ -21,7 +21,7 @@ feedsRouter.get('/feeds/video-comments.:format',
21feedsRouter.get('/feeds/videos.:format', 21feedsRouter.get('/feeds/videos.:format',
22 videosSortValidator, 22 videosSortValidator,
23 setDefaultSort, 23 setDefaultSort,
24 asyncMiddleware(cacheRoute(ROUTE_CACHE_LIFETIME.FEEDS)), 24 asyncMiddleware(cache(ROUTE_CACHE_LIFETIME.FEEDS)),
25 asyncMiddleware(videoFeedsValidator), 25 asyncMiddleware(videoFeedsValidator),
26 asyncMiddleware(generateVideoFeed) 26 asyncMiddleware(generateVideoFeed)
27) 27)
diff --git a/server/controllers/static.ts b/server/controllers/static.ts
index 8de9c5a78..ce5d0c5fa 100644
--- a/server/controllers/static.ts
+++ b/server/controllers/static.ts
@@ -1,11 +1,16 @@
1import * as cors from 'cors' 1import * as cors from 'cors'
2import * as express from 'express' 2import * as express from 'express'
3import { CONFIG, STATIC_DOWNLOAD_PATHS, STATIC_MAX_AGE, STATIC_PATHS } from '../initializers' 3import { CONFIG, STATIC_DOWNLOAD_PATHS, STATIC_MAX_AGE, STATIC_PATHS, ROUTE_CACHE_LIFETIME } from '../initializers'
4import { VideosPreviewCache } from '../lib/cache' 4import { VideosPreviewCache } from '../lib/cache'
5import { cache } from '../middlewares/cache'
5import { asyncMiddleware, videosGetValidator } from '../middlewares' 6import { asyncMiddleware, videosGetValidator } from '../middlewares'
6import { VideoModel } from '../models/video/video' 7import { VideoModel } from '../models/video/video'
7import { VideosCaptionCache } from '../lib/cache/videos-caption-cache' 8import { VideosCaptionCache } from '../lib/cache/videos-caption-cache'
9import { UserModel } from '../models/account/user'
10import { VideoCommentModel } from '../models/video/video-comment'
11import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../models/nodeinfo'
8 12
13const packageJSON = require('../../../package.json')
9const staticRouter = express.Router() 14const staticRouter = express.Router()
10 15
11staticRouter.use(cors()) 16staticRouter.use(cors())
@@ -65,10 +70,32 @@ staticRouter.use(
65) 70)
66 71
67// robots.txt service 72// robots.txt service
68staticRouter.get('/robots.txt', (req: express.Request, res: express.Response) => { 73staticRouter.get('/robots.txt',
69 res.type('text/plain') 74 asyncMiddleware(cache(ROUTE_CACHE_LIFETIME.ROBOTS)),
70 return res.send(CONFIG.INSTANCE.ROBOTS) 75 (_, res: express.Response) => {
71}) 76 res.type('text/plain')
77 return res.send(CONFIG.INSTANCE.ROBOTS)
78 }
79)
80
81// nodeinfo service
82staticRouter.use('/.well-known/nodeinfo',
83 asyncMiddleware(cache(ROUTE_CACHE_LIFETIME.NODEINFO)),
84 (_, res: express.Response) => {
85 return res.json({
86 links: [
87 {
88 rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0',
89 href: CONFIG.WEBSERVER.URL + '/nodeinfo/2.0.json'
90 }
91 ]
92 })
93 }
94)
95staticRouter.use('/nodeinfo/:version.json',
96 asyncMiddleware(cache(ROUTE_CACHE_LIFETIME.NODEINFO)),
97 asyncMiddleware(generateNodeinfo)
98)
72 99
73// --------------------------------------------------------------------------- 100// ---------------------------------------------------------------------------
74 101
@@ -95,6 +122,54 @@ async function getVideoCaption (req: express.Request, res: express.Response) {
95 return res.sendFile(path, { maxAge: STATIC_MAX_AGE }) 122 return res.sendFile(path, { maxAge: STATIC_MAX_AGE })
96} 123}
97 124
125async function generateNodeinfo (req: express.Request, res: express.Response, next: express.NextFunction) {
126 const { totalVideos } = await VideoModel.getStats()
127 const { totalLocalVideoComments } = await VideoCommentModel.getStats()
128 const { totalUsers } = await UserModel.getStats()
129 let json = {}
130
131 if (req.params.version && (req.params.version === '2.0')) {
132 json = {
133 version: '2.0',
134 software: {
135 name: 'peertube',
136 version: packageJSON.version
137 },
138 protocols: [
139 'activitypub'
140 ],
141 services: {
142 inbound: [],
143 outbound: [
144 'atom1.0',
145 'rss2.0'
146 ]
147 },
148 openRegistrations: CONFIG.SIGNUP.ENABLED,
149 usage: {
150 users: {
151 total: totalUsers
152 },
153 localPosts: totalVideos,
154 localComments: totalLocalVideoComments
155 },
156 metadata: {
157 taxonomy: {
158 postsName: 'Videos'
159 },
160 nodeName: CONFIG.INSTANCE.NAME,
161 nodeDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION
162 }
163 } as HttpNodeinfoDiasporaSoftwareNsSchema20
164 res.set('Content-Type', 'application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#; charset=utf-8')
165 } else {
166 json = { error: 'Nodeinfo schema version not handled' }
167 res.status(404)
168 }
169
170 return res.end(JSON.stringify(json))
171}
172
98async function downloadTorrent (req: express.Request, res: express.Response, next: express.NextFunction) { 173async function downloadTorrent (req: express.Request, res: express.Response, next: express.NextFunction) {
99 const { video, videoFile } = getVideoAndFile(req, res) 174 const { video, videoFile } = getVideoAndFile(req, res)
100 if (!videoFile) return res.status(404).end() 175 if (!videoFile) return res.status(404).end()
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts
index 8fa861281..834d788c8 100644
--- a/server/helpers/utils.ts
+++ b/server/helpers/utils.ts
@@ -104,6 +104,36 @@ function computeResolutionsToTranscode (videoFileHeight: number) {
104 return resolutionsEnabled 104 return resolutionsEnabled
105} 105}
106 106
107const timeTable = {
108 ms: 1,
109 second: 1000,
110 minute: 60000,
111 hour: 3600000,
112 day: 3600000 * 24,
113 week: 3600000 * 24 * 7,
114 month: 3600000 * 24 * 30
115}
116export function parseDuration (duration: number | string, defaultDuration: number): number {
117 if (typeof duration === 'number') return duration
118
119 if (typeof duration === 'string') {
120 const split = duration.match(/^([\d\.,]+)\s?(\w+)$/)
121
122 if (split.length === 3) {
123 const len = parseFloat(split[1])
124 let unit = split[2].replace(/s$/i,'').toLowerCase()
125 if (unit === 'm') {
126 unit = 'ms'
127 }
128
129 return (len || 1) * (timeTable[unit] || 0)
130 }
131 }
132
133 logger.error('Duration could not be properly parsed, defaulting to ' + defaultDuration)
134 return defaultDuration
135}
136
107function resetSequelizeInstance (instance: Model<any>, savedFields: object) { 137function resetSequelizeInstance (instance: Model<any>, savedFields: object) {
108 Object.keys(savedFields).forEach(key => { 138 Object.keys(savedFields).forEach(key => {
109 const value = savedFields[key] 139 const value = savedFields[key]
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index e66ebb662..e8e0da683 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -46,9 +46,11 @@ const OAUTH_LIFETIME = {
46} 46}
47 47
48const ROUTE_CACHE_LIFETIME = { 48const ROUTE_CACHE_LIFETIME = {
49 FEEDS: 1000 * 60 * 15, // 15 minutes 49 FEEDS: '15 minutes',
50 ROBOTS: '2 hours',
51 NODEINFO: '10 minutes',
50 ACTIVITY_PUB: { 52 ACTIVITY_PUB: {
51 VIDEOS: 1000 // 1 second, cache concurrent requests after a broadcast for example 53 VIDEOS: '1 second' // 1 second, cache concurrent requests after a broadcast for example
52 } 54 }
53} 55}
54 56
diff --git a/server/middlewares/cache.ts b/server/middlewares/cache.ts
index 1de44db70..1e5a13b2e 100644
--- a/server/middlewares/cache.ts
+++ b/server/middlewares/cache.ts
@@ -1,5 +1,6 @@
1import * as express from 'express' 1import * as express from 'express'
2import * as AsyncLock from 'async-lock' 2import * as AsyncLock from 'async-lock'
3import { parseDuration } from '../helpers/utils'
3import { Redis } from '../lib/redis' 4import { Redis } from '../lib/redis'
4import { logger } from '../helpers/logger' 5import { logger } from '../helpers/logger'
5 6
@@ -20,7 +21,7 @@ function cacheRoute (lifetime: number) {
20 21
21 res.send = (body) => { 22 res.send = (body) => {
22 if (res.statusCode >= 200 && res.statusCode < 400) { 23 if (res.statusCode >= 200 && res.statusCode < 400) {
23 const contentType = res.getHeader('content-type').toString() 24 const contentType = res.get('content-type')
24 Redis.Instance.setCachedRoute(req, body, lifetime, contentType, res.statusCode) 25 Redis.Instance.setCachedRoute(req, body, lifetime, contentType, res.statusCode)
25 .then(() => done()) 26 .then(() => done())
26 .catch(err => { 27 .catch(err => {
@@ -35,7 +36,7 @@ function cacheRoute (lifetime: number) {
35 return next() 36 return next()
36 } 37 }
37 38
38 if (cached.contentType) res.contentType(cached.contentType) 39 if (cached.contentType) res.set('content-type', cached.contentType)
39 40
40 if (cached.statusCode) { 41 if (cached.statusCode) {
41 const statusCode = parseInt(cached.statusCode, 10) 42 const statusCode = parseInt(cached.statusCode, 10)
@@ -50,8 +51,14 @@ function cacheRoute (lifetime: number) {
50 } 51 }
51} 52}
52 53
54const cache = (duration: number | string) => {
55 const _lifetime = parseDuration(duration, 3600000)
56 return cacheRoute(_lifetime)
57}
58
53// --------------------------------------------------------------------------- 59// ---------------------------------------------------------------------------
54 60
55export { 61export {
56 cacheRoute 62 cacheRoute,
63 cache
57} 64}
diff --git a/server/models/nodeinfo/index.d.ts b/server/models/nodeinfo/index.d.ts
new file mode 100644
index 000000000..0a2d0492e
--- /dev/null
+++ b/server/models/nodeinfo/index.d.ts
@@ -0,0 +1,117 @@
1/**
2 * NodeInfo schema version 2.0.
3 */
4export interface HttpNodeinfoDiasporaSoftwareNsSchema20 {
5 /**
6 * The schema version, must be 2.0.
7 */
8 version: '2.0'
9 /**
10 * Metadata about server software in use.
11 */
12 software: {
13 /**
14 * The canonical name of this server software.
15 */
16 name: string
17 /**
18 * The version of this server software.
19 */
20 version: string
21 }
22 /**
23 * The protocols supported on this server.
24 */
25 protocols: (
26 | 'activitypub'
27 | 'buddycloud'
28 | 'dfrn'
29 | 'diaspora'
30 | 'libertree'
31 | 'ostatus'
32 | 'pumpio'
33 | 'tent'
34 | 'xmpp'
35 | 'zot')[]
36 /**
37 * The third party sites this server can connect to via their application API.
38 */
39 services: {
40 /**
41 * The third party sites this server can retrieve messages from for combined display with regular traffic.
42 */
43 inbound: ('atom1.0' | 'gnusocial' | 'imap' | 'pnut' | 'pop3' | 'pumpio' | 'rss2.0' | 'twitter')[]
44 /**
45 * The third party sites this server can publish messages to on the behalf of a user.
46 */
47 outbound: (
48 | 'atom1.0'
49 | 'blogger'
50 | 'buddycloud'
51 | 'diaspora'
52 | 'dreamwidth'
53 | 'drupal'
54 | 'facebook'
55 | 'friendica'
56 | 'gnusocial'
57 | 'google'
58 | 'insanejournal'
59 | 'libertree'
60 | 'linkedin'
61 | 'livejournal'
62 | 'mediagoblin'
63 | 'myspace'
64 | 'pinterest'
65 | 'pnut'
66 | 'posterous'
67 | 'pumpio'
68 | 'redmatrix'
69 | 'rss2.0'
70 | 'smtp'
71 | 'tent'
72 | 'tumblr'
73 | 'twitter'
74 | 'wordpress'
75 | 'xmpp')[]
76 }
77 /**
78 * Whether this server allows open self-registration.
79 */
80 openRegistrations: boolean
81 /**
82 * Usage statistics for this server.
83 */
84 usage: {
85 /**
86 * statistics about the users of this server.
87 */
88 users: {
89 /**
90 * The total amount of on this server registered users.
91 */
92 total?: number
93 /**
94 * The amount of users that signed in at least once in the last 180 days.
95 */
96 activeHalfyear?: number
97 /**
98 * The amount of users that signed in at least once in the last 30 days.
99 */
100 activeMonth?: number
101 };
102 /**
103 * The amount of posts that were made by users that are registered on this server.
104 */
105 localPosts?: number
106 /**
107 * The amount of comments that were made by users that are registered on this server.
108 */
109 localComments?: number
110 }
111 /**
112 * Free form key value pairs for software specific values. Clients should not rely on any specific key present.
113 */
114 metadata: {
115 [k: string]: any
116 }
117}