@@ -145,100 +145,46 @@ class LLWriteBase extends LLFilesystemOperation {
145145 }
146146}
147147
148+ /**
149+ * The "overwrite" write operation.
150+ *
151+ * This operation is used to write a file to an existing path.
152+ *
153+ * @extends LLWriteBase
154+ */
148155class LLOWrite extends LLWriteBase {
149156 async _run ( ) {
150- const {
151- node, actor, immutable,
152- file, tmp, fsentry_tmp,
153- message,
154- } = this . values ;
155-
156- const svc = Context . get ( 'services' ) ;
157- const sizeService = svc . get ( 'sizeService' ) ;
158- const resourceService = svc . get ( 'resourceService' ) ;
159- const svc_fsEntry = svc . get ( 'fsEntryService' ) ;
160- const svc_event = svc . get ( 'event' ) ;
157+ const node = this . values . node ;
161158
162- // TODO: fs:decouple-versions
163- // add version hook externally so LLCWrite doesn't
164- // need direct database access
165- const db = svc . get ( 'database' ) . get ( DB_WRITE , 'filesystem' ) ;
159+ // Embed fields into this.context
160+ this . context . set ( 'immutable' , this . values . immutable ) ;
161+ this . context . set ( 'tmp' , this . values . tmp ) ;
162+ this . context . set ( 'fsentry_tmp' , this . values . fsentry_tmp ) ;
163+ this . context . set ( 'message' , this . values . message ) ;
164+ this . context . set ( 'actor' , this . values . actor ) ;
165+ this . context . set ( 'app_id' , this . values . app_id ) ;
166166
167167 // TODO: Add symlink write
168168 if ( ! await node . exists ( ) ) {
169169 // TODO: different class of errors for low-level operations
170170 throw APIError . create ( 'subject_does_not_exist' ) ;
171171 }
172172
173- const svc_acl = this . context . get ( 'services' ) . get ( 'acl' ) ;
174- if ( ! await svc_acl . check ( actor , node , 'write' ) ) {
175- throw await svc_acl . get_safe_acl_error ( actor , node , 'write' ) ;
176- }
177-
178- const uid = await node . get ( 'uid' ) ;
179-
180- const bucket_region = node . entry . bucket_region ;
181- const bucket = node . entry . bucket ;
182-
183- const state_upload = await this . _storage_upload ( {
184- uuid : node . entry . uuid ,
185- bucket, bucket_region, file,
186- tmp : {
187- ...tmp ,
188- path : await node . get ( 'path' ) ,
189- }
190- } ) ;
191-
192- if ( fsentry_tmp ?. thumbnail_promise ) {
193- fsentry_tmp . thumbnail = await fsentry_tmp . thumbnail_promise ;
194- delete fsentry_tmp . thumbnail_promise ;
195- }
196-
197- const ts = Math . round ( Date . now ( ) / 1000 ) ;
198- const raw_fsentry_delta = {
199- modified : ts ,
200- accessed : ts ,
201- size : file . size ,
202- ...fsentry_tmp ,
203- } ;
204-
205- resourceService . register ( {
206- uid,
207- status : RESOURCE_STATUS_PENDING_CREATE ,
208- } ) ;
209-
210- const filesize = file . size ;
211- sizeService . change_usage ( actor . type . user . id , filesize ) ;
212-
213- const entryOp = await svc_fsEntry . update ( uid , raw_fsentry_delta ) ;
214-
215- // depends on fsentry, does not depend on S3
216- ( async ( ) => {
217- await entryOp . awaitDone ( ) ;
218- this . log . debug ( '[owrite] finished creating fsentry' , { uid } )
219- resourceService . free ( uid ) ;
220- svc_event . emit ( 'fs.written.file' , {
221- node,
222- context : this . context ,
223- } ) ;
224- } ) ( ) ;
225-
226- state_upload . post_insert ( {
227- db, user : actor . type . user , node, uid, message, ts,
228- } ) ;
229-
230- const svc_fileCache = this . context . get ( 'services' ) . get ( 'file-cache' ) ;
231- await svc_fileCache . invalidate ( node ) ;
232-
233- svc_event . emit ( 'fs.write.file' , {
234- node,
173+ return await node . provider . write_overwrite ( {
235174 context : this . context ,
175+ node : node ,
176+ file : this . values . file ,
236177 } ) ;
237-
238- return node ;
239178 }
240179}
241180
181+ /**
182+ * The "non-overwrite" write operation.
183+ *
184+ * This operation is used to write a file to a non-existent path.
185+ *
186+ * @extends LLWriteBase
187+ */
242188class LLCWrite extends LLWriteBase {
243189 static MODULES = {
244190 _path : require ( 'path' ) ,
@@ -247,144 +193,26 @@ class LLCWrite extends LLWriteBase {
247193 }
248194
249195 async _run ( ) {
250- const { _path, uuidv4, config } = this . modules ;
251- const {
252- parent, name, immutable,
253- file, tmp, fsentry_tmp,
254- message,
255-
256- actor : actor_let ,
257- app_id,
258- } = this . values ;
259- let actor = actor_let ;
260-
261- const svc = Context . get ( 'services' ) ;
262- const sizeService = svc . get ( 'sizeService' ) ;
263- const resourceService = svc . get ( 'resourceService' ) ;
264- const svc_fsEntry = svc . get ( 'fsEntryService' ) ;
265- const svc_event = svc . get ( 'event' ) ;
266- const fs = svc . get ( 'filesystem' ) ;
267-
268- // TODO: fs:decouple-versions
269- // add version hook externally so LLCWrite doesn't
270- // need direct database access
271- const db = svc . get ( 'database' ) . get ( DB_WRITE , 'filesystem' ) ;
272-
273- const uid = uuidv4 ( ) ;
274- this . field ( 'fsentry-uid' , uid ) ;
196+ const parent = this . values . parent ;
275197
276- // determine bucket region
277- let bucket_region = config . s3_region ?? config . region ;
278- let bucket = config . s3_bucket ;
198+ // Embed fields into this.context
199+ this . context . set ( 'immutable' , this . values . immutable ) ;
200+ this . context . set ( 'tmp' , this . values . tmp ) ;
201+ this . context . set ( 'fsentry_tmp' , this . values . fsentry_tmp ) ;
202+ this . context . set ( 'message' , this . values . message ) ;
203+ this . context . set ( 'actor' , this . values . actor ) ;
204+ this . context . set ( 'app_id' , this . values . app_id ) ;
279205
280- this . checkpoint ( 'before acl' ) ;
281206 if ( ! await parent . exists ( ) ) {
282207 throw APIError . create ( 'subject_does_not_exist' ) ;
283208 }
284209
285- const svc_acl = this . context . get ( 'services' ) . get ( 'acl' ) ;
286- actor = actor ?? Context . get ( 'actor' ) ;
287- if ( ! await svc_acl . check ( actor , parent , 'write' ) ) {
288- throw await svc_acl . get_safe_acl_error ( actor , parent , 'write' ) ;
289- }
290-
291- this . checkpoint ( 'before storage upload' ) ;
292-
293- const storage_resp = await this . _storage_upload ( {
294- uuid : uid ,
295- bucket, bucket_region, file,
296- tmp : {
297- ...tmp ,
298- path : _path . join ( await parent . get ( 'path' ) , name ) ,
299- }
300- } ) ;
301-
302- this . checkpoint ( 'after storage upload' ) ;
303-
304- fsentry_tmp . thumbnail = await fsentry_tmp . thumbnail_promise ;
305- delete fsentry_tmp . thumbnail_promise ;
306-
307- this . checkpoint ( 'after thumbnail promise' ) ;
308-
309- const ts = Math . round ( Date . now ( ) / 1000 ) ;
310- const raw_fsentry = {
311- uuid : uid ,
312- is_dir : 0 ,
313- user_id : actor . type . user . id ,
314- created : ts ,
315- accessed : ts ,
316- modified : ts ,
317- parent_uid : await parent . get ( 'uid' ) ,
318- name,
319- size : file . size ,
320- path : _path . join ( await parent . get ( 'path' ) , name ) ,
321- ...fsentry_tmp ,
322-
323- bucket_region,
324- bucket,
325-
326- associated_app_id : app_id ?? null ,
327- } ;
328-
329- svc_event . emit ( 'fs.pending.file' , {
330- fsentry : FSNodeContext . sanitize_pending_entry_info ( raw_fsentry ) ,
331- context : this . context ,
332- } )
333-
334- this . checkpoint ( 'after emit pending file' ) ;
335-
336- resourceService . register ( {
337- uid,
338- status : RESOURCE_STATUS_PENDING_CREATE ,
339- } ) ;
340-
341- const filesize = file . size ;
342- sizeService . change_usage ( actor . type . user . id , filesize ) ;
343-
344- this . checkpoint ( 'after change_usage' ) ;
345-
346- const entryOp = await svc_fsEntry . insert ( raw_fsentry ) ;
347-
348- this . checkpoint ( 'after fsentry insert enqueue' ) ;
349-
350- ( async ( ) => {
351- await entryOp . awaitDone ( ) ;
352- this . log . debug ( 'finished creating fsentry' , { uid } )
353- resourceService . free ( uid ) ;
354-
355- const new_item_node = await fs . node ( new NodeUIDSelector ( uid ) ) ;
356- const new_item = await new_item_node . get ( 'entry' ) ;
357- const store_version_id = storage_resp . VersionId ;
358- if ( store_version_id ) {
359- // insert version into db
360- db . write (
361- "INSERT INTO `fsentry_versions` (`user_id`, `fsentry_id`, `fsentry_uuid`, `version_id`, `message`, `ts_epoch`) VALUES (?, ?, ?, ?, ?, ?)" ,
362- [
363- actor . type . user . id ,
364- new_item . id ,
365- new_item . uuid ,
366- store_version_id ,
367- message ?? null ,
368- ts ,
369- ]
370- ) ;
371- }
372- } ) ( ) ;
373-
374- this . checkpoint ( 'after version IIAFE' ) ;
375-
376- const node = await fs . node ( new NodeUIDSelector ( uid ) ) ;
377-
378- this . checkpoint ( 'after create FSNodeContext' ) ;
379-
380- svc_event . emit ( 'fs.create.file' , {
381- node,
210+ return await parent . provider . write_new ( {
382211 context : this . context ,
212+ parent,
213+ name : this . values . name ,
214+ file : this . values . file ,
383215 } ) ;
384-
385- this . checkpoint ( 'return result' ) ;
386-
387- return node ;
388216 }
389217}
390218
0 commit comments