-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathserver.coffee
132 lines (96 loc) · 3.85 KB
/
server.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import {_} from 'meteor/underscore'
import Fiber from 'fibers'
savedYield = Fiber.yield
# When inside Meteor._noYieldsAllowed Fiber.yield is overridden with
# a function which throws an exception, so is not savedYield anymore.
# Afterwards Fiber.yield is restored back to savedYield.
isInsideNoYieldsAllowed = ->
Fiber.yield isnt savedYield
class MiddlewarePublish
constructor: (@publish) ->
# We store those methods at construction time because
# we override them later on publish object.
@_publishAdded = @publish.added.bind @publish
@_publishChanged = @publish.changed.bind @publish
@_publishRemoved = @publish.removed.bind @publish
@_publishReady = @publish.ready.bind @publish
@_publishStop = @publish.stop.bind @publish
@_publishError = @publish.error.bind @publish
# We copy other fields as they are
for own key, value of @publish when key not in ['added', 'changed', 'removed', 'ready', 'stop', 'error']
@[key] = value
added: (args...) ->
@_publishAdded args...
changed: (args...) ->
@_publishChanged args...
removed: (args...) ->
@_publishRemoved args...
ready: (args...) ->
@_publishReady args...
stop: (args...) ->
@_publishStop args...
error: (args...) ->
@_publishError args...
export class PublishEndpoint
constructor: (@options, @publishFunction) ->
# To pass null (autopublish) or string directly for name
if @options is null or _.isString @options
@options =
name: @options
@middlewares = []
self = @
Meteor.publish @options.name, (args...) ->
publish = @
state = {}
publish.params = ->
args
publish.set = (key, value) ->
state[key] = value
publish.get = (key) ->
state[key]
self.publish self.middlewares, publish
publish: (middlewares, publish) ->
if middlewares.length
latestMiddleware = middlewares[middlewares.length - 1]
otherMiddlewares = middlewares[0...middlewares.length - 1]
midlewarePublish = new MiddlewarePublish publish
publish.added = (collection, id, fields) ->
latestMiddleware.added midlewarePublish, collection, id, fields
publish.changed = (collection, id, fields) ->
latestMiddleware.changed midlewarePublish, collection, id, fields
publishRemoved = publish.removed
publish.removed = (collection, id) ->
# When unsubscribing, Meteor removes all documents so this callback is called
# inside Meteor._noYieldsAllowed which means inside the callback no function
# which calls yield can be called. Because this is often not true, in that
# special case we are not going through middlewares but are directly calling
# original removed callback.
if isInsideNoYieldsAllowed()
publishRemoved.call publish, collection, id
else
latestMiddleware.removed midlewarePublish, collection, id
publish.ready = ->
latestMiddleware.onReady midlewarePublish
publish.stop = ->
latestMiddleware.onStop midlewarePublish
publish.error = (error) ->
latestMiddleware.onError midlewarePublish, error
@publish otherMiddlewares, publish
else
@publishFunction.apply publish, publish.params()
use: (middleware) ->
throw new Error "Middleware '#{ middleware }' is not an instance of a PublishMiddleware class" unless middleware instanceof PublishMiddleware
@middlewares.push middleware
export class PublishMiddleware
added: (publish, collection, id, fields) ->
publish.added collection, id, fields
changed: (publish, collection, id, fields) ->
publish.changed collection, id, fields
removed: (publish, collection, id) ->
publish.removed collection, id
onReady: (publish) ->
publish.ready()
onStop: (publish) ->
publish.stop()
onError: (publish, error) ->
publish.error error