aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/activitypub
diff options
context:
space:
mode:
authorChocobozzz <florian.bigard@gmail.com>2017-11-09 17:51:58 +0100
committerChocobozzz <florian.bigard@gmail.com>2017-11-27 19:40:51 +0100
commite4f97babf701481b55cc10fb3448feab5f97c867 (patch)
treeaf37402a594dc5ff09f71ecb0687e8cfe4cdb471 /server/lib/activitypub
parent343ad675f2a26c15b86150a9a3552e619d5d44f4 (diff)
downloadPeerTube-e4f97babf701481b55cc10fb3448feab5f97c867.tar.gz
PeerTube-e4f97babf701481b55cc10fb3448feab5f97c867.tar.zst
PeerTube-e4f97babf701481b55cc10fb3448feab5f97c867.zip
Begin activitypub
Diffstat (limited to 'server/lib/activitypub')
-rw-r--r--server/lib/activitypub/index.ts3
-rw-r--r--server/lib/activitypub/process-create.ts104
-rw-r--r--server/lib/activitypub/process-flag.ts17
-rw-r--r--server/lib/activitypub/process-update.ts29
-rw-r--r--server/lib/activitypub/send-request.ts129
5 files changed, 282 insertions, 0 deletions
diff --git a/server/lib/activitypub/index.ts b/server/lib/activitypub/index.ts
new file mode 100644
index 000000000..740800606
--- /dev/null
+++ b/server/lib/activitypub/index.ts
@@ -0,0 +1,3 @@
1export * from './process-create'
2export * from './process-flag'
3export * from './process-update'
diff --git a/server/lib/activitypub/process-create.ts b/server/lib/activitypub/process-create.ts
new file mode 100644
index 000000000..114ff1848
--- /dev/null
+++ b/server/lib/activitypub/process-create.ts
@@ -0,0 +1,104 @@
1import {
2 ActivityCreate,
3 VideoTorrentObject,
4 VideoChannelObject
5} from '../../../shared'
6import { database as db } from '../../initializers'
7import { logger, retryTransactionWrapper } from '../../helpers'
8
9function processCreateActivity (activity: ActivityCreate) {
10 const activityObject = activity.object
11 const activityType = activityObject.type
12
13 if (activityType === 'Video') {
14 return processCreateVideo(activityObject as VideoTorrentObject)
15 } else if (activityType === 'VideoChannel') {
16 return processCreateVideoChannel(activityObject as VideoChannelObject)
17 }
18
19 logger.warn('Unknown activity object type %s when creating activity.', activityType, { activity: activity.id })
20 return Promise.resolve()
21}
22
23// ---------------------------------------------------------------------------
24
25export {
26 processCreateActivity
27}
28
29// ---------------------------------------------------------------------------
30
31function processCreateVideo (video: VideoTorrentObject) {
32 const options = {
33 arguments: [ video ],
34 errorMessage: 'Cannot insert the remote video with many retries.'
35 }
36
37 return retryTransactionWrapper(addRemoteVideo, options)
38}
39
40async function addRemoteVideo (videoToCreateData: VideoTorrentObject) {
41 logger.debug('Adding remote video %s.', videoToCreateData.url)
42
43 await db.sequelize.transaction(async t => {
44 const sequelizeOptions = {
45 transaction: t
46 }
47
48 const videoFromDatabase = await db.Video.loadByUUID(videoToCreateData.uuid)
49 if (videoFromDatabase) throw new Error('UUID already exists.')
50
51 const videoChannel = await db.VideoChannel.loadByHostAndUUID(fromPod.host, videoToCreateData.channelUUID, t)
52 if (!videoChannel) throw new Error('Video channel ' + videoToCreateData.channelUUID + ' not found.')
53
54 const tags = videoToCreateData.tags
55 const tagInstances = await db.Tag.findOrCreateTags(tags, t)
56
57 const videoData = {
58 name: videoToCreateData.name,
59 uuid: videoToCreateData.uuid,
60 category: videoToCreateData.category,
61 licence: videoToCreateData.licence,
62 language: videoToCreateData.language,
63 nsfw: videoToCreateData.nsfw,
64 description: videoToCreateData.truncatedDescription,
65 channelId: videoChannel.id,
66 duration: videoToCreateData.duration,
67 createdAt: videoToCreateData.createdAt,
68 // FIXME: updatedAt does not seems to be considered by Sequelize
69 updatedAt: videoToCreateData.updatedAt,
70 views: videoToCreateData.views,
71 likes: videoToCreateData.likes,
72 dislikes: videoToCreateData.dislikes,
73 remote: true,
74 privacy: videoToCreateData.privacy
75 }
76
77 const video = db.Video.build(videoData)
78 await db.Video.generateThumbnailFromData(video, videoToCreateData.thumbnailData)
79 const videoCreated = await video.save(sequelizeOptions)
80
81 const tasks = []
82 for (const fileData of videoToCreateData.files) {
83 const videoFileInstance = db.VideoFile.build({
84 extname: fileData.extname,
85 infoHash: fileData.infoHash,
86 resolution: fileData.resolution,
87 size: fileData.size,
88 videoId: videoCreated.id
89 })
90
91 tasks.push(videoFileInstance.save(sequelizeOptions))
92 }
93
94 await Promise.all(tasks)
95
96 await videoCreated.setTags(tagInstances, sequelizeOptions)
97 })
98
99 logger.info('Remote video with uuid %s inserted.', videoToCreateData.uuid)
100}
101
102function processCreateVideoChannel (videoChannel: VideoChannelObject) {
103
104}
diff --git a/server/lib/activitypub/process-flag.ts b/server/lib/activitypub/process-flag.ts
new file mode 100644
index 000000000..6fa862ee9
--- /dev/null
+++ b/server/lib/activitypub/process-flag.ts
@@ -0,0 +1,17 @@
1import {
2 ActivityCreate,
3 VideoTorrentObject,
4 VideoChannelObject
5} from '../../../shared'
6
7function processFlagActivity (activity: ActivityCreate) {
8 // empty
9}
10
11// ---------------------------------------------------------------------------
12
13export {
14 processFlagActivity
15}
16
17// ---------------------------------------------------------------------------
diff --git a/server/lib/activitypub/process-update.ts b/server/lib/activitypub/process-update.ts
new file mode 100644
index 000000000..187c7be7c
--- /dev/null
+++ b/server/lib/activitypub/process-update.ts
@@ -0,0 +1,29 @@
1import {
2 ActivityCreate,
3 VideoTorrentObject,
4 VideoChannelObject
5} from '../../../shared'
6
7function processUpdateActivity (activity: ActivityCreate) {
8 if (activity.object.type === 'Video') {
9 return processUpdateVideo(activity.object)
10 } else if (activity.object.type === 'VideoChannel') {
11 return processUpdateVideoChannel(activity.object)
12 }
13}
14
15// ---------------------------------------------------------------------------
16
17export {
18 processUpdateActivity
19}
20
21// ---------------------------------------------------------------------------
22
23function processUpdateVideo (video: VideoTorrentObject) {
24
25}
26
27function processUpdateVideoChannel (videoChannel: VideoChannelObject) {
28
29}
diff --git a/server/lib/activitypub/send-request.ts b/server/lib/activitypub/send-request.ts
new file mode 100644
index 000000000..6a31c226d
--- /dev/null
+++ b/server/lib/activitypub/send-request.ts
@@ -0,0 +1,129 @@
1import * as Sequelize from 'sequelize'
2
3import {
4 AccountInstance,
5 VideoInstance,
6 VideoChannelInstance
7} from '../../models'
8import { httpRequestJobScheduler } from '../jobs'
9import { signObject, activityPubContextify } from '../../helpers'
10import { Activity } from '../../../shared'
11
12function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
13 const videoChannelObject = videoChannel.toActivityPubObject()
14 const data = createActivityData(videoChannel.url, videoChannel.Account, videoChannelObject)
15
16 return broadcastToFollowers(data, t)
17}
18
19function sendUpdateVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
20 const videoChannelObject = videoChannel.toActivityPubObject()
21 const data = updateActivityData(videoChannel.url, videoChannel.Account, videoChannelObject)
22
23 return broadcastToFollowers(data, t)
24}
25
26function sendDeleteVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
27 const videoChannelObject = videoChannel.toActivityPubObject()
28 const data = deleteActivityData(videoChannel.url, videoChannel.Account, videoChannelObject)
29
30 return broadcastToFollowers(data, t)
31}
32
33function sendAddVideo (video: VideoInstance, t: Sequelize.Transaction) {
34 const videoObject = video.toActivityPubObject()
35 const data = addActivityData(video.url, video.VideoChannel.Account, video.VideoChannel.url, videoObject)
36
37 return broadcastToFollowers(data, t)
38}
39
40function sendUpdateVideo (video: VideoInstance, t: Sequelize.Transaction) {
41 const videoObject = video.toActivityPubObject()
42 const data = updateActivityData(video.url, video.VideoChannel.Account, videoObject)
43
44 return broadcastToFollowers(data, t)
45}
46
47function sendDeleteVideo (video: VideoInstance, t: Sequelize.Transaction) {
48 const videoObject = video.toActivityPubObject()
49 const data = deleteActivityData(video.url, video.VideoChannel.Account, videoObject)
50
51 return broadcastToFollowers(data, t)
52}
53
54// ---------------------------------------------------------------------------
55
56export {
57
58}
59
60// ---------------------------------------------------------------------------
61
62function broadcastToFollowers (data: any, t: Sequelize.Transaction) {
63 return httpRequestJobScheduler.createJob(t, 'http-request', 'httpRequestBroadcastHandler', data)
64}
65
66function buildSignedActivity (byAccount: AccountInstance, data: Object) {
67 const activity = activityPubContextify(data)
68
69 return signObject(byAccount, activity) as Promise<Activity>
70}
71
72async function getPublicActivityTo (account: AccountInstance) {
73 const inboxUrls = await account.getFollowerSharedInboxUrls()
74
75 return inboxUrls.concat('https://www.w3.org/ns/activitystreams#Public')
76}
77
78async function createActivityData (url: string, byAccount: AccountInstance, object: any) {
79 const to = await getPublicActivityTo(byAccount)
80 const base = {
81 type: 'Create',
82 id: url,
83 actor: byAccount.url,
84 to,
85 object
86 }
87
88 return buildSignedActivity(byAccount, base)
89}
90
91async function updateActivityData (url: string, byAccount: AccountInstance, object: any) {
92 const to = await getPublicActivityTo(byAccount)
93 const base = {
94 type: 'Update',
95 id: url,
96 actor: byAccount.url,
97 to,
98 object
99 }
100
101 return buildSignedActivity(byAccount, base)
102}
103
104async function deleteActivityData (url: string, byAccount: AccountInstance, object: any) {
105 const to = await getPublicActivityTo(byAccount)
106 const base = {
107 type: 'Update',
108 id: url,
109 actor: byAccount.url,
110 to,
111 object
112 }
113
114 return buildSignedActivity(byAccount, base)
115}
116
117async function addActivityData (url: string, byAccount: AccountInstance, target: string, object: any) {
118 const to = await getPublicActivityTo(byAccount)
119 const base = {
120 type: 'Add',
121 id: url,
122 actor: byAccount.url,
123 to,
124 object,
125 target
126 }
127
128 return buildSignedActivity(byAccount, base)
129}