-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathrequests.ts
208 lines (188 loc) · 5.37 KB
/
requests.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/* ---------------------------------------------------------------------------------------------
* Copyright (c) Infiniscene, Inc. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* -------------------------------------------------------------------------------------------- */
/**
* Requests provide single-concern abstractions
* over the various backend APIs (Layout/Live).
*
* Not every external request is represented here. In some cases
* it is simpler to use the API SDK client interface directly.
*/
import { LiveApiModel } from '@api.stream/sdk'
import { Helpers } from '.'
import {
CoreContext,
InternalProject,
InternalSource,
InternalUser
} from './context'
import { getAccessTokenData, getProject, getUser, hydrateProject } from './data'
import { Props, Role } from './types'
export const createProject = async (request: {
settings?: { [prop: string]: any }
props?: Props // Arbitrary metadata (e.g. 'name')
size?: { x: number; y: number }
type?: 'sceneless' | 'freeform'
}) => {
const collectionId = getUser().id
const type = request.type || 'sceneless'
const size = request.size || {
x: 1280,
y: 720,
}
const settings = request.settings || {}
// Create a project to go with the collection
let createProjectResponse = await CoreContext.clients
.LiveApi()
.project.createProject({
collectionId,
rendering: {
video: {
width: size.x,
height: size.y,
framerate: 30,
},
},
composition: {
studioSdk: { version: CoreContext.rendererVersion },
},
metadata: {},
webrtc: {
hosted: {},
},
})
const layout = await createLayout({
projectId: createProjectResponse.project.projectId,
collectionId: createProjectResponse.project.collectionId,
settings,
size,
type,
})
const { displayName } = getAccessTokenData()
// Save the layoutId on the project (no need to await)
const metadata = {
type,
layoutId: layout.id,
hostDisplayName: displayName,
props: request.props || {},
}
let projectResponse = await CoreContext.clients
.LiveApi()
.project.updateProject({
collectionId,
projectId: createProjectResponse.project.projectId,
updateMask: ['metadata'],
metadata,
})
createProjectResponse.project = projectResponse.project
createProjectResponse.project.metadata = metadata
return { project: createProjectResponse.project, layout }
}
export const deleteProject = async (request: { projectId: string }) => {
const { projectId } = request
const project = getProject(projectId)
const collectionId = getUser().id
await Promise.all([
CoreContext.clients.LiveApi().project.deleteProject({
collectionId,
projectId,
}),
CoreContext.clients.LayoutApi().layout.deleteLayout({
layoutId: project.layoutApi.layoutId,
}),
])
}
/**
* Load the user data from whatever access token has been registered
* with the API.
*/
export const loadUser = async (
size?: {
x: number
y: number
},
options?: {
updateLayoutOnly?: boolean
}
): Promise<{
user: InternalUser
projects: InternalProject[]
sources: InternalSource[]
}> => {
const collections = await loadCollections()
let collection: LiveApiModel.Collection
const { displayName, serviceUserId } = getAccessTokenData()
// Get a single collection, corresponding to a user
if (collections.length === 0) {
// If the user has no collections, create one
const response = await CoreContext.clients
.LiveApi()
.collection.createCollection({
metadata: {
serviceUserId,
displayName,
props: {},
},
})
collection = response.collection
} else {
// only 1 collection per user for studio-kit
collection = collections[0]
}
await CoreContext.clients
.LiveApi()
.subscribeToCollection(collection.collectionId)
// Take the Vapi Project and hydrate it with Compositor and Lapi project details
const projects = await Promise.all(
collection.projects
.filter((p) => Boolean(p.metadata?.layoutId))
.map((project) => hydrateProject(project, 'ROLE_HOST' as Role, size, options?.updateLayoutOnly)),
)
return {
user: {
id: collection.collectionId,
metadata: collection.metadata,
props: collection.metadata?.props || {},
name: displayName,
},
projects,
sources: collection.sources,
}
}
export const loadCollections = async () => {
let result = await CoreContext.clients.LiveApi().collection.getCollections({})
return result.collections
}
export const createLayout = async (request: {
projectId: string
collectionId: string
settings: { [prop: string]: any }
size: { x: number; y: number }
type?: string
}) => {
const { settings, size, type, projectId, collectionId } = request
const layout = await CoreContext.clients.LayoutApi().layout.createLayout({
layout: {
projectId,
collectionId,
},
})
if (type === 'sceneless') {
await Helpers.ScenelessProject.createCompositor(layout.id, size, settings)
} else {
await CoreContext.compositor.createProject(
{
props: {
name: 'Root',
layout: 'Free',
...settings,
isRoot: true,
size,
},
},
layout.id,
)
}
return layout
}