Skip to content

Commit db1a5dc

Browse files
committed
v1.0.0
0 parents  commit db1a5dc

21 files changed

+6403
-0
lines changed

.gitignore

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
8+
# Runtime data
9+
pids
10+
*.pid
11+
*.seed
12+
*.pid.lock
13+
14+
# Directory for instrumented libs generated by jscoverage/JSCover
15+
lib-cov
16+
17+
# Coverage directory used by tools like istanbul
18+
coverage
19+
20+
# nyc test coverage
21+
.nyc_output
22+
23+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24+
.grunt
25+
26+
# Bower dependency directory (https://bower.io/)
27+
bower_components
28+
29+
# node-waf configuration
30+
.lock-wscript
31+
32+
# Compiled binary addons (http://nodejs.org/api/addons.html)
33+
build/Release
34+
35+
# Dependency directories
36+
node_modules/
37+
jspm_packages/
38+
39+
# Typescript v1 declaration files
40+
typings/
41+
42+
# Optional npm cache directory
43+
.npm
44+
45+
# Optional eslint cache
46+
.eslintcache
47+
48+
# Optional REPL history
49+
.node_repl_history
50+
51+
# Output of 'npm pack'
52+
*.tgz
53+
54+
# Yarn Integrity file
55+
.yarn-integrity
56+
57+
# dotenv environment variables file
58+
.env
59+

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
language: node_js
2+
node_js:
3+
- "node"
4+

LICENSE

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
The ISC License
2+
3+
Copyright (c) Luca Tabone and Contributors
4+
5+
Permission to use, copy, modify, and/or distribute this software for any
6+
purpose with or without fee is hereby granted, provided that the above
7+
copyright notice and this permission notice appear in all copies.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15+
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

