@@ -3,7 +3,19 @@ import { Button } from "antd";
33import Toast from "libs/toast" ;
44import messages from "messages" ;
55import React from "react" ;
6- import { call , cancel , cancelled , delay , fork , put , retry , takeEvery } from "typed-redux-saga" ;
6+ import {
7+ call ,
8+ cancel ,
9+ cancelled ,
10+ delay ,
11+ type FixedTask ,
12+ fork ,
13+ put ,
14+ race ,
15+ retry ,
16+ take ,
17+ takeEvery ,
18+ } from "typed-redux-saga" ;
719import {
820 type SetIsMutexAcquiredAction ,
921 type SetOthersMayEditForAnnotationAction ,
@@ -14,11 +26,15 @@ import {
1426import type { Saga } from "viewer/model/sagas/effect-generators" ;
1527import { select } from "viewer/model/sagas/effect-generators" ;
1628import { ensureWkReady } from "../ready_sagas" ;
29+ import { EnsureMaySaveNowAction } from "viewer/model/actions/save_actions" ;
30+
31+ // Also refer to application.conf where annotation.mutex.expiryTime is defined
32+ // (typically, 2 minutes).
1733
1834const MUTEX_NOT_ACQUIRED_KEY = "MutexCouldNotBeAcquired" ;
1935const MUTEX_ACQUIRED_KEY = "AnnotationMutexAcquired" ;
20- const RETRY_COUNT = 12 ;
2136const ACQUIRE_MUTEX_INTERVAL = 1000 * 60 ;
37+ const RETRY_COUNT = 12 ; // 12 retries with 60/12=5 seconds backup delay
2238
2339// todop
2440const DISABLE_EAGER_MUTEX_ACQUISITION = true ;
@@ -32,27 +48,23 @@ function* getDoesHaveMutex(): Saga<boolean> {
3248}
3349
3450export function * acquireAnnotationMutexMaybe ( ) : Saga < void > {
35- if ( DISABLE_EAGER_MUTEX_ACQUISITION ) {
36- return ;
37- }
51+ yield * call ( ensureWkReady ) ;
3852 const initialAllowUpdate = yield * select (
3953 ( state ) => state . annotation . restrictions . initialAllowUpdate ,
4054 ) ;
4155 if ( ! initialAllowUpdate ) {
42- // We are in an read-only annotation.
56+ // We are in an read-only annotation. There's no point in acquiring mutexes.
57+ console . log ( "exit mutex saga" ) ;
4358 return ;
4459 }
4560 const mutexLogicState : MutexLogicState = {
4661 isInitialRequest : true ,
4762 } ;
4863
49- yield * call ( ensureWkReady ) ;
5064 yield * fork ( watchMutexStateChangesForNotification , mutexLogicState ) ;
5165
52- let runningTryAcquireMutexContinuouslySaga = yield * fork (
53- tryAcquireMutexContinuously ,
54- mutexLogicState ,
55- ) ;
66+ let runningTryAcquireMutexContinuouslySaga : FixedTask < void > | null ;
67+
5668 function * reactToOthersMayEditChanges ( {
5769 othersMayEdit,
5870 } : SetOthersMayEditForAnnotationAction ) : Saga < void > {
@@ -65,8 +77,9 @@ export function* acquireAnnotationMutexMaybe(): Saga<void> {
6577 mutexLogicState ,
6678 ) ;
6779 } else {
68- // othersMayEdit was turned off. The user editing it should be able to edit the annotation.
69- // let's check that owner === activeUser, anyway.
80+ // othersMayEdit was turned off by the activeUser. Since this is only
81+ // allowed by the owner, they should be able to edit the annotation, too.
82+ // Still, let's check that owner === activeUser to be extra safe.
7083 const owner = yield * select ( ( storeState ) => storeState . annotation . owner ) ;
7184 const activeUser = yield * select ( ( state ) => state . activeUser ) ;
7285 if ( activeUser && owner ?. id === activeUser ?. id ) {
@@ -75,16 +88,55 @@ export function* acquireAnnotationMutexMaybe(): Saga<void> {
7588 }
7689 }
7790 yield * takeEvery ( "SET_OTHERS_MAY_EDIT_FOR_ANNOTATION" , reactToOthersMayEditChanges ) ;
91+
92+ if ( DISABLE_EAGER_MUTEX_ACQUISITION ) {
93+ console . log ( "listening to all ENSURE_MAY_SAVE_NOW" ) ;
94+ yield * takeEvery ( "ENSURE_MAY_SAVE_NOW" , resolveEnsureMaySaveNowActions ) ;
95+ while ( true ) {
96+ console . log ( "taking ENSURE_MAY_SAVE_NOW" ) ;
97+ yield * take ( "ENSURE_MAY_SAVE_NOW" ) ;
98+ console . log ( "took ENSURE_MAY_SAVE_NOW" ) ;
99+ const { doneSaving } = yield race ( {
100+ tryAcquireMutexContinuously : fork ( tryAcquireMutexContinuously , mutexLogicState ) ,
101+ doneSaving : take ( "DONE_SAVING" ) ,
102+ } ) ;
103+ if ( doneSaving ) {
104+ yield call ( releaseMutex ) ;
105+ }
106+ }
107+ } else {
108+ runningTryAcquireMutexContinuouslySaga = yield * fork (
109+ tryAcquireMutexContinuously ,
110+ mutexLogicState ,
111+ ) ;
112+ }
78113}
79114
80- function * tryAcquireMutexContinuously ( mutexLogicState : MutexLogicState ) : Saga < void > {
115+ function * resolveEnsureMaySaveNowActions ( action : EnsureMaySaveNowAction ) {
116+ /*
117+ * For each EnsureMaySaveNowAction wait until, we have the mutex. Then call
118+ * the callback.
119+ */
120+ while ( true ) {
121+ const doesHaveMutex = yield * select ( getDoesHaveMutex ) ;
122+ if ( doesHaveMutex ) {
123+ action . callback ( ) ;
124+ return ;
125+ }
126+ yield * take ( "SET_BLOCKED_BY_USER" ) ;
127+ }
128+ }
129+
130+ function * tryAcquireMutexContinuously ( mutexLogicState : MutexLogicState ) : Saga < never > {
131+ console . log ( "started tryAcquireMutexContinuously" ) ;
81132 const annotationId = yield * select ( ( storeState ) => storeState . annotation . annotationId ) ;
82133 const activeUser = yield * select ( ( state ) => state . activeUser ) ;
83134 mutexLogicState . isInitialRequest = true ;
84135
85136 // We can simply use an infinite loop here, because the saga will be cancelled by
86137 // reactToOthersMayEditChanges when othersMayEdit is set to false.
87138 while ( true ) {
139+ console . log ( "tryAcquireMutexContinuously loop" ) ;
88140 const blockedByUser = yield * select ( ( state ) => state . annotation . blockedByUser ) ;
89141 if ( blockedByUser == null || blockedByUser . id !== activeUser ?. id ) {
90142 // If the annotation is currently not blocked by the active user,
@@ -114,7 +166,9 @@ function* tryAcquireMutexContinuously(mutexLogicState: MutexLogicState): Saga<vo
114166 // Therefore, we also print the error in the test context.
115167 console . error ( "Error while trying to acquire mutex:" , error ) ;
116168 }
169+ // todop: I think this needs to happen in a finally block?
117170 const wasCanceled = yield * cancelled ( ) ;
171+ console . log ( "wasCanceled" , wasCanceled ) ;
118172 if ( ! wasCanceled ) {
119173 console . error ( "Error while trying to acquire mutex." , error ) ;
120174 yield * put ( setBlockedByUserAction ( undefined ) ) ;
@@ -159,3 +213,15 @@ function* watchMutexStateChangesForNotification(mutexLogicState: MutexLogicState
159213 } ,
160214 ) ;
161215}
216+
217+ function * releaseMutex ( ) {
218+ const annotationId = yield * select ( ( storeState ) => storeState . annotation . annotationId ) ;
219+ yield * retry (
220+ RETRY_COUNT ,
221+ ACQUIRE_MUTEX_INTERVAL / RETRY_COUNT ,
222+ acquireAnnotationMutex ,
223+ annotationId ,
224+ ) ;
225+ yield * put ( setAnnotationAllowUpdateAction ( true ) ) ;
226+ yield * put ( setBlockedByUserAction ( null ) ) ;
227+ }
0 commit comments