11import debounce from 'lodash/debounce' ;
22import get from 'lodash/get' ;
33import pick from 'lodash/pick' ;
4+ import orderBy from 'lodash/orderBy' ;
5+ import uniq from 'lodash/uniq' ;
46import applyChanges from './applyRemoteChanges' ;
57import { hasActiveLocks , cleanupLocks } from './changes' ;
68import {
@@ -10,6 +12,7 @@ import {
1012 IGNORED_SOURCE ,
1113 CHANNEL_SYNC_KEEP_ALIVE_INTERVAL ,
1214 ACTIVE_CHANNELS ,
15+ MAX_REV_KEY ,
1316} from './constants' ;
1417import db from './db' ;
1518import mergeAllChanges from './mergeChanges' ;
@@ -22,6 +25,10 @@ import urls from 'shared/urls';
2225// change being registered, sync changes!
2326const SYNC_IF_NO_CHANGES_FOR = 2 ;
2427
28+ // When this many seconds pass, repoll the backend to
29+ // check for any updates to active channels, or the user and sync any current changes
30+ const SYNC_POLL_INTERVAL = 5 ;
31+
2532// Flag to check if a sync is currently active.
2633let syncActive = false ;
2734
@@ -142,15 +149,32 @@ function handleSuccesses(response) {
142149 const successes = get ( response , [ 'data' , 'successes' ] , [ ] ) ;
143150 if ( successes . length ) {
144151 return db [ CHANGES_TABLE ] . where ( 'server_rev' )
145- . anyOf ( successes )
152+ . anyOf ( successes . map ( c => c . server_rev ) )
146153 . delete ( ) ;
147154 }
148155 return Promise . resolve ( ) ;
149156}
150157
151- function handleMaxRev ( response ) {
152- const max_rev = response . data . max_rev ;
153- return Session . updateSession ( { max_rev } ) ;
158+ function handleMaxRevs ( response , userId ) {
159+ const allChanges = orderBy (
160+ get ( response , [ 'data' , 'changes' ] , [ ] )
161+ . concat ( get ( response , [ 'data' , 'errors' ] , [ ] ) )
162+ . concat ( get ( response , [ 'data' , 'successes' ] , [ ] ) ) ,
163+ 'server_rev' ,
164+ 'desc'
165+ ) ;
166+ const channelIds = uniq ( allChanges . map ( c => c . channel_id ) ) . filter ( Boolean ) ;
167+ const maxRevs = { } ;
168+ for ( let channelId of channelIds ) {
169+ maxRevs [ `${ MAX_REV_KEY } .${ channelId } ` ] = allChanges . find (
170+ c => c . channel_id === channelId
171+ ) . server_rev ;
172+ }
173+ const lastUserChange = allChanges . find ( c => c . user_id === userId ) ;
174+ if ( lastUserChange ) {
175+ maxRevs . user_rev = lastUserChange . server_rev ;
176+ }
177+ return Session . updateSession ( maxRevs ) ;
154178}
155179
156180async function syncChanges ( ) {
@@ -169,26 +193,29 @@ async function syncChanges() {
169193 // might have come in during processing - leave them for the next cycle.
170194 // This is the primary key of the change objects, so the collection is ordered by this
171195 // by default - if we just grab the last object, we can get the key from there.
172- const [ lastChange , earliestServerChange , user ] = await Promise . all ( [
196+ const [ lastChange , user ] = await Promise . all ( [
173197 db [ CHANGES_TABLE ] . orderBy ( 'rev' ) . last ( ) ,
174- db [ CHANGES_TABLE ] . orderBy ( 'server_rev' ) . first ( ) ,
175198 Session . getSession ( ) ,
176199 ] ) ;
177200 if ( ! user ) {
178201 // If not logged in, nothing to do.
179202 return ;
180203 }
204+
181205 const now = Date . now ( ) ;
182- const currentUser = await Session . getSession ( ) ;
183- const channel_ids = Object . entries ( currentUser [ ACTIVE_CHANNELS ] )
206+ const channel_ids = Object . entries ( user [ ACTIVE_CHANNELS ] )
184207 . filter ( ( [ id , time ] ) => id && time > now - CHANNEL_SYNC_KEEP_ALIVE_INTERVAL )
185208 . map ( ( [ id ] ) => id ) ;
209+ const channel_revs = { } ;
210+ console . log ( user ) ;
211+ for ( let channelId of channel_ids ) {
212+ channel_revs [ channelId ] = get ( user , [ MAX_REV_KEY , channelId ] , 0 ) ;
213+ }
214+
186215 const requestPayload = {
187216 changes : [ ] ,
188- channel_ids,
189- // Last rev to send to the server is either the earliest change we are still seeking
190- // confirmation on, or the current max_rev that we have synced to the frontend.
191- last_rev : ( earliestServerChange && earliestServerChange . server_rev ) || user . max_rev ,
217+ channel_revs,
218+ user_rev : user . user_rev || 0 ,
192219 } ;
193220
194221 if ( lastChange ) {
@@ -216,7 +243,7 @@ async function syncChanges() {
216243 // "allowed": [],
217244 // "changes": [],
218245 // "errors": [],
219- // "successess ": [],
246+ // "successes ": [],
220247 // }
221248 const response = await client . post ( urls [ 'sync' ] ( ) , requestPayload ) ;
222249 try {
@@ -226,7 +253,7 @@ async function syncChanges() {
226253 handleReturnedChanges ( response ) ,
227254 handleErrors ( response ) ,
228255 handleSuccesses ( response ) ,
229- handleMaxRev ( response ) ,
256+ handleMaxRevs ( response , user . id ) ,
230257 ] ) ;
231258 } catch ( err ) {
232259 console . error ( 'There was an error updating change status' , err ) ; // eslint-disable-line no-console
@@ -279,15 +306,20 @@ async function handleChanges(changes) {
279306 }
280307}
281308
309+ let intervalTimer ;
310+
282311export function startSyncing ( ) {
283312 cleanupLocks ( ) ;
284313 // Initiate a sync immediately in case any data
285314 // is left over in the database.
286315 debouncedSyncChanges ( ) ;
316+ // Start the sync interval
317+ intervalTimer = setInterval ( debouncedSyncChanges , SYNC_POLL_INTERVAL * 1000 ) ;
287318 db . on ( 'changes' , handleChanges ) ;
288319}
289320
290321export function stopSyncing ( ) {
322+ clearInterval ( intervalTimer ) ;
291323 debouncedSyncChanges . cancel ( ) ;
292324 // Dexie's slightly counterintuitive method for unsubscribing from events
293325 db . on ( 'changes' ) . unsubscribe ( handleChanges ) ;
0 commit comments