-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathorganizer.proto
324 lines (266 loc) · 10.7 KB
/
organizer.proto
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
syntax = "proto3";
package clapshot.organizer;
import public "common.proto";
import public "database.proto";
import public "client.proto";
import "google/protobuf/timestamp.proto";
// This defines the gRPC API for Clapshot Organizer services.
//
// An **organizer plugin** is responsible for organizing
// media files into UI folders and enforcing access
// control according to your particular business logic,
// perhaps by looking up projects and ACL groups from
// some LDAP or project management SQL database.
//
// Clapshot server will connect the organizer
// on startup, and sends the handshake message. Organizer
// connects back to the server and send its own
// handshake message.
//
// The organizer service must live as long as the Clapshot
// server and have a stable connection, which is why it is
// recommended to have the server actually launch the
// organizer service as a subprocess and use Unix sockets
// for communication.
// Calls that Organizer makes to Clapshot server
service OrganizerOutbound {
rpc handshake(OrganizerInfo) returns (Empty);
rpc client_define_actions(ClientDefineActionsRequest) returns (Empty); // Multiple calls will add/replace actions
rpc client_show_page(ClientShowPageRequest) returns (Empty);
rpc client_show_user_message(ClientShowUserMessageRequest) returns (Empty);
rpc client_open_media_file(ClientOpenMediaFileRequest) returns (Empty);
rpc client_set_cookies(ClientSetCookiesRequest) returns (Empty);
rpc delete_media_file(DeleteMediaFileRequest) returns (Empty); // Delete (trash) media file cleanly from both database and filesystem
// Database access (note: these may each happen in a separate DB connection / transaction)
rpc DbGetMediaFiles(DbGetMediaFilesRequest) returns (DbMediaFileList);
rpc DbGetComments(DbGetCommentsRequest) returns (DbCommentList);
rpc DbGetUserMessages(DbGetUserMessagesRequest) returns (DbUserMessageList);
rpc DbUpsert(DbUpsertRequest) returns (DbUpsertResponse);
rpc DbDelete(DbDeleteRequest) returns (DbDeleteResponse);
}
// Calls that Clapshot server makes to Organizer
service OrganizerInbound {
// Initialization calls (in the order they are made)
rpc check_migrations(CheckMigrationsRequest) returns (CheckMigrationsResponse);
rpc apply_migration(ApplyMigrationRequest) returns (ApplyMigrationResponse);
rpc handshake(ServerInfo) returns (Empty);
// Organizer should respond to all calls as quickly as possible.
// Two standard gRPC error returns status codes have special meaning:
// - `UNIMPLEMENTED` = Organizer does not support this call. The server will assume the default behavior.
// - `ABORTED` = Call failed, but server should not show it to the user (e.g. Organizer handled reporting).
//
// All other gRPC errors will be considered more serious, and the server will log them in detail and possibly show to the user.
// User session events
rpc on_start_user_session(OnStartUserSessionRequest) returns (OnStartUserSessionResponse);
rpc navigate_page(NavigatePageRequest) returns (ClientShowPageRequest);
rpc authz_user_action(AuthzUserActionRequest) returns (AuthzResponse);
rpc cmd_from_client(CmdFromClientRequest) returns (Empty);
// Calls from client when user interacts with the folder UI
rpc move_to_folder(MoveToFolderRequest) returns (Empty);
rpc reorder_items(ReorderItemsRequest) returns (Empty);
// Unit / integration tests (not called in production)
rpc list_tests(Empty) returns (ListTestsResponse);
rpc run_test(RunTestRequest) returns (RunTestResponse);
}
// ---------------------------------------------------------
message Database {
enum DatabaseType {
SQLITE = 0;
}
DatabaseType type = 1;
string endpoint = 2;
}
message ServerInfo {
message Storage {
message LocalFilesystem {
string base_dir = 1;
}
oneof storage {
LocalFilesystem local_fs = 1;
}
}
message GrpcEndpoint {
message Unix {
string path = 1;
}
message TCP {
string host = 1;
uint32 port = 2;
}
oneof endpoint {
Unix unix = 1;
TCP tcp = 2;
}
}
SemanticVersionNumber version = 1;
Storage storage = 3;
string url_base = 4;
Database db = 5;
GrpcEndpoint backchannel = 6;
}
message OrganizerInfo {
SemanticVersionNumber version = 1;
string name = 2; // Make sure this is (globally) unique, e.g. "com.example.myorganizer", to avoid conflicts
string description = 3; // Human-readable description of the organizer plugin
repeated OrganizerDependency hard_dependencies = 4; // List of any other modules that must be present for this module to work
}
message OrganizerDependency {
string name = 1; // e.g. "com.example.someotherorganizer", or "clapshot.server" for the core server
SemanticVersionNumber min_ver = 2;
}
message SemanticVersionNumber {
uint64 major = 1;
uint64 minor = 2;
uint64 patch = 3;
}
// ---------------------------------------------------------
message Migration {
string uuid = 1; // Unique identifier for this migration
string version = 2; // Schema version this migration will result in. (must be sortable (e.g. "1.2.3", "2024-01-02_b" etc)
repeated Dependency dependencies = 3; // Note: remember to include the plugin itself in the list, if needed
string description = 4; // Human-readable description of the migration, for logging
message Dependency {
string name = 1; // Plugin/module whose schema version to check
optional string min_ver = 2; // "Name"'s schema version must be at least this for this migration to be applicable. (not set = any)
optional string max_ver = 3; // --||-- at most --||--
}
}
message CheckMigrationsRequest {
Database db = 1;
}
message CheckMigrationsResponse {
string name = 1; // Name of the organizer module (see OrganizerInfo)
string current_schema_ver = 2; // Current (last applied) migration version
repeated Migration pending_migrations = 3; // List of pending (alternative) migrations.
// Note that multiple migrations can result in the same resulting schema version, but via different dependencies.
// The algorithm will try to find smallest set of migrations that satisfies all dependencies and achieves the highest version.
}
message ApplyMigrationRequest {
Database db = 1; // Database to apply the migration to. Organizer MUST NOT store the connection, but release it after the call.
string uuid = 2; // UUID of the migration to apply (from CheckMigrationResponse)
}
message ApplyMigrationResponse {}
message AfterMigrationsRequest {}
// ---------------------------------------------------------
message UserSessionData {
string sid = 1;
UserInfo user = 2;
bool is_admin = 3;
map<string, string> cookies = 4;
}
// ---------------------------------------------------------
// Server -> Organizer commands
// ---------------------------------------------------------
message OnStartUserSessionRequest {
UserSessionData ses = 1;
}
message OnStartUserSessionResponse {}
message NavigatePageRequest {
UserSessionData ses = 1;
optional string page_id = 2;
}
message CmdFromClientRequest {
UserSessionData ses = 1;
string cmd = 2;
string args = 3; // Arbitrary data from your own Action handler that is executed on the client
}
message MoveToFolderRequest {
UserSessionData ses = 1;
repeated FolderItemID ids = 2;
string dst_folder_id = 3;
map<string, string> listing_data = 4;
}
message ReorderItemsRequest {
UserSessionData ses = 1;
repeated FolderItemID ids = 2;
map<string, string> listing_data = 3;
}
message AuthzUserActionRequest {
message OtherOp {
enum Op {
LOGIN = 0;
VIEW_HOME = 1;
UPLOAD_MEDIA_FILE = 2;
JOIN_COLLAB_SESSION = 10;
}
Op op = 1;
optional string subject = 2;
}
message MediaFileOp {
enum Op {
VIEW = 0;
RENAME = 1;
DELETE = 2;
COMMENT = 3;
EDIT = 4;
}
MediaFile media_file = 1;
Op op = 2;
}
message CommentOp {
enum Op {
EDIT = 0;
DELETE = 1;
}
Comment comment = 1;
Op op = 2;
}
UserSessionData ses = 1;
oneof op {
OtherOp other_op = 8;
MediaFileOp media_file_op = 9;
CommentOp comment_op = 10;
}
}
message AuthzResponse {
optional bool is_authorized = 1; // If not set, leave authorization decision to server
optional string message = 2; // e.g. "You are not authorized to view this media file"
optional string details = 3; // e.g. "You are not a member of the project"
}
// --- Unit / integration tests ---
message ListTestsResponse {
repeated string test_names = 1;
}
message RunTestRequest {
string test_name = 1;
}
message RunTestResponse {
string output = 1;
optional string error = 2;
}
// ---------------------------------------------------------
// Organizer -> Server commands
// ---------------------------------------------------------
message ClientShowPageRequest {
string sid = 1;
repeated PageItem page_items = 2;
optional string page_id = 3; // Arbitrary string to identify the page. When this changes, the client will consider it a new page in browser history
optional string page_title = 4; // shown in browser tab
}
message ClientShowUserMessageRequest {
UserMessage msg = 1;
oneof recipient {
string sid = 100; // send to client with this session ID
string user_temp = 101; // send to all session with this username
string user_persist = 102; // send to all sessions with this username, and store in DB
string media_file_id = 103; // send to all clients watching this media file
string collab_session = 104; // send to all clients in this collaboration session
}
}
message ClientDefineActionsRequest {
string sid = 1;
map<string, ActionDef> actions = 2; // e.g. "rename" -> {label: "Rename", icon: "edit"}
}
// Tell client of session `sid` to open media file `id` in the player
message ClientOpenMediaFileRequest {
string sid = 1;
string id = 2;
}
message ClientSetCookiesRequest {
string sid = 1;
map<string, string> cookies = 2;
optional google.protobuf.Timestamp expire_time = 3;
}
message DeleteMediaFileRequest {
string id = 1;
}