mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	sync status widget
This commit is contained in:
		| @@ -12,9 +12,10 @@ const messageHandlers = []; | |||||||
|  |  | ||||||
| let ws; | let ws; | ||||||
| let lastAcceptedEntityChangeId = window.glob.maxEntityChangeIdAtLoad; | let lastAcceptedEntityChangeId = window.glob.maxEntityChangeIdAtLoad; | ||||||
|  | let lastAcceptedEntityChangeSyncId = window.glob.maxEntityChangeSyncIdAtLoad; | ||||||
| let lastProcessedEntityChangeId = window.glob.maxEntityChangeIdAtLoad; | let lastProcessedEntityChangeId = window.glob.maxEntityChangeIdAtLoad; | ||||||
| let lastPingTs; | let lastPingTs; | ||||||
| let syncDataQueue = []; | let frontendUpdateDataQueue = []; | ||||||
|  |  | ||||||
| function logError(message) { | function logError(message) { | ||||||
|     console.error(utils.now(), message); // needs to be separate from .trace() |     console.error(utils.now(), message); // needs to be separate from .trace() | ||||||
| @@ -34,7 +35,7 @@ function subscribeToMessages(messageHandler) { | |||||||
|     messageHandlers.push(messageHandler); |     messageHandlers.push(messageHandler); | ||||||
| } | } | ||||||
|  |  | ||||||
| // used to serialize sync operations | // used to serialize frontend update operations | ||||||
| let consumeQueuePromise = null; | let consumeQueuePromise = null; | ||||||
|  |  | ||||||
| // to make sure each change event is processed only once. Not clear if this is still necessary | // to make sure each change event is processed only once. Not clear if this is still necessary | ||||||
| @@ -46,7 +47,7 @@ function logRows(entityChanges) { | |||||||
|         && (row.entityName !== 'options' || row.entityId !== 'openTabs')); |         && (row.entityName !== 'options' || row.entityId !== 'openTabs')); | ||||||
|  |  | ||||||
|     if (filteredRows.length > 0) { |     if (filteredRows.length > 0) { | ||||||
|         console.debug(utils.now(), "Sync data: ", filteredRows); |         console.debug(utils.now(), "Frontend update data: ", filteredRows); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -57,17 +58,24 @@ async function handleMessage(event) { | |||||||
|         messageHandler(message); |         messageHandler(message); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (message.type === 'sync') { |     if (message.type === 'frontend-update') { | ||||||
|         let entityChanges = message.data; |         let {entityChanges, lastSyncedPush} = message.data; | ||||||
|         lastPingTs = Date.now(); |         lastPingTs = Date.now(); | ||||||
|  |  | ||||||
|         if (entityChanges.length > 0) { |         if (entityChanges.length > 0) { | ||||||
|             logRows(entityChanges); |             logRows(entityChanges); | ||||||
|  |  | ||||||
|             syncDataQueue.push(...entityChanges); |             frontendUpdateDataQueue.push(...entityChanges); | ||||||
|  |  | ||||||
|             // we set lastAcceptedEntityChangeId even before sync processing and send ping so that backend can start sending more updates |             // we set lastAcceptedEntityChangeId even before frontend update processing and send ping so that backend can start sending more updates | ||||||
|             lastAcceptedEntityChangeId = Math.max(lastAcceptedEntityChangeId, entityChanges[entityChanges.length - 1].id); |             lastAcceptedEntityChangeId = Math.max(lastAcceptedEntityChangeId, entityChanges[entityChanges.length - 1].id); | ||||||
|  |  | ||||||
|  |             const lastSyncEntityChange = entityChanges.slice().reverse().find(ec => ec.isSynced); | ||||||
|  |  | ||||||
|  |             if (lastSyncEntityChange) { | ||||||
|  |                 lastAcceptedEntityChangeSyncId = Math.max(lastAcceptedEntityChangeSyncId, lastSyncEntityChange.id); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             sendPing(); |             sendPing(); | ||||||
|  |  | ||||||
|             // first wait for all the preceding consumers to finish |             // first wait for all the preceding consumers to finish | ||||||
| @@ -77,7 +85,7 @@ async function handleMessage(event) { | |||||||
|  |  | ||||||
|             try { |             try { | ||||||
|                 // it's my turn so start it up |                 // it's my turn so start it up | ||||||
|                 consumeQueuePromise = consumeSyncData(); |                 consumeQueuePromise = consumeFrontendUpdateData(); | ||||||
|  |  | ||||||
|                 await consumeQueuePromise; |                 await consumeQueuePromise; | ||||||
|             } |             } | ||||||
| @@ -129,19 +137,10 @@ function checkEntityChangeIdListeners() { | |||||||
|         .forEach(l => console.log(`Waiting for entityChangeId ${l.desiredEntityChangeId} while last processed is ${lastProcessedEntityChangeId} (last accepted ${lastAcceptedEntityChangeId}) for ${Math.floor((Date.now() - l.start) / 1000)}s`)); |         .forEach(l => console.log(`Waiting for entityChangeId ${l.desiredEntityChangeId} while last processed is ${lastProcessedEntityChangeId} (last accepted ${lastAcceptedEntityChangeId}) for ${Math.floor((Date.now() - l.start) / 1000)}s`)); | ||||||
| } | } | ||||||
|  |  | ||||||
| async function runSafely(syncHandler, syncData) { | async function consumeFrontendUpdateData() { | ||||||
|     try { |     if (frontendUpdateDataQueue.length > 0) { | ||||||
|         return await syncHandler(syncData); |         const allEntityChanges = frontendUpdateDataQueue; | ||||||
|     } |         frontendUpdateDataQueue = []; | ||||||
|     catch (e) { |  | ||||||
|         console.log(`Sync handler failed with ${e.message}: ${e.stack}`); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function consumeSyncData() { |  | ||||||
|     if (syncDataQueue.length > 0) { |  | ||||||
|         const allEntityChanges = syncDataQueue; |  | ||||||
|         syncDataQueue = []; |  | ||||||
|  |  | ||||||
|         const nonProcessedEntityChanges = allEntityChanges.filter(ec => !processedEntityChangeIds.has(ec.id)); |         const nonProcessedEntityChanges = allEntityChanges.filter(ec => !processedEntityChangeIds.has(ec.id)); | ||||||
|  |  | ||||||
| @@ -213,30 +212,6 @@ setTimeout(() => { | |||||||
|     setInterval(sendPing, 1000); |     setInterval(sendPing, 1000); | ||||||
| }, 0); | }, 0); | ||||||
|  |  | ||||||
| subscribeToMessages(async message => { |  | ||||||
|     const appContext = (await import("./app_context.js")).default; |  | ||||||
|  |  | ||||||
|     if (message.type === 'sync-pull-in-progress') { |  | ||||||
|         toastService.showPersistent({ |  | ||||||
|             id: 'sync', |  | ||||||
|             title: "Sync status", |  | ||||||
|             message: "Sync update in progress", |  | ||||||
|             icon: "refresh" |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         appContext.triggerEvent('syncInProgress'); |  | ||||||
|     } |  | ||||||
|     else if (message.type === 'sync-finished') { |  | ||||||
|         // this gives user a chance to see the toast in case of fast sync finish |  | ||||||
|         setTimeout(() => toastService.closePersistent('sync'), 1000); |  | ||||||
|  |  | ||||||
|         appContext.triggerEvent('syncFinished'); |  | ||||||
|     } |  | ||||||
|     else if (message.type === 'sync-failed') { |  | ||||||
|         appContext.triggerEvent('syncFailed'); |  | ||||||
|     } |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| async function processEntityChanges(entityChanges) { | async function processEntityChanges(entityChanges) { | ||||||
|     const loadResults = new LoadResults(treeCache); |     const loadResults = new LoadResults(treeCache); | ||||||
|  |  | ||||||
| @@ -413,5 +388,6 @@ export default { | |||||||
|     logError, |     logError, | ||||||
|     subscribeToMessages, |     subscribeToMessages, | ||||||
|     waitForEntityChangeId, |     waitForEntityChangeId, | ||||||
|     waitForMaxKnownEntityChangeId |     waitForMaxKnownEntityChangeId, | ||||||
|  |     getMaxKnownEntityChangeSyncId: () => lastAcceptedEntityChangeSyncId | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| import BasicWidget from "./basic_widget.js"; | import BasicWidget from "./basic_widget.js"; | ||||||
| import utils from "../services/utils.js"; | import utils from "../services/utils.js"; | ||||||
| import syncService from "../services/sync.js"; |  | ||||||
|  |  | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="global-menu-wrapper"> | <div class="global-menu-wrapper"> | ||||||
| @@ -45,11 +44,6 @@ const TPL = ` | |||||||
|                 Options |                 Options | ||||||
|             </a> |             </a> | ||||||
|  |  | ||||||
|             <a class="dropdown-item sync-now-button" title="Trigger sync"> |  | ||||||
|                 <span class="bx bx-refresh"></span> |  | ||||||
|                 Sync now |  | ||||||
|             </a> |  | ||||||
|  |  | ||||||
|             <a class="dropdown-item" data-trigger-command="openNewWindow"> |             <a class="dropdown-item" data-trigger-command="openNewWindow"> | ||||||
|                 <span class="bx bx-window-open"></span> |                 <span class="bx bx-window-open"></span> | ||||||
|                 Open new window |                 Open new window | ||||||
| @@ -121,8 +115,6 @@ export default class GlobalMenuWidget extends BasicWidget { | |||||||
|         this.$widget.find(".show-about-dialog-button").on('click', |         this.$widget.find(".show-about-dialog-button").on('click', | ||||||
|             () => import("../dialogs/about.js").then(d => d.showDialog())); |             () => import("../dialogs/about.js").then(d => d.showDialog())); | ||||||
|  |  | ||||||
|         this.$widget.find(".sync-now-button").on('click', () => syncService.syncNow()); |  | ||||||
|  |  | ||||||
|         this.$widget.find(".logout-button").toggle(!utils.isElectron()); |         this.$widget.find(".logout-button").toggle(!utils.isElectron()); | ||||||
|  |  | ||||||
|         this.$widget.find(".open-dev-tools-button").toggle(utils.isElectron()); |         this.$widget.find(".open-dev-tools-button").toggle(utils.isElectron()); | ||||||
|   | |||||||
| @@ -1,9 +1,13 @@ | |||||||
| import BasicWidget from "./basic_widget.js"; | import BasicWidget from "./basic_widget.js"; | ||||||
|  | import toastService from "../services/toast.js"; | ||||||
|  | import ws from "../services/ws.js"; | ||||||
|  | import options from "../services/options.js"; | ||||||
|  | import syncService from "../services/sync.js"; | ||||||
|  |  | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="sync-status-wrapper"> | <div class="sync-status-widget"> | ||||||
|     <style> |     <style> | ||||||
|     .sync-status-wrapper { |     .sync-status-widget { | ||||||
|         height: 35px; |         height: 35px; | ||||||
|         box-sizing: border-box; |         box-sizing: border-box; | ||||||
|         border-bottom: 1px solid var(--main-border-color); |         border-bottom: 1px solid var(--main-border-color); | ||||||
| @@ -12,78 +16,127 @@ const TPL = ` | |||||||
|     .sync-status { |     .sync-status { | ||||||
|         height: 34px; |         height: 34px; | ||||||
|         box-sizing: border-box; |         box-sizing: border-box; | ||||||
|     } |  | ||||||
|      |  | ||||||
|     .sync-status button { |  | ||||||
|         height: 34px; |  | ||||||
|         border: none; |  | ||||||
|         font-size: 180%; |  | ||||||
|         padding-left: 10px; |         padding-left: 10px; | ||||||
|         padding-right: 10px; |         padding-right: 10px; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     .sync-status button > span { |     .sync-status .sync-status-icon { | ||||||
|  |         height: 34px; | ||||||
|  |         font-size: 180%; | ||||||
|         display: inline-block; |         display: inline-block; | ||||||
|         position: relative; |         position: relative; | ||||||
|         top: -5px; |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     .sync-status button:hover { |     .sync-status .sync-status-icon span { | ||||||
|  |         border: none !important; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     .sync-status-icon:not(.sync-status-in-progress):hover { | ||||||
|         background-color: var(--hover-item-background-color); |         background-color: var(--hover-item-background-color); | ||||||
|     } |         cursor: pointer; | ||||||
|      |  | ||||||
|     .sync-status .dropdown-menu { |  | ||||||
|         width: 20em; |  | ||||||
|     } |     } | ||||||
|     </style> |     </style> | ||||||
|  |  | ||||||
|     <div class="sync-status"> |     <div class="sync-status"> | ||||||
|         <button type="button" class="btn btn-sm" title="Sync status"> |         <span class="sync-status-icon sync-status-connected-with-changes" title="<p>Connected to the sync server. <br>There are some outstanding changes yet to be synced.</p><p>Click to trigger sync.</p>"> | ||||||
|             <span class="sync-status-icon sync-status-online-with-changes" title="Connected to the sync server. There are some outstanding changes yet to be synced."> |  | ||||||
|             <span class="bx bx-wifi"></span> |             <span class="bx bx-wifi"></span> | ||||||
|             <span class="bx bxs-star" style="font-size: 40%; position: absolute; left: -3px; top: 20px;"></span> |             <span class="bx bxs-star" style="font-size: 40%; position: absolute; left: -3px; top: 20px;"></span> | ||||||
|         </span> |         </span> | ||||||
|             <span class="sync-status-icon sync-status-online-no-changes" title="Connected to the sync server. All changes have been already synced."> |         <span class="sync-status-icon sync-status-connected-no-changes"  | ||||||
|  |               data-toggle="tooltip"  | ||||||
|  |               title="<p>Connected to the sync server.<br>All changes have been already synced.</p><p>Click to trigger sync.</p>"> | ||||||
|             <span class="bx bx-wifi"></span> |             <span class="bx bx-wifi"></span> | ||||||
|         </span> |         </span> | ||||||
|             <span class="sync-status-icon sync-status-offline-with-changes" title="Establishing the connection to the sync server was unsuccessful. There are some outstanding changes yet to be synced."> |         <span class="sync-status-icon sync-status-disconnected-with-changes" | ||||||
|  |               data-toggle="tooltip"  | ||||||
|  |               title="<p>Establishing the connection to the sync server was unsuccessful.<br>There are some outstanding changes yet to be synced.</p><p>Click to trigger sync.</p>"> | ||||||
|             <span class="bx bx-wifi-off"></span> |             <span class="bx bx-wifi-off"></span> | ||||||
|             <span class="bx bxs-star" style="font-size: 40%; position: absolute; left: -3px; top: 20px;"></span> |             <span class="bx bxs-star" style="font-size: 40%; position: absolute; left: -3px; top: 20px;"></span> | ||||||
|         </span> |         </span> | ||||||
|             <span class="sync-status-icon sync-status-offline-no-changes" title="Establishing the connection to the sync server was unsuccessful. All known changes have been synced."> |         <span class="sync-status-icon sync-status-disconnected-no-changes"  | ||||||
|  |               data-toggle="tooltip" | ||||||
|  |               title="<p>Establishing the connection to the sync server was unsuccessful.<br>All known changes have been synced.</p><p>Click to trigger sync.</p>"> | ||||||
|             <span class="bx bx-wifi-off"></span> |             <span class="bx bx-wifi-off"></span> | ||||||
|         </span> |         </span> | ||||||
|             <span class="sync-status-icon sync-status-in-progress" title="Sync with the server is in progress."> |         <span class="sync-status-icon sync-status-in-progress"  | ||||||
|  |               data-toggle="tooltip" | ||||||
|  |               title="Sync with the server is in progress."> | ||||||
|             <span class="bx bx-analyse bx-spin"></span> |             <span class="bx bx-analyse bx-spin"></span> | ||||||
|         </span> |         </span> | ||||||
|         </button> |  | ||||||
|     </div> |     </div> | ||||||
| </div> | </div> | ||||||
| `; | `; | ||||||
|  |  | ||||||
| export default class SyncStatusWidget extends BasicWidget { | export default class SyncStatusWidget extends BasicWidget { | ||||||
|  |     constructor() { | ||||||
|  |         super(); | ||||||
|  |  | ||||||
|  |         ws.subscribeToMessages(message => this.processMessage(message)); | ||||||
|  |  | ||||||
|  |         this.syncState = 'disconnected'; | ||||||
|  |         this.allChangesPushed = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
|         this.$widget.hide(); |         this.$widget.hide(); | ||||||
|  |  | ||||||
|  |         this.$widget.find('[data-toggle="tooltip"]').tooltip({ | ||||||
|  |             html: true | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         this.$widget.find('.sync-status-icon:not(.sync-status-in-progress)') | ||||||
|  |             .on('click', () => syncService.syncNow()) | ||||||
|  |  | ||||||
|         this.overflowing(); |         this.overflowing(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     syncInProgressEvent() { |  | ||||||
|         this.showIcon('in-progress'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     syncFinishedEvent() { |  | ||||||
|         this.showIcon('online-no-changes'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     syncFailedEvent() { |  | ||||||
|         this.showIcon('offline-no-changes'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     showIcon(className) { |     showIcon(className) { | ||||||
|  |         if (!options.get('syncServerHost')) { | ||||||
|  |             this.$widget.hide(); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         this.$widget.show(); |         this.$widget.show(); | ||||||
|         this.$widget.find('.sync-status-icon').hide(); |         this.$widget.find('.sync-status-icon').hide(); | ||||||
|         this.$widget.find('.sync-status-' + className).show(); |         this.$widget.find('.sync-status-' + className).show(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     processMessage(message) { | ||||||
|  |         if (message.type === 'sync-pull-in-progress') { | ||||||
|  |             toastService.showPersistent({ | ||||||
|  |                 id: 'sync', | ||||||
|  |                 title: "Sync status", | ||||||
|  |                 message: "Sync update in progress", | ||||||
|  |                 icon: "refresh" | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             this.syncState = 'in-progress'; | ||||||
|  |             this.allChangesPushed = false; | ||||||
|  |         } | ||||||
|  |         else if (message.type === 'sync-push-in-progress') { | ||||||
|  |             this.syncState = 'in-progress'; | ||||||
|  |             this.allChangesPushed = false; | ||||||
|  |         } | ||||||
|  |         else if (message.type === 'sync-finished') { | ||||||
|  |             // this gives user a chance to see the toast in case of fast sync finish | ||||||
|  |             setTimeout(() => toastService.closePersistent('sync'), 1000); | ||||||
|  |  | ||||||
|  |             this.syncState = 'connected'; | ||||||
|  |         } | ||||||
|  |         else if (message.type === 'sync-failed') { | ||||||
|  |             this.syncState = 'disconnected'; | ||||||
|  |         } | ||||||
|  |         else if (message.type === 'frontend-update') { | ||||||
|  |             const {lastSyncedPush} = message.data; | ||||||
|  |  | ||||||
|  |             this.allChangesPushed = lastSyncedPush === ws.getMaxKnownEntityChangeSyncId(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.syncState === 'in-progress') { | ||||||
|  |             this.showIcon('in-progress'); | ||||||
|  |         } else { | ||||||
|  |             this.showIcon(this.syncState + '-' + (this.allChangesPushed ? 'no-changes' : 'with-changes')); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ function index(req, res) { | |||||||
|         detailFontSize: parseInt(options.detailFontSize), |         detailFontSize: parseInt(options.detailFontSize), | ||||||
|         sourceId: sourceIdService.generateSourceId(), |         sourceId: sourceIdService.generateSourceId(), | ||||||
|         maxEntityChangeIdAtLoad: sql.getValue("SELECT COALESCE(MAX(id), 0) FROM entity_changes"), |         maxEntityChangeIdAtLoad: sql.getValue("SELECT COALESCE(MAX(id), 0) FROM entity_changes"), | ||||||
|  |         maxEntityChangeSyncIdAtLoad: sql.getValue("SELECT COALESCE(MAX(id), 0) FROM entity_changes WHERE isSynced = 1"), | ||||||
|         instanceName: config.General ? config.General.instanceName : null, |         instanceName: config.General ? config.General.instanceName : null, | ||||||
|         appCssNoteIds: getAppCssNoteIds(), |         appCssNoteIds: getAppCssNoteIds(), | ||||||
|         isDev: env.isDev(), |         isDev: env.isDev(), | ||||||
|   | |||||||
| @@ -234,7 +234,7 @@ function transactional(func) { | |||||||
|         const ret = dbConnection.transaction(func).deferred(); |         const ret = dbConnection.transaction(func).deferred(); | ||||||
|  |  | ||||||
|         if (!dbConnection.inTransaction) { // i.e. transaction was really committed (and not just savepoint released) |         if (!dbConnection.inTransaction) { // i.e. transaction was really committed (and not just savepoint released) | ||||||
|             require('./ws.js').sendTransactionSyncsToAllClients(); |             require('./ws.js').sendTransactionEntityChangesToAllClients(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return ret; |         return ret; | ||||||
|   | |||||||
| @@ -363,10 +363,16 @@ function setLastSyncedPull(entityChangeId) { | |||||||
| } | } | ||||||
|  |  | ||||||
| function getLastSyncedPush() { | function getLastSyncedPush() { | ||||||
|     return parseInt(optionService.getOption('lastSyncedPush')); |     const lastSyncedPush = parseInt(optionService.getOption('lastSyncedPush')); | ||||||
|  |  | ||||||
|  |     ws.setLastSyncedPush(lastSyncedPush); | ||||||
|  |  | ||||||
|  |     return lastSyncedPush; | ||||||
| } | } | ||||||
|  |  | ||||||
| function setLastSyncedPush(entityChangeId) { | function setLastSyncedPush(entityChangeId) { | ||||||
|  |     ws.setLastSyncedPush(entityChangeId); | ||||||
|  |  | ||||||
|     optionService.setOption('lastSyncedPush', entityChangeId); |     optionService.setOption('lastSyncedPush', entityChangeId); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -382,9 +388,12 @@ sqlInit.dbReady.then(() => { | |||||||
|     setInterval(cls.wrap(sync), 60000); |     setInterval(cls.wrap(sync), 60000); | ||||||
|  |  | ||||||
|     // kickoff initial sync immediately |     // kickoff initial sync immediately | ||||||
|     setTimeout(cls.wrap(sync), 3000); |     setTimeout(cls.wrap(sync), 5000); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | // called just so ws.setLastSyncedPush() is called | ||||||
|  | getLastSyncedPush(); | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     sync, |     sync, | ||||||
|     login, |     login, | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ const syncMutexService = require('./sync_mutex'); | |||||||
| const protectedSessionService = require('./protected_session'); | const protectedSessionService = require('./protected_session'); | ||||||
|  |  | ||||||
| let webSocketServer; | let webSocketServer; | ||||||
|  | let lastSyncedPush = null; | ||||||
|  |  | ||||||
| function init(httpServer, sessionParser) { | function init(httpServer, sessionParser) { | ||||||
|     webSocketServer = new WebSocket.Server({ |     webSocketServer = new WebSocket.Server({ | ||||||
| @@ -61,7 +62,9 @@ function sendMessageToAllClients(message) { | |||||||
|     const jsonStr = JSON.stringify(message); |     const jsonStr = JSON.stringify(message); | ||||||
|  |  | ||||||
|     if (webSocketServer) { |     if (webSocketServer) { | ||||||
|  |         if (message.type !== 'sync-failed') { | ||||||
|             log.info("Sending message to all clients: " + jsonStr); |             log.info("Sending message to all clients: " + jsonStr); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         webSocketServer.clients.forEach(function each(client) { |         webSocketServer.clients.forEach(function each(client) { | ||||||
|             if (client.readyState === WebSocket.OPEN) { |             if (client.readyState === WebSocket.OPEN) { | ||||||
| @@ -96,23 +99,26 @@ function fillInAdditionalProperties(entityChange) { | |||||||
| } | } | ||||||
|  |  | ||||||
| function sendPing(client, entityChanges = []) { | function sendPing(client, entityChanges = []) { | ||||||
|     for (const sync of entityChanges) { |     for (const entityChange of entityChanges) { | ||||||
|         try { |         try { | ||||||
|             fillInAdditionalProperties(sync); |             fillInAdditionalProperties(entityChange); | ||||||
|         } |         } | ||||||
|         catch (e) { |         catch (e) { | ||||||
|             log.error("Could not fill additional properties for sync " + JSON.stringify(sync) |             log.error("Could not fill additional properties for entity change " + JSON.stringify(entityChange) | ||||||
|                 + " because of error: " + e.message + ": " + e.stack); |                 + " because of error: " + e.message + ": " + e.stack); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     sendMessage(client, { |     sendMessage(client, { | ||||||
|         type: 'sync', |         type: 'frontend-update', | ||||||
|         data: entityChanges |         data: { | ||||||
|  |             lastSyncedPush, | ||||||
|  |             entityChanges | ||||||
|  |         } | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| function sendTransactionSyncsToAllClients() { | function sendTransactionEntityChangesToAllClients() { | ||||||
|     if (webSocketServer) { |     if (webSocketServer) { | ||||||
|         const entityChanges = cls.getAndClearEntityChanges(); |         const entityChanges = cls.getAndClearEntityChanges(); | ||||||
|  |  | ||||||
| @@ -136,6 +142,10 @@ function syncFailed() { | |||||||
|     sendMessageToAllClients({ type: 'sync-failed' }); |     sendMessageToAllClients({ type: 'sync-failed' }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function setLastSyncedPush(entityChangeId) { | ||||||
|  |     lastSyncedPush = entityChangeId; | ||||||
|  | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     init, |     init, | ||||||
|     sendMessageToAllClients, |     sendMessageToAllClients, | ||||||
| @@ -143,5 +153,6 @@ module.exports = { | |||||||
|     syncPullInProgress, |     syncPullInProgress, | ||||||
|     syncFinished, |     syncFinished, | ||||||
|     syncFailed, |     syncFailed, | ||||||
|     sendTransactionSyncsToAllClients |     sendTransactionEntityChangesToAllClients, | ||||||
|  |     setLastSyncedPush | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -49,6 +49,7 @@ | |||||||
|         activeDialog: null, |         activeDialog: null, | ||||||
|         sourceId: '<%= sourceId %>', |         sourceId: '<%= sourceId %>', | ||||||
|         maxEntityChangeIdAtLoad: <%= maxEntityChangeIdAtLoad %>, |         maxEntityChangeIdAtLoad: <%= maxEntityChangeIdAtLoad %>, | ||||||
|  |         maxEntityChangeSyncIdAtLoad: <%= maxEntityChangeSyncIdAtLoad %>, | ||||||
|         instanceName: '<%= instanceName %>', |         instanceName: '<%= instanceName %>', | ||||||
|         csrfToken: '<%= csrfToken %>', |         csrfToken: '<%= csrfToken %>', | ||||||
|         isDev: <%= isDev %>, |         isDev: <%= isDev %>, | ||||||
|   | |||||||
| @@ -111,6 +111,7 @@ | |||||||
|         activeDialog: null, |         activeDialog: null, | ||||||
|         sourceId: '<%= sourceId %>', |         sourceId: '<%= sourceId %>', | ||||||
|         maxEntityChangeIdAtLoad: <%= maxEntityChangeIdAtLoad %>, |         maxEntityChangeIdAtLoad: <%= maxEntityChangeIdAtLoad %>, | ||||||
|  |         maxEntityChangeSyncIdAtLoad: <%= maxEntityChangeSyncIdAtLoad %>, | ||||||
|         instanceName: '<%= instanceName %>', |         instanceName: '<%= instanceName %>', | ||||||
|         csrfToken: '<%= csrfToken %>', |         csrfToken: '<%= csrfToken %>', | ||||||
|         isDev: <%= isDev %>, |         isDev: <%= isDev %>, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user