@@ -10,6 +10,7 @@ const qr = require('qr-image')
10
10
const ipcMain = electron . ipcMain
11
11
const locale = require ( './locale' )
12
12
const messages = require ( '../js/constants/messages' )
13
+ const siteTags = require ( '../js/constants/siteTags' )
13
14
const syncMessages = require ( '../js/constants/sync/messages' )
14
15
const categories = require ( '../js/constants/sync/proto' ) . categories
15
16
const writeActions = require ( '../js/constants/sync/proto' ) . actions
@@ -27,7 +28,6 @@ const extensions = require('./extensions')
27
28
28
29
const CATEGORY_MAP = syncUtil . CATEGORY_MAP
29
30
const CATEGORY_NAMES = Object . keys ( categories )
30
- const SYNC_ACTIONS = Object . values ( syncConstants )
31
31
32
32
// The sync background script message sender
33
33
let backgroundSender = null
@@ -47,7 +47,7 @@ let pollIntervalId = null
47
47
let deviceIdSent = false
48
48
let bookmarksToolbarShown = false
49
49
50
- // Determines what to sync
50
+ // Syncs state diffs to the sync server if needed
51
51
const appStoreChangeCallback = function ( diffs ) {
52
52
if ( ! backgroundSender ) {
53
53
return
@@ -73,34 +73,61 @@ const appStoreChangeCallback = function (diffs) {
73
73
return
74
74
}
75
75
76
- const isInsert = diff . op === 'add' && path . length === 3
77
- const isUpdate = fieldsToPick . includes ( path [ 3 ] ) // Ignore insignicant updates
76
+ let action = null
78
77
79
- // DELETES are handled in appState because the old object is no longer
80
- // available by the time emitChanges is received
81
- if ( isInsert || isUpdate ) {
82
- // Get the item's path and entry in appStore
83
- const statePath = path . slice ( 1 , 3 ) . map ( ( item ) => item . replace ( / ~ 1 / g, '/' ) )
84
- const entry = AppStore . getState ( ) . getIn ( statePath )
85
- if ( ! entry || ! entry . toJS ) {
86
- return
87
- }
88
-
89
- let action = null
90
-
91
- if ( isInsert && ! entry . get ( 'skipSync' ) ) {
78
+ if ( path . length === 3 || path [ 3 ] === 'tags' ) {
79
+ // XXX: adding/removing a tag (e.g. 'bookmark') corresponds to adding/deleting a site record in sync
80
+ if ( diff . op === 'add' ) {
92
81
action = writeActions . CREATE
93
- } else if ( isUpdate ) {
94
- action = writeActions . UPDATE
82
+ } else if ( diff . op === 'remove' ) {
83
+ action = writeActions . DELETE
95
84
}
85
+ } else if ( fieldsToPick . includes ( path [ 3 ] ) ) {
86
+ action = writeActions . UPDATE
87
+ }
96
88
97
- if ( action !== null ) {
98
- // Set the object ID if there is not already one
99
- const entryJS = entry . toJS ( )
100
- entryJS . objectId = entryJS . objectId || syncUtil . newObjectId ( statePath )
89
+ if ( action === null ) {
90
+ return
91
+ }
101
92
102
- sendSyncRecords ( backgroundSender , action ,
103
- [ type === 'sites' ? syncUtil . createSiteData ( entryJS ) : syncUtil . createSiteSettingsData ( statePath [ 1 ] , entryJS ) ] )
93
+ const statePath = path . slice ( 1 , 3 ) . map ( ( item ) => item . replace ( / ~ 1 / g, '/' ) )
94
+ const state = AppStore . getState ( )
95
+ const entry = state . getIn ( statePath )
96
+ const isSite = type === 'sites'
97
+
98
+ if ( isSite && action === writeActions . DELETE && ! entry ) {
99
+ // If we deleted the site, it is no longer availble in appState.
100
+ // Find the corresponding objectId using the sync cache
101
+ // and send this in the sync record
102
+ const objectId = syncUtil . siteKeyToObjectId ( state , statePath [ 1 ] )
103
+ if ( objectId ) {
104
+ // Delete the site from both history and bookmarks
105
+ sendSyncRecords ( backgroundSender , action , [ {
106
+ name : 'bookmark' ,
107
+ objectId,
108
+ value : { }
109
+ } ] )
110
+ sendSyncRecords ( backgroundSender , action , [ {
111
+ name : 'historySite' ,
112
+ objectId,
113
+ value : { }
114
+ } ] )
115
+ }
116
+ } else if ( entry && entry . toJS ) {
117
+ const entryJS = entry . toJS ( )
118
+ if ( action === writeActions . DELETE && isSite ) {
119
+ const tags = entryJS . tags || [ ]
120
+ sendSyncRecords ( backgroundSender , action , [ {
121
+ objectId : entryJS . objectId ,
122
+ value : { } ,
123
+ name : tags . includes ( siteTags . BOOKMARK ) || siteTags . includes ( siteTags . BOOKMARK_FOLDER )
124
+ ? 'historySite' // if the site is still a bookmark, it must have been deleted from history
125
+ : 'bookmark'
126
+ } ] )
127
+ } else {
128
+ sendSyncRecords ( backgroundSender , action , [
129
+ isSite ? syncUtil . createSiteData ( entryJS , state ) : syncUtil . createSiteSettingsData ( statePath [ 1 ] , entryJS )
130
+ ] )
104
131
}
105
132
}
106
133
} )
@@ -110,7 +137,7 @@ const appStoreChangeCallback = function (diffs) {
110
137
* Sends sync records of the same category to the sync server.
111
138
* @param {event.sender } sender
112
139
* @param {number } action
113
- * @param {Array.<{name: string, value: Object}> } data
140
+ * @param {Array.<{objectId: Array, name: string, value: Object}> } data
114
141
*/
115
142
const sendSyncRecords = ( sender , action , data ) => {
116
143
if ( ! deviceId ) {
@@ -125,7 +152,7 @@ const sendSyncRecords = (sender, action, data) => {
125
152
return
126
153
}
127
154
sender . send ( syncMessages . SEND_SYNC_RECORDS , category . categoryName , data . map ( ( item ) => {
128
- if ( ! item || ! item . name || ! item . value ) {
155
+ if ( ! item || ! item . name || ! item . value || ! item . objectId ) {
129
156
return
130
157
}
131
158
return {
@@ -137,34 +164,6 @@ const sendSyncRecords = (sender, action, data) => {
137
164
} ) )
138
165
}
139
166
140
- /**
141
- * @param {Object } action
142
- * @returns {boolean }
143
- */
144
- const validateAction = ( action ) => {
145
- const SYNC_ACTIONS_WITHOUT_ITEMS = [
146
- syncConstants . SYNC_CLEAR_HISTORY ,
147
- syncConstants . SYNC_CLEAR_SITE_SETTINGS
148
- ]
149
- if ( SYNC_ACTIONS . includes ( action . actionType ) !== true ) {
150
- return false
151
- }
152
-
153
- // If the action requires an item, validate the item.
154
- if ( SYNC_ACTIONS_WITHOUT_ITEMS . includes ( action . actionType ) !== true ) {
155
- if ( ! action . item || ! action . item . toJS ) {
156
- log ( 'Missing item!' )
157
- return false
158
- }
159
- // Only accept items who have an objectId set already
160
- if ( ! action . item . get ( 'objectId' ) ) {
161
- log ( `Missing object ID! ${ action . item . toJS ( ) } ` )
162
- return false
163
- }
164
- }
165
- return true
166
- }
167
-
168
167
const dispatcherCallback = ( action ) => {
169
168
if ( ! backgroundSender ) {
170
169
return
@@ -176,14 +175,10 @@ const dispatcherCallback = (action) => {
176
175
}
177
176
}
178
177
// If sync is not enabled, the following actions should be ignored.
179
- if ( ! syncEnabled ( ) || validateAction ( action ) !== true || backgroundSender . isDestroyed ( ) ) {
178
+ if ( ! syncEnabled ( ) || backgroundSender . isDestroyed ( ) ) {
180
179
return
181
180
}
182
181
switch ( action . actionType ) {
183
- case syncConstants . SYNC_REMOVE_SITE :
184
- sendSyncRecords ( backgroundSender , writeActions . DELETE ,
185
- [ syncUtil . createSiteData ( action . item . toJS ( ) ) ] )
186
- break
187
182
case syncConstants . SYNC_CLEAR_HISTORY :
188
183
backgroundSender . send ( syncMessages . DELETE_SYNC_CATEGORY , CATEGORY_MAP . historySite . categoryName )
189
184
break
@@ -318,7 +313,6 @@ module.exports.init = function (appState) {
318
313
}
319
314
// sent by about:preferences when sync should be reloaded
320
315
ipcMain . on ( messages . RELOAD_SYNC_EXTENSION , ( ) => {
321
- console . log ( 'reloading sync' )
322
316
extensions . reloadExtension ( syncExtensionId )
323
317
} )
324
318
// sent by about:preferences when resetting sync
0 commit comments