From 18dc84b951ac786529ba3ad5cbc82a0d4471943b Mon Sep 17 00:00:00 2001 From: dblythy Date: Tue, 20 Oct 2020 13:27:51 +1100 Subject: [PATCH 1/9] LiveQueryEvent Improvements --- spec/ParseLiveQuery.spec.js | 10 ++------ src/LiveQuery/ParseLiveQueryServer.js | 35 +++++++++++++++++++++++---- src/cloud-code/Parse.Cloud.js | 1 + 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/spec/ParseLiveQuery.spec.js b/spec/ParseLiveQuery.spec.js index 496f9fb922..de3d974692 100644 --- a/spec/ParseLiveQuery.spec.js +++ b/spec/ParseLiveQuery.spec.js @@ -232,7 +232,7 @@ describe('ParseLiveQuery', function () { await object.save(); }); - it('can handle afterEvent throw', async done => { + it('can handle afterEvent sendEvent to false', async done => { await reconfigureServer({ liveQuery: { classNames: ['TestObject'], @@ -246,16 +246,10 @@ describe('ParseLiveQuery', function () { await object.save(); Parse.Cloud.afterLiveQueryEvent('TestObject', req => { - const current = req.object; - const original = req.original; - setTimeout(() => { done(); }, 2000); - - if (current.get('foo') != original.get('foo')) { - throw "Don't pass an update trigger, or message"; - } + req.sendEvent = false; }); const query = new Parse.Query(TestObject); diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index e535480a71..a58b1b96d1 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -160,6 +160,7 @@ class ParseLiveQueryServer { // Check CLP const op = this._getCLPOperation(subscription.query); let res = {}; + let aclError = true; this._matchesCLP( classLevelPermissions, message.currentParseObject, @@ -175,6 +176,7 @@ class ParseLiveQueryServer { if (!isMatched) { return null; } + aclError = false; res = { event: 'Delete', sessionToken: client.sessionToken, @@ -182,11 +184,15 @@ class ParseLiveQueryServer { clients: this.clients.size, subscriptions: this.subscriptions.size, useMasterKey: client.hasMasterKey, - installationId: client.installationId + installationId: client.installationId, + sendEvent: false, }; return maybeRunAfterEventTrigger('afterEvent', className, res); }) .then(() => { + if (!res.sendEvent) { + return; + } if (res.object && typeof res.object.toJSON === 'function') { deletedParseObject = res.object.toJSON(); deletedParseObject.className = className; @@ -194,7 +200,14 @@ class ParseLiveQueryServer { client.pushDelete(requestId, deletedParseObject); }) .catch(error => { - logger.error('Matching ACL error : ', error); + if (aclError) { + logger.error('Matching ACL error : ', error); + } else { + logger.error( + `Failed running afterLiveQueryEvent for event ${res.event} session ${res.sessionToken} with:\n Error: ` + + JSON.stringify(error) + ); + } }); } } @@ -262,6 +275,7 @@ class ParseLiveQueryServer { // subscription, we do not need to check ACL let currentACLCheckingPromise; let res = {}; + let aclError = true; if (!isCurrentSubscriptionMatched) { currentACLCheckingPromise = Promise.resolve(false); } else { @@ -297,7 +311,7 @@ class ParseLiveQueryServer { isCurrentMatched, subscription.hash ); - + aclError = false; // Decide event type let type; if (isOriginalMatched && isCurrentMatched) { @@ -322,12 +336,16 @@ class ParseLiveQueryServer { clients: this.clients.size, subscriptions: this.subscriptions.size, useMasterKey: client.hasMasterKey, - installationId: client.installationId + installationId: client.installationId, + sendEvent: true, }; return maybeRunAfterEventTrigger('afterEvent', className, res); }) .then( () => { + if (!res.sendEvent) { + return; + } if (res.object && typeof res.object.toJSON === 'function') { currentParseObject = res.object.toJSON(); currentParseObject.className = @@ -349,7 +367,14 @@ class ParseLiveQueryServer { } }, error => { - logger.error('Matching ACL error : ', error); + if (aclError) { + logger.error('Matching ACL error : ', error); + } else { + logger.error( + `Failed running afterLiveQueryEvent for event ${res.event} session ${res.sessionToken} with:\n Error: ` + + JSON.stringify(error) + ); + } } ); } diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index c3f0536c2b..01d1569bc1 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -600,6 +600,7 @@ module.exports = ParseCloud; * @property {Parse.Object} original If set, the object, as currently stored. * @property {Integer} clients The number of clients connected. * @property {Integer} subscriptions The number of subscriptions connected. + * @property {Boolean} sendEvent If the LiveQuery event should be sent to the client. Set to false to prevent LiveQuery from pushing to the client. */ /** From a76b7f022348322a83d1b7ed03e585dca50847b3 Mon Sep 17 00:00:00 2001 From: dblythy Date: Tue, 20 Oct 2020 13:32:58 +1100 Subject: [PATCH 2/9] Update ParseLiveQueryServer.js --- src/LiveQuery/ParseLiveQueryServer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index a58b1b96d1..b56a1ee9e6 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -204,7 +204,7 @@ class ParseLiveQueryServer { logger.error('Matching ACL error : ', error); } else { logger.error( - `Failed running afterLiveQueryEvent for event ${res.event} session ${res.sessionToken} with:\n Error: ` + + `Failed running afterLiveQueryEvent for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + JSON.stringify(error) ); } @@ -370,8 +370,8 @@ class ParseLiveQueryServer { if (aclError) { logger.error('Matching ACL error : ', error); } else { - logger.error( - `Failed running afterLiveQueryEvent for event ${res.event} session ${res.sessionToken} with:\n Error: ` + + logger.log( + `Failed running afterLiveQueryEvent for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + JSON.stringify(error) ); } From 968de7d5bef0f5aec0e9bc129d643bb6e9bb60f3 Mon Sep 17 00:00:00 2001 From: dblythy Date: Tue, 20 Oct 2020 13:55:01 +1100 Subject: [PATCH 3/9] Update ParseLiveQueryServer.js --- src/LiveQuery/ParseLiveQueryServer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index b56a1ee9e6..2e88341311 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -185,7 +185,7 @@ class ParseLiveQueryServer { subscriptions: this.subscriptions.size, useMasterKey: client.hasMasterKey, installationId: client.installationId, - sendEvent: false, + sendEvent: true, }; return maybeRunAfterEventTrigger('afterEvent', className, res); }) From 2510b66236e7563f92bfbdb78e66be0490cffc9c Mon Sep 17 00:00:00 2001 From: dblythy Date: Tue, 20 Oct 2020 14:07:10 +1100 Subject: [PATCH 4/9] More Tests --- spec/ParseLiveQuery.spec.js | 40 ++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/spec/ParseLiveQuery.spec.js b/spec/ParseLiveQuery.spec.js index de3d974692..9840b4f41b 100644 --- a/spec/ParseLiveQuery.spec.js +++ b/spec/ParseLiveQuery.spec.js @@ -231,6 +231,38 @@ describe('ParseLiveQuery', function () { object.set({ foo: 'bar' }); await object.save(); }); + it('can handle afterEvent throw', async done => { + await reconfigureServer({ + liveQuery: { + classNames: ['TestObject'], + }, + startLiveQueryServer: true, + verbose: false, + silent: true, + }); + + const object = new TestObject(); + await object.save(); + + Parse.Cloud.afterLiveQueryEvent('TestObject', () => { + setTimeout(() => { + done(); + }, 2000); + throw 'Error.'; + }); + + const query = new Parse.Query(TestObject); + query.equalTo('objectId', object.id); + const subscription = await query.subscribe(); + subscription.on('update', () => { + fail('update should not have been called.'); + }); + subscription.on('error', () => { + fail('error should not have been called.'); + }); + object.set({ foo: 'bar' }); + await object.save(); + }); it('can handle afterEvent sendEvent to false', async done => { await reconfigureServer({ @@ -246,10 +278,16 @@ describe('ParseLiveQuery', function () { await object.save(); Parse.Cloud.afterLiveQueryEvent('TestObject', req => { + const current = req.object; + const original = req.original; + setTimeout(() => { done(); }, 2000); - req.sendEvent = false; + + if (current.get('foo') != original.get('foo')) { + req.sendEvent = false; + } }); const query = new Parse.Query(TestObject); From fae8223c701b49263809d3fd433daf1377e1c68b Mon Sep 17 00:00:00 2001 From: dblythy Date: Tue, 20 Oct 2020 14:19:33 +1100 Subject: [PATCH 5/9] Update ParseLiveQueryServer.js --- src/LiveQuery/ParseLiveQueryServer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 2e88341311..63d8d733a4 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -370,7 +370,7 @@ class ParseLiveQueryServer { if (aclError) { logger.error('Matching ACL error : ', error); } else { - logger.log( + logger.error( `Failed running afterLiveQueryEvent for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + JSON.stringify(error) ); From fe2812d5c6b683695939a9a4bb9bab992a97b6cb Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 21 Oct 2020 11:52:31 +1100 Subject: [PATCH 6/9] Pass thrown errors to subscription --- spec/ParseLiveQuery.spec.js | 10 ++++------ src/LiveQuery/ParseLiveQueryServer.js | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/spec/ParseLiveQuery.spec.js b/spec/ParseLiveQuery.spec.js index 9840b4f41b..8192597aa0 100644 --- a/spec/ParseLiveQuery.spec.js +++ b/spec/ParseLiveQuery.spec.js @@ -245,10 +245,7 @@ describe('ParseLiveQuery', function () { await object.save(); Parse.Cloud.afterLiveQueryEvent('TestObject', () => { - setTimeout(() => { - done(); - }, 2000); - throw 'Error.'; + throw 'Throw error from LQ afterEvent.'; }); const query = new Parse.Query(TestObject); @@ -257,8 +254,9 @@ describe('ParseLiveQuery', function () { subscription.on('update', () => { fail('update should not have been called.'); }); - subscription.on('error', () => { - fail('error should not have been called.'); + subscription.on('error', e => { + expect(e).toBe('Throw error from LQ afterEvent.'); + done(); }); object.set({ foo: 'bar' }); await object.save(); diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 63d8d733a4..fdf0ba1d9c 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -203,6 +203,13 @@ class ParseLiveQueryServer { if (aclError) { logger.error('Matching ACL error : ', error); } else { + Client.pushError( + client.parseWebSocket, + error.code || 101, + error.message || error, + false, + requestId + ); logger.error( `Failed running afterLiveQueryEvent for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + JSON.stringify(error) @@ -370,6 +377,13 @@ class ParseLiveQueryServer { if (aclError) { logger.error('Matching ACL error : ', error); } else { + Client.pushError( + client.parseWebSocket, + error.code || 101, + error.message || error, + false, + requestId + ); logger.error( `Failed running afterLiveQueryEvent for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + JSON.stringify(error) From c2368cde05da0ba2c1e562d6024801ae0479f564 Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 21 Oct 2020 12:25:04 +1100 Subject: [PATCH 7/9] Update ParseLiveQueryServer.js --- src/LiveQuery/ParseLiveQueryServer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index fdf0ba1d9c..07b82161c3 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -211,7 +211,7 @@ class ParseLiveQueryServer { requestId ); logger.error( - `Failed running afterLiveQueryEvent for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + + `Failed running afterLiveQueryEvent on class ${className} for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + JSON.stringify(error) ); } @@ -385,7 +385,7 @@ class ParseLiveQueryServer { requestId ); logger.error( - `Failed running afterLiveQueryEvent for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + + `Failed running afterLiveQueryEvent on class ${className} for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + JSON.stringify(error) ); } From 9b0faceb0df37f1e5dbbe8bb4e1f6a8b9d49be9e Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 21 Oct 2020 17:30:52 +1100 Subject: [PATCH 8/9] Update ParseLiveQueryServer.js --- src/LiveQuery/ParseLiveQueryServer.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 07b82161c3..38a9b81972 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -160,7 +160,6 @@ class ParseLiveQueryServer { // Check CLP const op = this._getCLPOperation(subscription.query); let res = {}; - let aclError = true; this._matchesCLP( classLevelPermissions, message.currentParseObject, @@ -176,7 +175,6 @@ class ParseLiveQueryServer { if (!isMatched) { return null; } - aclError = false; res = { event: 'Delete', sessionToken: client.sessionToken, @@ -200,12 +198,15 @@ class ParseLiveQueryServer { client.pushDelete(requestId, deletedParseObject); }) .catch(error => { - if (aclError) { + if ( + error.code == Parse.Error.OBJECT_NOT_FOUND || + error.code == Parse.Error.OPERATION_FORBIDDEN + ) { logger.error('Matching ACL error : ', error); } else { Client.pushError( client.parseWebSocket, - error.code || 101, + error.code || 141, error.message || error, false, requestId @@ -282,7 +283,6 @@ class ParseLiveQueryServer { // subscription, we do not need to check ACL let currentACLCheckingPromise; let res = {}; - let aclError = true; if (!isCurrentSubscriptionMatched) { currentACLCheckingPromise = Promise.resolve(false); } else { @@ -318,7 +318,6 @@ class ParseLiveQueryServer { isCurrentMatched, subscription.hash ); - aclError = false; // Decide event type let type; if (isOriginalMatched && isCurrentMatched) { @@ -374,12 +373,15 @@ class ParseLiveQueryServer { } }, error => { - if (aclError) { + if ( + error.code == Parse.Error.OBJECT_NOT_FOUND || + error.code == Parse.Error.OPERATION_FORBIDDEN + ) { logger.error('Matching ACL error : ', error); } else { Client.pushError( client.parseWebSocket, - error.code || 101, + error.code || 141, error.message || error, false, requestId @@ -697,7 +699,7 @@ class ParseLiveQueryServer { } catch (error) { Client.pushError( parseWebsocket, - error.code || 101, + error.code || 141, error.message || error, false ); @@ -815,7 +817,7 @@ class ParseLiveQueryServer { } catch (e) { Client.pushError( parseWebsocket, - e.code || 101, + e.code || 141, e.message || e, false, request.requestId From d51a3f52449b1b08b594d329dc882e57dd52b65d Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 21 Oct 2020 17:47:14 +1100 Subject: [PATCH 9/9] Remove ACL error --- src/LiveQuery/ParseLiveQueryServer.js | 58 ++++++++++----------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/src/LiveQuery/ParseLiveQueryServer.js b/src/LiveQuery/ParseLiveQueryServer.js index 38a9b81972..f0d0db19a4 100644 --- a/src/LiveQuery/ParseLiveQueryServer.js +++ b/src/LiveQuery/ParseLiveQueryServer.js @@ -198,24 +198,17 @@ class ParseLiveQueryServer { client.pushDelete(requestId, deletedParseObject); }) .catch(error => { - if ( - error.code == Parse.Error.OBJECT_NOT_FOUND || - error.code == Parse.Error.OPERATION_FORBIDDEN - ) { - logger.error('Matching ACL error : ', error); - } else { - Client.pushError( - client.parseWebSocket, - error.code || 141, - error.message || error, - false, - requestId - ); - logger.error( - `Failed running afterLiveQueryEvent on class ${className} for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + - JSON.stringify(error) - ); - } + Client.pushError( + client.parseWebSocket, + error.code || 141, + error.message || error, + false, + requestId + ); + logger.error( + `Failed running afterLiveQueryEvent on class ${className} for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + + JSON.stringify(error) + ); }); } } @@ -373,24 +366,17 @@ class ParseLiveQueryServer { } }, error => { - if ( - error.code == Parse.Error.OBJECT_NOT_FOUND || - error.code == Parse.Error.OPERATION_FORBIDDEN - ) { - logger.error('Matching ACL error : ', error); - } else { - Client.pushError( - client.parseWebSocket, - error.code || 141, - error.message || error, - false, - requestId - ); - logger.error( - `Failed running afterLiveQueryEvent on class ${className} for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + - JSON.stringify(error) - ); - } + Client.pushError( + client.parseWebSocket, + error.code || 141, + error.message || error, + false, + requestId + ); + logger.error( + `Failed running afterLiveQueryEvent on class ${className} for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + + JSON.stringify(error) + ); } ); }