@@ -25,7 +25,12 @@ import {
2525 CreateDestroyStartStop ,
2626 ready ,
2727} from '@matrixai/async-init/dist/CreateDestroyStartStop' ;
28- import { withF , withG } from '@matrixai/resources' ;
28+ import {
29+ ResourceAcquire ,
30+ ResourceRelease ,
31+ withF ,
32+ withG ,
33+ } from '@matrixai/resources' ;
2934import { RWLockWriter } from '@matrixai/async-locks' ;
3035import * as vaultsUtils from './utils' ;
3136import * as vaultsErrors from './errors' ;
@@ -536,6 +541,86 @@ class VaultInternal {
536541 } ) ;
537542 }
538543
544+ /**
545+ * Acquire a read-only lock on this vault
546+ */
547+ @ready ( new vaultsErrors . ErrorVaultNotRunning ( ) )
548+ public acquireRead ( ) : ResourceAcquire < FileSystemReadable > {
549+ return async ( ) => {
550+ const acquire = this . lock . read ( ) ;
551+ const [ release ] = await acquire ( ) ;
552+ return [
553+ async ( e ?: Error ) => {
554+ release ( e ) ;
555+ } ,
556+ this . efsVault ,
557+ ] ;
558+ } ;
559+ }
560+
561+ /**
562+ * Acquire a read-write lock on this vault
563+ */
564+ @ready ( new vaultsErrors . ErrorVaultNotRunning ( ) )
565+ public acquireWrite (
566+ tran ?: DBTransaction ,
567+ ) : ResourceAcquire < FileSystemWritable > {
568+ return async ( ) => {
569+ let releaseTran : ResourceRelease | undefined = undefined ;
570+ const acquire = this . lock . write ( ) ;
571+ const [ release ] = await acquire ( [ tran ] ) ;
572+ if ( tran == null ) {
573+ const acquireTran = this . db . transaction ( ) ;
574+ [ releaseTran , tran ] = await acquireTran ( ) ;
575+ }
576+ // The returned transaction can be undefined, too. We won't handle those
577+ // cases.
578+ if ( tran == null ) utils . never ( ) ;
579+ await tran . lock (
580+ [ ...this . vaultMetadataDbPath , VaultInternal . dirtyKey ] . join ( '' ) ,
581+ ) ;
582+ if (
583+ ( await tran . get ( [
584+ ...this . vaultMetadataDbPath ,
585+ VaultInternal . remoteKey ,
586+ ] ) ) != null
587+ ) {
588+ // Mirrored vaults are immutable
589+ throw new vaultsErrors . ErrorVaultRemoteDefined ( ) ;
590+ }
591+ await tran . put (
592+ [ ...this . vaultMetadataDbPath , VaultInternal . dirtyKey ] ,
593+ true ,
594+ ) ;
595+ return [
596+ async ( e ?: Error ) => {
597+ if ( e != null ) {
598+ try {
599+ // After doing mutation we need to commit the new history
600+ await this . createCommit ( ) ;
601+ } catch ( e_ ) {
602+ e = e_ ;
603+ }
604+ // This would happen if an error was caught inside the catch block
605+ if ( e != null ) {
606+ // Error implies dirty state
607+ await this . cleanWorkingDirectory ( ) ;
608+ }
609+ }
610+ // For some reason, the transaction type doesn't properly waterfall
611+ // down to here.
612+ await tran ! . put (
613+ [ ...this . vaultMetadataDbPath , VaultInternal . dirtyKey ] ,
614+ false ,
615+ ) ;
616+ if ( releaseTran != null ) releaseTran ( e ) ;
617+ release ( e ) ;
618+ } ,
619+ this . efsVault ,
620+ ] ;
621+ } ;
622+ }
623+
539624 /**
540625 * Pulls changes to a vault from the vault's default remote.
541626 * If `pullNodeId` and `pullVaultNameOrId` it uses that for the remote instead.
0 commit comments