@@ -20,7 +20,9 @@ OUTPUT: starts (or keeps running) the filesystem aware side of an editing sessio
20
20
21
21
*/
22
22
23
- // import { type Client } from "@cocalc/conat/core/client";
23
+ import type { Client , Message , Subscription } from "@cocalc/conat/core/client" ;
24
+ import { STICKY_QUEUE_GROUP } from "@cocalc/conat/core/client" ;
25
+ import { isValidUUID } from "@cocalc/util/misc" ;
24
26
25
27
interface SyncDoc {
26
28
close : ( ) => void ;
@@ -32,7 +34,6 @@ export type SyncDocCreator = (opts: {
32
34
doctype ?: any ;
33
35
} ) => SyncDoc ;
34
36
35
- /*
36
37
interface Options {
37
38
client : Client ;
38
39
@@ -43,28 +44,74 @@ interface Options {
43
44
createSyncDoc : SyncDocCreator ;
44
45
}
45
46
46
- export function init(opts: Options) {
47
- return new SyncServer(opts.client, opts.projects, opts.createSyncDocs);
47
+ export async function init ( opts : Options ) {
48
+ const syncServer = new SyncServer (
49
+ opts . client ,
50
+ opts . projects ,
51
+ opts . createSyncDoc ,
52
+ ) ;
53
+ await syncServer . init ( ) ;
54
+ return syncServer ;
48
55
}
49
56
50
57
interface Api {
51
58
open : ( opts : { path : string ; doctype ?: any } ) => Promise < void > ;
52
59
}
53
60
54
61
class SyncServer {
55
- constructor(client: Client, projects: string, createSyncDoc: SyncDocCreator) {
56
- this.client.service = await client1.service<Api>("arith.*", {
57
- add: async (a, b) => a + b,
58
- mul: async (a, b) => a * b,
59
- // Here we do NOT use an arrow => function and this is
60
- // bound to the calling mesg, which lets us get the subject.
61
- // Because user identity and permissions are done via wildcard
62
- // subjects, having access to the calling message is critical
63
- async open({ path, doctype }) {
64
- const mesg: Message = this as any;
65
- console.log(mesg.subject);
62
+ private service ?: Subscription ;
63
+ private syncDocs : { [ key : string ] : SyncDoc } = { } ;
64
+ private interest : { [ key : string ] : number } = { } ;
65
+
66
+ constructor (
67
+ private client : Client ,
68
+ private projects : string ,
69
+ private createSyncDoc : SyncDocCreator ,
70
+ ) { }
71
+
72
+ init = async ( ) => {
73
+ const self = this ;
74
+ this . service = await this . client . service < Api > (
75
+ "sync.*.open" ,
76
+ {
77
+ async open ( { path, doctype } ) {
78
+ const mesg : Message = this as any ;
79
+ self . open ( mesg . subject , path , doctype ) ;
80
+ } ,
66
81
} ,
82
+ { queue : STICKY_QUEUE_GROUP } ,
83
+ ) ;
84
+ } ;
85
+
86
+ private key = ( project_id , path ) => {
87
+ return `${ project_id } /${ path } ` ;
88
+ } ;
89
+
90
+ private open = ( subject : string , path : string , doctype ) => {
91
+ const project_id = subject . split ( "." ) [ 1 ] ?. slice ( "project-" . length ) ;
92
+ console . log ( "open" , {
93
+ subject,
94
+ path,
95
+ doctype,
96
+ project_id,
97
+ projects : this . projects ,
67
98
} ) ;
68
- }
99
+ if ( ! isValidUUID ( project_id ) ) {
100
+ throw Error ( "invalid subject" ) ;
101
+ }
102
+ const key = this . key ( project_id , path ) ;
103
+ if ( this . syncDocs [ key ] === undefined ) {
104
+ this . syncDocs [ key ] = this . createSyncDoc ( { project_id, path, doctype } ) ;
105
+ }
106
+ this . interest [ key ] = Date . now ( ) ;
107
+ } ;
108
+
109
+ close = ( ) => {
110
+ this . service ?. close ( ) ;
111
+ delete this . service ;
112
+ for ( const key in this . syncDocs ) {
113
+ this . syncDocs [ key ] . close ( ) ;
114
+ delete this . syncDocs [ key ] ;
115
+ }
116
+ } ;
69
117
}
70
- */
0 commit comments