diff options
author | Eric Guzman | 2012-04-23 11:55:55 -0700 |
---|---|---|
committer | Eric Guzman | 2012-04-23 11:55:55 -0700 |
commit | cdd1189e349e2974681e2c451e861e5b0db570e4 (patch) | |
tree | d8823c3d050e011032c563d20c1a5f61e67ae740 /node_modules/montage/core/promise-connection.js | |
parent | c0fce534c255ef1e25779e2f0e8de95bb4e160cf (diff) | |
parent | 5a0331fc26fcc2cdc6200086109e34440a2dec6a (diff) | |
download | ninja-cdd1189e349e2974681e2c451e861e5b0db570e4.tar.gz |
Merge branch 'refs/heads/master' into CSSPanelUpdates
Diffstat (limited to 'node_modules/montage/core/promise-connection.js')
-rw-r--r-- | node_modules/montage/core/promise-connection.js | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/node_modules/montage/core/promise-connection.js b/node_modules/montage/core/promise-connection.js new file mode 100644 index 00000000..dc218f11 --- /dev/null +++ b/node_modules/montage/core/promise-connection.js | |||
@@ -0,0 +1,285 @@ | |||
1 | |||
2 | var Montage = require("./core").Montage; | ||
3 | var UUID = require("./uuid"); | ||
4 | var Promise = require("./promise").Promise; | ||
5 | var PromiseQueue = require("./promise-queue").PromiseQueue; | ||
6 | var CacheMap = require("./shim/structures").CacheMap; | ||
7 | var logger = require("./logger").logger("promise-connections"); | ||
8 | var rootId = ""; | ||
9 | |||
10 | exports.connect = connect; | ||
11 | function connect(port, local, options) { | ||
12 | return PromiseConnection.create().init(port, local, options); | ||
13 | } | ||
14 | |||
15 | var PromiseConnection = | ||
16 | exports.PromiseConnection = Montage.create(Montage, { | ||
17 | |||
18 | init: { | ||
19 | value: function (port, local, options) { | ||
20 | options = options || {}; | ||
21 | // sigil for debug message prefix | ||
22 | this.sigil = Math.random().toString(36).toUpperCase().slice(2, 4); | ||
23 | this.makeId = options.makeId || UUID.generate; | ||
24 | this.locals = CacheMap(options.max); | ||
25 | this.port = Adapter.adapt(port, options.origin); | ||
26 | this.port.forEach(function (message) { | ||
27 | this.log("receive:", message); | ||
28 | message = JSON.parse(message); | ||
29 | if (!this.receivers[message.type]) | ||
30 | return; | ||
31 | if (!this.locals.has(message.to)) | ||
32 | return; | ||
33 | this.receivers[message.type].call(this, message); | ||
34 | }, this); | ||
35 | this.makeLocal(rootId); | ||
36 | this.resolveLocal(rootId, local); | ||
37 | return this.makeRemote(rootId); | ||
38 | } | ||
39 | }, | ||
40 | |||
41 | log: { | ||
42 | value: function (/*...args*/) { | ||
43 | logger.debug.apply(logger, ["Connection:", this.sigil].concat(Array.prototype.slice.call(arguments))) | ||
44 | } | ||
45 | }, | ||
46 | |||
47 | encode: { | ||
48 | value: function (object) { | ||
49 | if (Promise.isPromise(object)) { | ||
50 | var id = this.makeId(); | ||
51 | this.makeLocal(id); | ||
52 | this.resolveLocal(id, object); | ||
53 | return {"@": id}; | ||
54 | } else if (Array.isArray(object)) { | ||
55 | return object.map(this.encode, this); | ||
56 | } else if (typeof object === "object") { | ||
57 | var newObject = {}; | ||
58 | if (has.call(object, key)) { | ||
59 | var newKey = key; | ||
60 | if (/^[!@]$/.exec(key)) | ||
61 | newKey = key + key; | ||
62 | newObject[newKey] = this.encode(object[key]); | ||
63 | } | ||
64 | return newObject; | ||
65 | } else { | ||
66 | return object; | ||
67 | } | ||
68 | } | ||
69 | }, | ||
70 | |||
71 | decode: { | ||
72 | value: function (object) { | ||
73 | if (!object) { | ||
74 | return object; | ||
75 | } else if (object['!']) { | ||
76 | return Promise.reject(object['!']); | ||
77 | } else if (object['@']) { | ||
78 | return this.makeRemote(object['@']); | ||
79 | } else if (Array.isArray(object)) { | ||
80 | return object.map(this.decode, this); | ||
81 | } else if (typeof object === 'object') { | ||
82 | var newObject = {}; | ||
83 | for (var key in object) { | ||
84 | if (has.call(object, key)) { | ||
85 | var newKey = key; | ||
86 | if (/^(@@|!!)$/.exec(key)) | ||
87 | newKey = key.substring(1); | ||
88 | newObject[newKey] = this.decode(object[key]); | ||
89 | } | ||
90 | } | ||
91 | return newObject; | ||
92 | } else { | ||
93 | return object; | ||
94 | } | ||
95 | } | ||
96 | }, | ||
97 | |||
98 | makeLocal: { | ||
99 | value: function (id) { | ||
100 | if (!this.locals.has(id)) { | ||
101 | this.locals.set(id, Promise.defer()); | ||
102 | } | ||
103 | return this.locals.get(id).promise; | ||
104 | } | ||
105 | }, | ||
106 | |||
107 | resolveLocal: { | ||
108 | value: function (id, value) { | ||
109 | this.log('resolve:', 'L' + JSON.stringify(id), JSON.stringify(value)); | ||
110 | this.locals.get(id).resolve(value); | ||
111 | } | ||
112 | }, | ||
113 | |||
114 | makeRemote: { | ||
115 | value: function (id) { | ||
116 | return RemotePromise.create().init(this, id); | ||
117 | } | ||
118 | }, | ||
119 | |||
120 | receivers: { | ||
121 | value: Object.create(null, { | ||
122 | |||
123 | resolve: { | ||
124 | value: function (message) { | ||
125 | if (this.locals.has(message.to)) { | ||
126 | this.resolveLocal(message.to, this.decode(message.resolution)); | ||
127 | } | ||
128 | } | ||
129 | }, | ||
130 | |||
131 | send: { | ||
132 | value: function (message) { | ||
133 | var connection = this; | ||
134 | this.locals.get(message.to).promise | ||
135 | .send(message.op, this.decode(message.args)) | ||
136 | .then(function (resolution) { | ||
137 | return Promise.call(function () { | ||
138 | return JSON.stringify({ | ||
139 | type: 'resolve', | ||
140 | to: message.from, | ||
141 | resolution: connection.encode(resolution) | ||
142 | }) | ||
143 | }) | ||
144 | .fail(function (error) { | ||
145 | console.log('XXX:', error); | ||
146 | return JSON.stringify({ | ||
147 | type: 'resolve', | ||
148 | to: message.from, | ||
149 | resolution: null | ||
150 | }); | ||
151 | }) | ||
152 | }, function (reason, error, rejection) { | ||
153 | return Promise.call(function () { | ||
154 | return JSON.stringify({ | ||
155 | type: 'resolve', | ||
156 | to: message.from, | ||
157 | resolution: {'!': connection.encode(reason)} | ||
158 | }) | ||
159 | }) | ||
160 | .fail(function () { | ||
161 | return JSON.stringify({ | ||
162 | type: 'resolve', | ||
163 | to: message.from, | ||
164 | resolution: {'!': null} | ||
165 | }); | ||
166 | }) | ||
167 | }) | ||
168 | .then(function (envelope) { | ||
169 | connection.port.put(envelope); | ||
170 | }) | ||
171 | .end(); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | }) | ||
176 | } | ||
177 | |||
178 | }); | ||
179 | |||
180 | var RemotePromise = Montage.create(Promise.AbstractPromise, { | ||
181 | init: { | ||
182 | value: function (connection, id) { | ||
183 | this._connection = connection; | ||
184 | this._id = id; | ||
185 | this.Promise = Promise; | ||
186 | return this; | ||
187 | } | ||
188 | }, | ||
189 | _handlers: { | ||
190 | value: {} | ||
191 | }, | ||
192 | _fallback: { | ||
193 | value: function (resolve, op /*...args*/) { | ||
194 | var localId = this._connection.makeId(); | ||
195 | var response = this._connection.makeLocal(localId); | ||
196 | var args = Array.prototype.slice.call(arguments, 2); | ||
197 | this._connection.log('sending:', 'R' + JSON.stringify(this._id), JSON.stringify(op), JSON.stringify(args)); | ||
198 | this._connection.port.put(JSON.stringify({ | ||
199 | type: 'send', | ||
200 | to: this._id, | ||
201 | from: localId, | ||
202 | op: op, | ||
203 | args: this._connection.encode(args) | ||
204 | })); | ||
205 | return response; | ||
206 | } | ||
207 | } | ||
208 | }); | ||
209 | |||
210 | var Adapter = | ||
211 | exports.Adapter = Montage.create(Montage, { | ||
212 | adapt: { | ||
213 | value: function (port, origin) { | ||
214 | return this.create().init(port, origin); | ||
215 | } | ||
216 | }, | ||
217 |