README.md

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
[![Build Status](https://travis-ci.org/tcp-emitter/server.svg?branch=master)](https://travis-ci.org/tcp-emitter/server)
2+
3+
# TCP Emitter Server
4+
5+
`TCP Emitter Server` is a [net.Server](https://nodejs.org/api/net.html#net_class_net_server) object that acts as an [Event Emitter](https://nodejs.org/api/events.html#events_class_eventemitter) router for different processes. These processes (known as `TCP Emitter clients`) can be implemented in any language and interact with `TCP Emitter server` via the [TCP Protocol](https://tools.ietf.org/html/rfc793).
6+
7+
# Installation
8+
9+
```
10+
npm install --save tcp-emitter
11+
```
12+
13+
# API
14+
## require('tcp-emitter')(options)
15+
16+
Options | Type | Default | Description
17+
---------------------- | ---------- | ------------ | -----------
18+
`options.delimiter` | `string` | '@@@' | Delimiter used to seperate payloads in a single TCP request. [More info here](#delimiter).
19+
`options.verifyClient` | `function` | `() => true` | Function used to determine whether to allow or deny a `TCP Emitter client` connection. By default all connections are allowed. [More info here](#verify-client).
20+
21+
### Delimiter
22+
Delimiter used to seperate payloads in a single TCP request. Apart from making it possible for `TCP Emitter clients` to combine multiple payloads in a single TCP request, this was mainly implemented due to the use of [Nagle's algorithm](https://en.wikipedia.org/wiki/Nagle%27s_algorithm) in NodeJS [net](https://nodejs.org/api/net.html) module. When sending data through TCP while using `net` module in seperate [.write()](https://nodejs.org/api/net.html#net_socket_write_data_encoding_callback) invocations, it will try to combine the messages together and send them in a single TCP request. For this reason when sending a payload (even when a TCP message consist of one payload), it should end with the specified delimiter.
23+
24+
#### Nagle's algorithm in NodeJS
25+
```javascript
26+
// Sending a message from the client side.
27+
clientSocket.write('hello')
28+
clientSocket.write('world')
29+
30+
// Receiving the message from the server side.
31+
serverSocket.on('data', console.log) // => 'helloworld'
32+
```
33+
34+
### Verify Client
35+
Function used to verify whether a connection should be allowed or denied. When omitted, all connections are allowed. When specified a connection will be allowed if it returns `true`. When this function requires async processing it should return a `Promise` resolved with `true` to allow a connection or any other value but `true` to deny it.
36+
37+
### Synchronous Verify Client.
38+
```javascript
39+
const verifyClient = socket => allowed.indexOf(socket.address().address) !== -1
40+
require('tcpEmitter')(verifyClient).listen({ host: 'localhost', port: 8080 })
41+
```
42+
43+
### Asynchronous Verify Client
44+
```javascript
45+
const verifyClient = socket => {
46+
return makeRequest('GET', '/allowed').then(allowed => {
47+
return allowed.indexOf(socket.address().address) !== -1
48+
})
49+
}
50+
51+
require('tcpEmitter')(verifyClient).listen({ host: 'localhost', port: 8080 })
52+
```
53+
54+
# TCP Emitter Clients
55+
As specified in the introduction, these can be implemented in any language as long as they follow the TCP Emitter Payload spec. A TCP Emitter client can do the following three different interactions with the `TCP Emitter server`:
56+
57+
> Examples assume that '@@@' delimiter is used. For more info about why delimiter is used please [refer to this section](#delimiter).
58+
59+
Name | Description
60+
----------- | -------------------------------------------------------------------------------
61+
subscribe | Subscribe (Listen) to an event.
62+
unsubscribe | Unsubscribe from an event.
63+
broadcast | Broadcast (notify) the listeners (i.e. other `TCP Emitter clients`) of an event.
64+
65+
## Payload Spec
66+
67+
### Subscribe
68+
Attribute | Type | Description
69+
--------- | -------- | --------------------
70+
`type` | `string` | Type of interaction, for a subscription this should be set to `subscribe`.
71+
`event` | `string` | Name of event to subscribe to.
72+
73+
### Example
74+
``` json
75+
{"type": "subscribe", "event": "event-name"}@@@
76+
```
77+
78+
### Unsubscribe
79+
Attribute | Type | Description
80+
--------- | -------- | --------------------
81+
`type` | `string` | Type of interaction, for an unsubscription this should be set to `unsubscribe`.
82+
`event` | `string` | Name of event to unsubscribe from.
83+
84+
### Example
85+
``` json
86+
{"type": "unsubscribe", "event": "event-name"}@@@
87+
```
88+
89+
### Broadcast
90+
Attribute | Type | Description
91+
--------- | ------------- | --------------------
92+
`type` | `string` | Type of interaction, for a broadcast this should be set to `broadcast`.
93+
`event` | `string` | Name of event to broadcast to.
94+
`args` | `Array.<any>` | Arguments that will be broadcasted to the TCP Emitter clients with the event.
95+
96+
> When a TCP Emitter client broadcasts to an event which itself is subscribed to, it won't be notified by TCP Emitter server.
97+
98+
### Example
99+
``` json
100+
{"type": "broadcast", "event": "event-name", "args": [1, "text", true, {"name": "luca"}]}@@@
101+
```
102+
103+
## Multi-Payload TCP Request
104+
As mentioned in the delimiter section, TCP Emitter clients can send multiple payloads in a single TCP Request. The following is an example of a TCP Request message containing multiple payloads.
105+
106+
```json
107+
{"type": "subscribe", "event": "new-user"}@@@{"type": "unsubscribe", "event": "new-admin"}@@@{"type": "broadcast", "event": "access-change", "args": ["user"]}@@@
108+
```
109+
110+
# Example
111+
TCP Emitter server configured with a delimiter set to `!!!`
112+
```javascript
113+
require('tcp-emitter')({
114+
delimiter: '!!!'
115+
}).listen({ host: 'localhost', port: 8080 })
116+
```
117+
118+
> Note in this example `TCP Emitter clients` are implemented in JavaScript, however as mentioned in the introduction these can be implemented in any language.
119+
120+
TCP Emitter client 1.
121+
```javascript
122+
const clientOne = require('net').createConnection({
123+
host: 'localhost',
124+
port: 8080
125+
}, () => {
126+
clientOne.on('data', console.log)
127+
128+
clientOne.setEncoding('utf-8')
129+
130+
clientOne.write(JSON.stringify({
131+
type: 'subscribe',
132+
event: 'got-episode'
133+
}) + '!!!')
134+
})
135+
```
136+
137+
TCP Emitter client 2.
138+
```javascript
139+
const clientTwo = require('net').createConnection({
140+
host: 'localhost',
141+
port: 8080
142+
}, () => {
143+
clientTwo.on('data', console.log)
144+
145+
clientTwo.setEncoding('utf-8')
146+
147+
clientTwo.write(JSON.stringify({
148+
type: 'subscribe',
149+
event: 'got-episode'
150+
}) + '!!!')
151+
})
152+
```
153+
154+
When TCP Emitter 1 broadcasts to `got-episode` event:
155+
156+
```javascript
157+
clientOne.write(JSON.stringify({
158+
type: 'broadcast',
159+
event: 'got-episode',
160+
args: ['S7E5 - Eastwatch']
161+
}) + '!!!')
162+
```
163+
164+
TCP Emitter 2 'data' listener will be invoked with the following string:
165+
```javascript
166+
'{"event":"got-episode","args":["S7E5 - Eastwatch"]}!!!'
167+
```
168+
169+
# Tests
170+
```
171+
npm install
172+
npm test
173+
```
174+
175+
# Generate Documentation
176+
```
177+
npm install
178+
npm run docs
179+
```
180+
181+
# License
182+
ISC

conf.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"sourceType": "module",
3+
"opts": {
4+
"recursive": true
5+
},
6+
"plugins": [
7+
"plugins/markdown"
8+
],
9+
"source": {
10+
"include": [ "./docs.js", "src/", "index.js" ]
11+
},
12+
"tags": {
13+
"allowUnknownTags": false,
14+
"dictionaries": [ "jsdoc" ]
15+
},
16+
"templates": {
17+
"cleverLinks": true,
18+
"monospaceLinks": true
19+
}
20+
}

docs.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Function used to verify whether a connection should be allowed or denied.
3+
* When omitted, all connections are allowed. When specified a connection will
4+
* be allowed if it returns `true`. When this function requires async processing
5+
* it should return a `Promise` resolved with `true` to allow a connection or
6+
* any other value but `true` to deny it.
7+
*
8+
* @example
9+
* <caption>Synchronous Verify Client</caption>
10+
* socket => allowed.indexOf(socket.address().address) !== -1
11+
*
12+
* @example
13+
* <caption>Asynchronous Verify Client</caption>
14+
* socket => {
15+
* return makeRequest('GET', '/allowed').then(allowed => {
16+
* return allowed.indexOf(socket.address().address) !== -1
17+
* })
18+
* }
19+
*
20+
* @async
21+
* @callback module:tcp-emitter~verify-client
22+
* @see {@link https://nodejs.org/api/net.html#net_class_net_socket|net.Socket}
23+
* @param {net.Socket} socket Connection object.
24+
* @return {boolean} When the connection is allowed, it should return
25+
* `true`.
26+
* @return {*} When the connection is denied, it should return
27+
* anything but `true`.
28+
* @return {Promise.<boolean>} When async processing is required and the
29+
* connection is allowed, it should return a
30+
* `Promise` resolved with `true`.
31+
* @return {Promise.<*>} When async processing is required and a
32+
* connection is denied, it should return a
33+
* `Promise` resolved with any value but `true`.
34+
*/

index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
'use strict'
2+
module.exports = require('./src')

0 commit comments

Comments
 (0)