@@ -10,12 +10,7 @@ import { ParsePubSub } from './ParsePubSub';
10
10
import SchemaController from '../Controllers/SchemaController' ;
11
11
import _ from 'lodash' ;
12
12
import { v4 as uuidv4 } from 'uuid' ;
13
- import {
14
- runLiveQueryEventHandlers ,
15
- maybeRunConnectTrigger ,
16
- maybeRunSubscribeTrigger ,
17
- maybeRunAfterEventTrigger ,
18
- } from '../triggers' ;
13
+ import { runLiveQueryEventHandlers , getTrigger , runTrigger } from '../triggers' ;
19
14
import { getAuthForSessionToken , Auth } from '../Auth' ;
20
15
import { getCacheController } from '../Controllers' ;
21
16
import LRU from 'lru-cache' ;
@@ -121,7 +116,7 @@ class ParseLiveQueryServer {
121
116
122
117
// Message is the JSON object from publisher after inflated. Message.currentParseObject is the ParseObject after changes.
123
118
// Message.originalParseObject is the original ParseObject.
124
- _onAfterDelete ( message : any ) : void {
119
+ async _onAfterDelete ( message : any ) : void {
125
120
logger . verbose ( Parse . applicationId + 'afterDelete is triggered' ) ;
126
121
127
122
let deletedParseObject = message . currentParseObject . toJSON ( ) ;
@@ -135,6 +130,7 @@ class ParseLiveQueryServer {
135
130
logger . debug ( 'Can not find subscriptions under this class ' + className ) ;
136
131
return ;
137
132
}
133
+
138
134
for ( const subscription of classSubscriptions . values ( ) ) {
139
135
const isSubscriptionMatched = this . _matchesSubscription ( deletedParseObject , subscription ) ;
140
136
if ( ! isSubscriptionMatched ) {
@@ -150,58 +146,66 @@ class ParseLiveQueryServer {
150
146
// Check CLP
151
147
const op = this . _getCLPOperation ( subscription . query ) ;
152
148
let res = { } ;
153
- this . _matchesCLP ( classLevelPermissions , message . currentParseObject , client , requestId , op )
154
- . then ( ( ) => {
155
- // Check ACL
156
- return this . _matchesACL ( acl , client , requestId ) ;
157
- } )
158
- . then ( isMatched => {
159
- if ( ! isMatched ) {
160
- return null ;
161
- }
162
- res = {
163
- event : 'delete' ,
164
- sessionToken : client . sessionToken ,
165
- object : deletedParseObject ,
166
- clients : this . clients . size ,
167
- subscriptions : this . subscriptions . size ,
168
- useMasterKey : client . hasMasterKey ,
169
- installationId : client . installationId ,
170
- sendEvent : true ,
171
- } ;
172
- return maybeRunAfterEventTrigger ( 'afterEvent' , className , res ) ;
173
- } )
174
- . then ( ( ) => {
175
- if ( ! res . sendEvent ) {
176
- return ;
177
- }
178
- if ( res . object && typeof res . object . toJSON === 'function' ) {
179
- deletedParseObject = res . object . toJSON ( ) ;
180
- deletedParseObject . className = className ;
149
+ try {
150
+ await this . _matchesCLP (
151
+ classLevelPermissions ,
152
+ message . currentParseObject ,
153
+ client ,
154
+ requestId ,
155
+ op
156
+ ) ;
157
+ const isMatched = await this . _matchesACL ( acl , client , requestId ) ;
158
+ if ( ! isMatched ) {
159
+ return null ;
160
+ }
161
+ res = {
162
+ event : 'delete' ,
163
+ sessionToken : client . sessionToken ,
164
+ object : deletedParseObject ,
165
+ clients : this . clients . size ,
166
+ subscriptions : this . subscriptions . size ,
167
+ useMasterKey : client . hasMasterKey ,
168
+ installationId : client . installationId ,
169
+ sendEvent : true ,
170
+ } ;
171
+ const trigger = getTrigger ( className , 'afterEvent' , Parse . applicationId ) ;
172
+ if ( trigger ) {
173
+ const auth = await this . getAuthForSessionToken ( res . sessionToken ) ;
174
+ res . user = auth . user ;
175
+ if ( res . object ) {
176
+ res . object = Parse . Object . fromJSON ( res . object ) ;
181
177
}
182
- client . pushDelete ( requestId , deletedParseObject ) ;
183
- } )
184
- . catch ( error => {
185
- Client . pushError (
186
- client . parseWebSocket ,
187
- error . code || 141 ,
188
- error . message || error ,
189
- false ,
190
- requestId
191
- ) ;
192
- logger . error (
193
- `Failed running afterLiveQueryEvent on class ${ className } for event ${ res . event } with session ${ res . sessionToken } with:\n Error: ` +
194
- JSON . stringify ( error )
195
- ) ;
196
- } ) ;
178
+ await runTrigger ( trigger , `afterEvent.${ className } ` , res , auth ) ;
179
+ }
180
+ if ( ! res . sendEvent ) {
181
+ return ;
182
+ }
183
+ if ( res . object && typeof res . object . toJSON === 'function' ) {
184
+ deletedParseObject = res . object . toJSON ( ) ;
185
+ deletedParseObject . className = className ;
186
+ }
187
+ client . pushDelete ( requestId , deletedParseObject ) ;
188
+ } catch ( error ) {
189
+ Client . pushError (
190
+ client . parseWebSocket ,
191
+ error . code || 141 ,
192
+ error . message || error ,
193
+ false ,
194
+ requestId
195
+ ) ;
196
+ logger . error (
197
+ `Failed running afterLiveQueryEvent on class ${ className } for event ${ res . event } with session ${ res . sessionToken } with:\n Error: ` +
198
+ JSON . stringify ( error )
199
+ ) ;
200
+ }
197
201
}
198
202
}
199
203
}
200
204
}
201
205
202
206
// Message is the JSON object from publisher after inflated. Message.currentParseObject is the ParseObject after changes.
203
207
// Message.originalParseObject is the original ParseObject.
204
- _onAfterSave ( message : any ) : void {
208
+ async _onAfterSave ( message : any ) : void {
205
209
logger . verbose ( Parse . applicationId + 'afterSave is triggered' ) ;
206
210
207
211
let originalParseObject = null ;
@@ -256,85 +260,98 @@ class ParseLiveQueryServer {
256
260
const currentACL = message . currentParseObject . getACL ( ) ;
257
261
currentACLCheckingPromise = this . _matchesACL ( currentACL , client , requestId ) ;
258
262
}
259
- const op = this . _getCLPOperation ( subscription . query ) ;
260
- this . _matchesCLP ( classLevelPermissions , message . currentParseObject , client , requestId , op )
261
- . then ( ( ) => {
262
- return Promise . all ( [ originalACLCheckingPromise , currentACLCheckingPromise ] ) ;
263
- } )
264
- . then ( ( [ isOriginalMatched , isCurrentMatched ] ) => {
265
- logger . verbose (
266
- 'Original %j | Current %j | Match: %s, %s, %s, %s | Query: %s' ,
267
- originalParseObject ,
268
- currentParseObject ,
269
- isOriginalSubscriptionMatched ,
270
- isCurrentSubscriptionMatched ,
271
- isOriginalMatched ,
272
- isCurrentMatched ,
273
- subscription . hash
274
- ) ;
275
- // Decide event type
276
- let type ;
277
- if ( isOriginalMatched && isCurrentMatched ) {
278
- type = 'update' ;
279
- } else if ( isOriginalMatched && ! isCurrentMatched ) {
280
- type = 'leave' ;
281
- } else if ( ! isOriginalMatched && isCurrentMatched ) {
282
- if ( originalParseObject ) {
283
- type = 'enter' ;
284
- } else {
285
- type = 'create' ;
286
- }
263
+ try {
264
+ const op = this . _getCLPOperation ( subscription . query ) ;
265
+ await this . _matchesCLP (
266
+ classLevelPermissions ,
267
+ message . currentParseObject ,
268
+ client ,
269
+ requestId ,
270
+ op
271
+ ) ;
272
+ const [ isOriginalMatched , isCurrentMatched ] = await Promise . all ( [
273
+ originalACLCheckingPromise ,
274
+ currentACLCheckingPromise ,
275
+ ] ) ;
276
+ logger . verbose (
277
+ 'Original %j | Current %j | Match: %s, %s, %s, %s | Query: %s' ,
278
+ originalParseObject ,
279
+ currentParseObject ,
280
+ isOriginalSubscriptionMatched ,
281
+ isCurrentSubscriptionMatched ,
282
+ isOriginalMatched ,
283
+ isCurrentMatched ,
284
+ subscription . hash
285
+ ) ;
286
+ // Decide event type
287
+ let type ;
288
+ if ( isOriginalMatched && isCurrentMatched ) {
289
+ type = 'update' ;
290
+ } else if ( isOriginalMatched && ! isCurrentMatched ) {
291
+ type = 'leave' ;
292
+ } else if ( ! isOriginalMatched && isCurrentMatched ) {
293
+ if ( originalParseObject ) {
294
+ type = 'enter' ;
287
295
} else {
288
- return null ;
296
+ type = 'create' ;
289
297
}
290
- message . event = type ;
291
- res = {
292
- event : type ,
293
- sessionToken : client . sessionToken ,
294
- object : currentParseObject ,
295
- original : originalParseObject ,
296
- clients : this . clients . size ,
297
- subscriptions : this . subscriptions . size ,
298
- useMasterKey : client . hasMasterKey ,
299
- installationId : client . installationId ,
300
- sendEvent : true ,
301
- } ;
302
- return maybeRunAfterEventTrigger ( 'afterEvent' , className , res ) ;
303
- } )
304
- . then (
305
- ( ) => {
306
- if ( ! res . sendEvent ) {
307
- return ;
308
- }
309
- if ( res . object && typeof res . object . toJSON === 'function' ) {
310
- currentParseObject = res . object . toJSON ( ) ;
311
- currentParseObject . className = res . object . className || className ;
312
- }
313
-
314
- if ( res . original && typeof res . original . toJSON === 'function' ) {
315
- originalParseObject = res . original . toJSON ( ) ;
316
- originalParseObject . className = res . original . className || className ;
317
- }
318
- const functionName =
319
- 'push' + message . event . charAt ( 0 ) . toUpperCase ( ) + message . event . slice ( 1 ) ;
320
- if ( client [ functionName ] ) {
321
- client [ functionName ] ( requestId , currentParseObject , originalParseObject ) ;
322
- }
323
- } ,
324
- error => {
325
- Client . pushError (
326
- client . parseWebSocket ,
327
- error . code || 141 ,
328
- error . message || error ,
329
- false ,
330
- requestId
331
- ) ;
332
- logger . error (
333
- `Failed running afterLiveQueryEvent on class ${ className } for event ${ res . event } with session ${ res . sessionToken } with:\n Error: ` +
334
- JSON . stringify ( error )
335
- ) ;
298
+ } else {
299
+ return null ;
300
+ }
301
+ message . event = type ;
302
+ res = {
303
+ event : type ,
304
+ sessionToken : client . sessionToken ,
305
+ object : currentParseObject ,
306
+ original : originalParseObject ,
307
+ clients : this . clients . size ,
308
+ subscriptions : this . subscriptions . size ,
309
+ useMasterKey : client . hasMasterKey ,
310
+ installationId : client . installationId ,
311
+ sendEvent : true ,
312
+ } ;
313
+ const trigger = getTrigger ( className , 'afterEvent' , Parse . applicationId ) ;
314
+ if ( trigger ) {
315
+ if ( res . object ) {
316
+ res . object = Parse . Object . fromJSON ( res . object ) ;
317
+ }
318
+ if ( res . original ) {
319
+ res . original = Parse . Object . fromJSON ( res . original ) ;
336
320
}
321
+ const auth = await this . getAuthForSessionToken ( res . sessionToken ) ;
322
+ res . user = auth . user ;
323
+ await runTrigger ( trigger , `afterEvent.${ className } ` , res , auth ) ;
324
+ }
325
+ if ( ! res . sendEvent ) {
326
+ return ;
327
+ }
328
+ if ( res . object && typeof res . object . toJSON === 'function' ) {
329
+ currentParseObject = res . object . toJSON ( ) ;
330
+ currentParseObject . className = res . object . className || className ;
331
+ }
332
+
333
+ if ( res . original && typeof res . original . toJSON === 'function' ) {
334
+ originalParseObject = res . original . toJSON ( ) ;
335
+ originalParseObject . className = res . original . className || className ;
336
+ }
337
+ const functionName =
338
+ 'push' + message . event . charAt ( 0 ) . toUpperCase ( ) + message . event . slice ( 1 ) ;
339
+ if ( client [ functionName ] ) {
340
+ client [ functionName ] ( requestId , currentParseObject , originalParseObject ) ;
341
+ }
342
+ } catch ( error ) {
343
+ Client . pushError (
344
+ client . parseWebSocket ,
345
+ error . code || 141 ,
346
+ error . message || error ,
347
+ false ,
348
+ requestId
349
+ ) ;
350
+ logger . error (
351
+ `Failed running afterLiveQueryEvent on class ${ className } for event ${ res . event } with session ${ res . sessionToken } with:\n Error: ` +
352
+ JSON . stringify ( error )
337
353
) ;
354
+ }
338
355
}
339
356
}
340
357
}
@@ -614,7 +631,12 @@ class ParseLiveQueryServer {
614
631
useMasterKey : client . hasMasterKey ,
615
632
installationId : request . installationId ,
616
633
} ;
617
- await maybeRunConnectTrigger ( 'beforeConnect' , req ) ;
634
+ const trigger = getTrigger ( '@Connect' , 'beforeConnect' , Parse . applicationId ) ;
635
+ if ( trigger ) {
636
+ const auth = await this . getAuthForSessionToken ( req . sessionToken ) ;
637
+ req . user = auth . user ;
638
+ await runTrigger ( trigger , `beforeConnect.@Connect` , req , auth ) ;
639
+ }
618
640
parseWebsocket . clientId = clientId ;
619
641
this . clients . set ( parseWebsocket . clientId , client ) ;
620
642
logger . info ( `Create new client: ${ parseWebsocket . clientId } ` ) ;
@@ -668,7 +690,22 @@ class ParseLiveQueryServer {
668
690
const client = this . clients . get ( parseWebsocket . clientId ) ;
669
691
const className = request . query . className ;
670
692
try {
671
- await maybeRunSubscribeTrigger ( 'beforeSubscribe' , className , request ) ;
693
+ const trigger = getTrigger ( className , 'beforeSubscribe' , Parse . applicationId ) ;
694
+ if ( trigger ) {
695
+ const auth = await this . getAuthForSessionToken ( request . sessionToken ) ;
696
+ request . user = auth . user ;
697
+
698
+ const parseQuery = new Parse . Query ( className ) ;
699
+ parseQuery . withJSON ( request . query ) ;
700
+ request . query = parseQuery ;
701
+ await runTrigger ( trigger , `beforeSubscribe.${ className } ` , request , auth ) ;
702
+
703
+ const query = request . query . toJSON ( ) ;
704
+ if ( query . keys ) {
705
+ query . fields = query . keys . split ( ',' ) ;
706
+ }
707
+ request . query = query ;
708
+ }
672
709
673
710
// Get subscription from subscriptions, create one if necessary
674
711
const subscriptionHash = queryHash ( request . query ) ;
0 commit comments