@@ -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