Comparing version 0.15.0 to 0.16.0
@@ -42,4 +42,4 @@ // Generated by LiveScript 1.4.0 | ||
} | ||
prototype.send = function(message, payload, replyHandler){ | ||
var requestId; | ||
prototype.send = function(messageName, payload, replyHandler){ | ||
var messageId; | ||
switch (false) { | ||
@@ -49,15 +49,15 @@ case !(replyHandler && typeof replyHandler !== 'function'): | ||
} | ||
requestId = this.messageSender.send(message, payload); | ||
messageId = this.messageSender.send(messageName, payload); | ||
if (replyHandler) { | ||
this.messageHandler.registerReplyHandler(requestId, replyHandler); | ||
this.messageHandler.registerReplyHandler(messageId, replyHandler); | ||
} | ||
return requestId; | ||
return messageId; | ||
}; | ||
prototype._onIncomingMessage = function(requestData){ | ||
switch (false) { | ||
case !!requestData.requestId: | ||
return 'missing request id'; | ||
case !!requestData.id: | ||
return 'missing message id'; | ||
} | ||
return this.messageHandler.handleRequest(requestData, { | ||
reply: this.messageSender.replyMethodFor(requestData.requestId), | ||
reply: this.messageSender.replyMethodFor(requestData.id), | ||
send: this.send | ||
@@ -64,0 +64,0 @@ }); |
@@ -11,10 +11,10 @@ // Generated by LiveScript 1.4.0 | ||
} | ||
prototype.getHandler = function(requestId){ | ||
return this.handlers[requestId]; | ||
prototype.getHandler = function(messageId){ | ||
return this.handlers[messageId]; | ||
}; | ||
prototype.handleCommand = function(arg$, methods){ | ||
var message, payload, handler; | ||
message = arg$.message, payload = arg$.payload; | ||
if (handler = this.getHandler(message)) { | ||
debug("handling message '" + message + "'"); | ||
var messageName, payload, handler; | ||
messageName = arg$.messageName, payload = arg$.payload; | ||
if (handler = this.getHandler(messageName)) { | ||
debug("handling message '" + messageName + "'"); | ||
handler(payload, methods); | ||
@@ -25,8 +25,8 @@ } | ||
prototype.handleReply = function(arg$){ | ||
var message, responseTo, payload, handler; | ||
message = arg$.message, responseTo = arg$.responseTo, payload = arg$.payload; | ||
var messageName, responseTo, payload, handler; | ||
messageName = arg$.messageName, responseTo = arg$.responseTo, payload = arg$.payload; | ||
if (handler = this.getHandler(responseTo)) { | ||
debug("handling message '" + message + "' in response to '" + responseTo + "'"); | ||
debug("handling message '" + messageName + "' in response to '" + responseTo + "'"); | ||
handler(payload, { | ||
outcome: message | ||
outcome: messageName | ||
}); | ||
@@ -36,11 +36,11 @@ } | ||
}; | ||
prototype.hasHandler = function(requestId){ | ||
return typeof this.getHandler(requestId) === 'function'; | ||
prototype.hasHandler = function(messageId){ | ||
return typeof this.getHandler(messageId) === 'function'; | ||
}; | ||
prototype.registerHandler = function(requestId, handler){ | ||
prototype.registerHandler = function(messageId, handler){ | ||
switch (false) { | ||
case !!requestId: | ||
return this.emit('error', new Error('No request id provided')); | ||
case typeof requestId === 'string': | ||
return this.emit('error', new Error('Request ids must be strings')); | ||
case !!messageId: | ||
return this.emit('error', new Error('No message id provided')); | ||
case typeof messageId === 'string': | ||
return this.emit('error', new Error('Message ids must be strings')); | ||
case !!handler: | ||
@@ -50,13 +50,13 @@ return this.emit('error', new Error('No message handler provided')); | ||
return this.emit('error', new Error('Message handler must be a function')); | ||
case !this.hasHandler(requestId): | ||
return this.emit('error', new Error("There is already a handler for message '" + requestId + "'")); | ||
case !this.hasHandler(messageId): | ||
return this.emit('error', new Error("There is already a handler for message '" + messageId + "'")); | ||
} | ||
this.debug("registering handler for request-id '" + requestId + "'"); | ||
return this.handlers[requestId] = handler; | ||
this.debug("registering handler for id '" + messageId + "'"); | ||
return this.handlers[messageId] = handler; | ||
}; | ||
prototype.registerHandlers = function(handlers){ | ||
var requestId, handler, results$ = []; | ||
for (requestId in handlers) { | ||
handler = handlers[requestId]; | ||
results$.push(this.registerHandler(requestId, handler)); | ||
var messageId, handler, results$ = []; | ||
for (messageId in handlers) { | ||
handler = handlers[messageId]; | ||
results$.push(this.registerHandler(messageId, handler)); | ||
} | ||
@@ -63,0 +63,0 @@ return results$; |
@@ -15,3 +15,3 @@ // Generated by LiveScript 1.4.0 | ||
x$.get('/status', this._statusController); | ||
x$.post('/run/:message', this._messageController); | ||
x$.post('/run/:messageName', this._messageController); | ||
this.port = null; | ||
@@ -48,6 +48,6 @@ } | ||
return res.status(200).end(); | ||
case 'missing request id': | ||
return res.status(400).end('missing request id'); | ||
case 'missing message id': | ||
return res.status(400).end('missing message id'); | ||
case 'unknown message': | ||
return res.status(404).end("unknown message: '" + requestData.message + "'"); | ||
return res.status(404).end("unknown message: '" + requestData.messageName + "'"); | ||
default: | ||
@@ -58,9 +58,9 @@ return this.emit('error', Error("unknown result code: '" + this.result + "'")); | ||
prototype._log = function(arg$){ | ||
var message, requestId, responseTo; | ||
message = arg$.message, requestId = arg$.requestId, responseTo = arg$.responseTo; | ||
var messageName, id, responseTo; | ||
messageName = arg$.messageName, id = arg$.id, responseTo = arg$.responseTo; | ||
switch (false) { | ||
case !responseTo: | ||
return debug("received message '" + message + "' with id '" + requestId + "' in response to '" + responseTo + "'"); | ||
return debug("received message '" + messageName + "' with id '" + id + "' in response to '" + responseTo + "'"); | ||
default: | ||
return debug("received message '" + message + "' with id '" + requestId + "'"); | ||
return debug("received message '" + messageName + "' with id '" + id + "'"); | ||
} | ||
@@ -72,12 +72,12 @@ }; | ||
prototype._parseRequest = function(req){ | ||
var message, payload, responseTo, requestId; | ||
message = req.params.message; | ||
var messageName, payload, responseTo, id; | ||
messageName = req.params.messageName; | ||
payload = req.body.payload; | ||
responseTo = req.body.responseTo; | ||
requestId = req.body.requestId; | ||
id = req.body.id; | ||
return { | ||
message: message, | ||
messageName: messageName, | ||
responseTo: responseTo, | ||
payload: payload, | ||
requestId: requestId | ||
id: id | ||
}; | ||
@@ -84,0 +84,0 @@ }; |
@@ -23,4 +23,4 @@ // Generated by LiveScript 1.4.0 | ||
switch (false) { | ||
case !!messageData.requestId: | ||
return 'missing request id'; | ||
case !!messageData.id: | ||
return 'missing message id'; | ||
case !this.replyHandlers.handleReply(messageData): | ||
@@ -34,4 +34,4 @@ return 'success'; | ||
}; | ||
prototype.registerReplyHandler = function(requestId, handler){ | ||
return this.replyHandlers.registerHandler(requestId, handler); | ||
prototype.registerReplyHandler = function(messageId, handler){ | ||
return this.replyHandlers.registerHandler(messageId, handler); | ||
}; | ||
@@ -38,0 +38,0 @@ return HandlerManager; |
@@ -16,18 +16,18 @@ // Generated by LiveScript 1.4.0 | ||
this.exocommPort = +this.exocommPort; | ||
this.lastSentRequestId = null; | ||
this.lastSentId = null; | ||
} | ||
prototype.replyMethodFor = function(requestId){ | ||
prototype.replyMethodFor = function(id){ | ||
var this$ = this; | ||
switch (false) { | ||
case !!requestId: | ||
return this.emit('error', new Error('MessageSender.replyMethodFor needs a requestId')); | ||
case !!id: | ||
return this.emit('error', new Error('MessageSender.replyMethodFor needs a id')); | ||
} | ||
return function(message, payload){ | ||
return function(messageName, payload){ | ||
payload == null && (payload = {}); | ||
return this$.send(message, payload, { | ||
responseTo: requestId | ||
return this$.send(messageName, payload, { | ||
responseTo: id | ||
}); | ||
}; | ||
}; | ||
prototype.send = function(message, payload, options){ | ||
prototype.send = function(messageName, payload, options){ | ||
var requestData; | ||
@@ -37,5 +37,5 @@ payload == null && (payload = {}); | ||
switch (false) { | ||
case !!message: | ||
case !!messageName: | ||
return this.emit('error', new Error('ExoRelay#send cannot send empty messages')); | ||
case typeof message === 'string': | ||
case typeof messageName === 'string': | ||
return this.emit('error', new Error('ExoRelay#send can only send string messages')); | ||
@@ -45,10 +45,10 @@ case typeof payload !== 'function': | ||
} | ||
this._log(message, options); | ||
this._log(messageName, options); | ||
requestData = { | ||
method: 'POST', | ||
url: "http://localhost:" + this.exocommPort + "/send/" + message, | ||
url: "http://localhost:" + this.exocommPort + "/send/" + messageName, | ||
json: true, | ||
body: { | ||
sender: this.serviceName, | ||
requestId: uuid.v1() | ||
id: uuid.v1() | ||
} | ||
@@ -64,3 +64,3 @@ }; | ||
if (err || (response != null ? response.statusCode : void 8) !== 200) { | ||
debug("Error sending message '" + message + "'"); | ||
debug("Error sending message '" + messageName + "'"); | ||
debug("* err: " + err); | ||
@@ -70,10 +70,10 @@ return debug("* response: " + (response != null ? response.statusCode : void 8)); | ||
}); | ||
return this.lastSentRequestId = requestData.body.requestId; | ||
return this.lastSentId = requestData.body.id; | ||
}; | ||
prototype._log = function(message, options){ | ||
prototype._log = function(messageName, options){ | ||
switch (false) { | ||
case !options.responseTo: | ||
return debug("sending message '" + message + "' in response to '" + options.responseTo + "'"); | ||
return debug("sending message '" + messageName + "' in response to '" + options.responseTo + "'"); | ||
default: | ||
return debug("sending message '" + message + "'"); | ||
return debug("sending message '" + messageName + "'"); | ||
} | ||
@@ -80,0 +80,0 @@ }; |
{ | ||
"name": "exorelay", | ||
"version": "0.15.0", | ||
"version": "0.16.0", | ||
"author": "Kevin Goslar", | ||
@@ -9,3 +9,3 @@ "dependencies": { | ||
"express": "4.13.4", | ||
"lodash.isempty": "4.1.2", | ||
"lodash.isempty": "4.1.3", | ||
"node-uuid": "1.4.7", | ||
@@ -24,3 +24,3 @@ "rails-delegate": "0.6.0", | ||
"livescript": "1.4.0", | ||
"lodash.isequal": "4.1.0", | ||
"lodash.isequal": "4.1.1", | ||
"mocha": "2.4.5", | ||
@@ -30,3 +30,3 @@ "mocha-circleci-reporter": "0.0.1", | ||
"o-tools": "0.1.4", | ||
"portfinder": "1.0.1", | ||
"portfinder": "1.0.2", | ||
"record-http": "0.6.0", | ||
@@ -33,0 +33,0 @@ "sinon": "1.17.3", |
145
README.md
@@ -7,5 +7,6 @@ # Exosphere Communication Relay for JavaScript | ||
This library allows you to add Exosphere communication to any Node.js codebase. | ||
It is intended to be used in your web or API server. | ||
If you want to write a micro-service in Node, | ||
This library allows you to add Exosphere communication to any Node.JS codebase. | ||
It is intended to be used in your web or API server, | ||
or with legacy Node code bases. | ||
If you want to write a new micro-service in Node, | ||
please use [ExoService-JS](https://github.com/Originate/exoservice-js), | ||
@@ -18,7 +19,2 @@ which uses this library internally. | ||
Each code base should have only one ExoRelay instance. | ||
ExoRelay instances emit events to signal state changes: | ||
* __online__: the instance is completely online now. Provides the port it listens on. | ||
* __offline__: the instance is offline now | ||
* __error__: an error has occurred. The instance is in an invalid state, | ||
your application should crash. | ||
@@ -36,25 +32,35 @@ ```coffeescript | ||
## Events | ||
ExoRelay instances are [EventEmitters](https://nodejs.org/api/events.html). | ||
They emit the following events to signal state changes: | ||
<table> | ||
<tr> | ||
<th>online</th> | ||
<td>The instance is completely online now. Provides the port it listens on. | ||
</tr> | ||
<tr> | ||
<th>offline</th> | ||
<td>The instance is offline now.</td> | ||
</tr> | ||
<tr> | ||
<th>error</th> | ||
<td>An error has occurred. The instance is in an invalid state, your application should crash.</td> | ||
</tr> | ||
</table> | ||
## Handle incoming messages | ||
Register a handler for incoming messages: | ||
Let's say we build a service that greets users. | ||
Here is how to register a handler for incoming "hello" messages: | ||
```coffeescript | ||
exoRelay.registerHandler 'hello', (name) -> | ||
console.log "Hello #{name}" | ||
exoRelay.registerHandler 'hello', (name) -> console.log "hello #{name}!" | ||
``` | ||
More details on how to define message listeners are [here](features/receiving-messages.feature). | ||
If you are implementing services, you want to send outgoing replies to incoming messages: | ||
```coffeescript | ||
exoRelay.registerHandler 'user.create', (userData, {reply}) -> | ||
# on this line we would create a user database record with the attributes given in userData | ||
reply 'user.created', id: 456, name: userData.name | ||
``` | ||
More details and a working example of how to send replies is [here](features/outgoing-replies.feature). | ||
## Send outgoing messages | ||
@@ -73,103 +79,30 @@ | ||
## Handle incoming replies | ||
## Send outgoing replies to incoming messages | ||
If a message you send expects a reply, | ||
you can provide the handler for it right when you send it: | ||
If you are implementing services, you want to send outgoing replies to incoming messages: | ||
```coffeescript | ||
exoRelay.send 'users.create', name: 'Will Riker', (createdUser) -> | ||
print "created user #{createdUser.id}" | ||
exoRelay.registerHandler 'user.create', (userData, {reply}) -> | ||
# on this line we would save userData in the database | ||
reply 'user.created', id: 456, name: userData.name | ||
``` | ||
Service calls are more expensive than in-process function calls. | ||
They are also higher-level, crossing functional boundaries within your application. | ||
Hence they (should) have more complex APIs than function calls. | ||
More details and a working example of how to send replies is [here](features/outgoing-replies.feature). | ||
* replies to commands often return the state changes caused by the command, | ||
to avoid having to do another call to the service to query the new state | ||
* commands often have more than one outcome. | ||
For example, the command | ||
_"transfer $100 from the checking account to the savings account"_ | ||
sent to an accounting service can reply with: | ||
<table> | ||
<tr> | ||
<th>transferred</th> | ||
<td>the money was transferred</td> | ||
</tr> | ||
<tr> | ||
<th>pending</th> | ||
<td>the transfer was initiated, but is pending a third-party approval</td> | ||
</tr> | ||
<tr> | ||
<th>transaction limit exceeded</th> | ||
<td>the account doesn't allow that much money to be transferred at once</td> | ||
</tr> | ||
<tr> | ||
<th>daily limit exceeded</th> | ||
<td>the daily transaction limit was exceeded</td> | ||
</tr> | ||
<tr> | ||
<th>insufficient funds</th> | ||
<td>there isn't enough money in the checking account</td> | ||
</tr> | ||
<tr> | ||
<th>unknown account</th> | ||
<td>one of the given accounts was not found</td> | ||
</tr> | ||
<tr> | ||
<th>unauthorized</th> | ||
<td>the currently logged in user does not have privileges to make this transfer</td> | ||
</tr> | ||
<tr> | ||
<th>internal error</th> | ||
<td>an internal error occurred in the accounting service</td> | ||
</tr> | ||
</table> | ||
## Handle incoming replies | ||
The outcome is provided as part of the optional second parameter to the reply handler. | ||
If a message you send expects a reply, | ||
you can provide the handler for it right when you send it: | ||
```livescript | ||
exoRelay.send 'transfer', amount: 100, from: 'checking', to: 'savings', (txn, {outcome}) -> | ||
switch outcome | ||
| 'transferred' => ... | ||
| 'pending' => ... | ||
| ... | ||
```coffeescript | ||
exoRelay.send 'users.create', name: 'Will Riker', (createdUser) -> | ||
console.log "the remove service has finished creating user #{createdUser.id}" | ||
``` | ||
A different use case for checking outcomes is ongoing monitoring of commands | ||
that take a while to execute. | ||
A service can send multiple replies, causing the reply handler to be called | ||
multiple times. Each reply can be a different message type: | ||
```livescript | ||
exoRelay.send 'file.copy', from: 'large.csv', to: 'backup.csv', (payload, {outcome}) -> | ||
switch outcome | ||
| 'file.copying' => console.log "still copying, #{payload.percent}% done" | ||
| 'file.copied' => console.log 'file copy finished!' | ||
``` | ||
Another use case is streaming responses, where a larger result is sent in chunks: | ||
```livescript | ||
exoRelay.send 'file.read', path: 'large.csv', (payload, {outcome}) -> | ||
switch outcome | ||
| 'file.read-chunk' => result += payload | ||
| 'file.read-done' => console.log "finished reading #{payload.megabytes} MB!" | ||
``` | ||
More examples for handling incoming replies are [here](features/incoming-replies.feature). | ||
Message handlers also provide a shortcut to send messages: | ||
```coffeescript | ||
exoRelay.registerHandler 'users.create', (createdUser, {send}) -> | ||
send 'passwords.encrypt' createdUser.password, (encryptedPassword) -> | ||
... | ||
``` | ||
More details and a working example of how to send messages from within message handlers is [here](features/sending-from-messages.feature). | ||
## Development | ||
See our [developer guidelines](CONTRIBUTING.md) |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
135627
105
+ Addedlodash.isempty@4.1.3(transitive)
- Removedlodash.isempty@4.1.2(transitive)
Updatedlodash.isempty@4.1.3