@@ -29,10 +29,11 @@ const FETCH_INTERVAL_MAX = 5000
2929const FETCH_INTERVAL_SINGLE_EDITOR = 5000
3030
3131/**
32- * Interval to check for changes for read only users
32+ * Interval to check for permission changes while read-only.
33+ * Step updates are rare here; keep polling fast so edit permission can be restored.
3334 * @type {number }
3435 */
35- const FETCH_INTERVAL_READ_ONLY = 30000
36+ const FETCH_INTERVAL_READ_ONLY = 5000
3637
3738/**
3839 * Interval to fetch for changes when a browser window is considered invisible by the
@@ -42,8 +43,6 @@ const FETCH_INTERVAL_READ_ONLY = 30000
4243 */
4344const FETCH_INTERVAL_INVISIBLE = 20000
4445
45- const FETCH_INTERVAL_NOTIFY = 30000
46-
4746/* Maximum number of retries for fetching before emitting a connection error */
4847const MAX_RETRY_FETCH_COUNT = 5
4948
@@ -59,6 +58,8 @@ class PollingBackend {
5958 #syncService
6059 /** @type {Connection } */
6160 #connection
61+ /** @type {boolean } */
62+ #readOnly = false
6263
6364 #lastPoll
6465 #fetchInterval
@@ -73,6 +74,7 @@ class PollingBackend {
7374 this . #fetchInterval = FETCH_INTERVAL
7475 this . #fetchRetryCounter = 0
7576 this . #lastPoll = 0
77+ this . #readOnly = connection . state ?. document ?. readOnly ?? false
7678 }
7779
7880 connect ( ) {
@@ -126,6 +128,18 @@ class PollingBackend {
126128 const { document, sessions } = data
127129 this . #fetchRetryCounter = 0
128130
131+ if ( data . readOnly !== undefined && data . readOnly !== this . #readOnly) {
132+ this . #readOnly = data . readOnly
133+ this . #syncService. bus . emit ( 'permissionChange' , {
134+ readOnly : this . #readOnly,
135+ } )
136+ if ( data . readOnly ) {
137+ this . maximumReadOnlyTimer ( )
138+ } else {
139+ this . resetRefetchTimer ( )
140+ }
141+ }
142+
129143 this . #syncService. bus . emit ( 'change' , { document, sessions } )
130144 this . #syncService. receiveSteps ( data )
131145
@@ -138,7 +152,7 @@ class PollingBackend {
138152 }
139153 const disconnect = Date . now ( ) - COLLABORATOR_DISCONNECT_TIME
140154 const alive = sessions . filter ( ( s ) => s . lastContact * 1000 > disconnect )
141- if ( this . #syncService . isReadOnly ) {
155+ if ( this . #readOnly ) {
142156 this . maximumReadOnlyTimer ( )
143157 } else if ( alive . length < 2 ) {
144158 this . maximumRefetchTimer ( )
@@ -197,25 +211,30 @@ class PollingBackend {
197211 document . removeEventListener ( 'visibilitychange' , this . visibilitychange . bind ( this ) )
198212 }
199213
214+ #notifyPushInterval( ) {
215+ // notify_push delivers step updates but not permission changes
216+ return FETCH_INTERVAL_SINGLE_EDITOR
217+ }
218+
200219 resetRefetchTimer ( ) {
201220 if ( this . #notifyPushBus && this . #initialLoadingFinished) {
202- this . #fetchInterval = FETCH_INTERVAL_NOTIFY
221+ this . #fetchInterval = this . #notifyPushInterval ( )
203222 return
204223 }
205224 this . #fetchInterval = FETCH_INTERVAL
206225 }
207226
208227 increaseRefetchTimer ( ) {
209228 if ( this . #notifyPushBus && this . #initialLoadingFinished) {
210- this . #fetchInterval = FETCH_INTERVAL_NOTIFY
229+ this . #fetchInterval = this . #notifyPushInterval ( )
211230 return
212231 }
213232 this . #fetchInterval = Math . min ( this . #fetchInterval * 2 , FETCH_INTERVAL_MAX )
214233 }
215234
216235 maximumRefetchTimer ( ) {
217236 if ( this . #notifyPushBus && this . #initialLoadingFinished) {
218- this . #fetchInterval = FETCH_INTERVAL_NOTIFY
237+ this . #fetchInterval = this . #notifyPushInterval ( )
219238 return
220239 }
221240 this . #fetchInterval = FETCH_INTERVAL_SINGLE_EDITOR
0 commit comments