Skip to content

Commit

Permalink
rework netcode
Browse files Browse the repository at this point in the history
  • Loading branch information
timotejroiko committed May 9, 2021
1 parent 24a7bdf commit b8f9d80
Show file tree
Hide file tree
Showing 9 changed files with 365 additions and 200 deletions.
5 changes: 0 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
node_modules
package-lock.json
yarn.lock
.vscode
.yarn
.pnp.js
.yarnrc.yml
132 changes: 84 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ A simple message based IPC client/server providing bi-directional communication
const { Server } = require("net-ipc");

const server = new Server({
port:8333, // for TCP
//path:"mypath", // for sockets
//max: 100 // max number of clients (default unlimited)
port: 8333, // for TCP
// path: "mypath", // for sockets
// max: 100 // max number of clients (default unlimited)
// retries: 5 // number of retries in case of unnatural disconnections (default 3)
});

server.on("ready", url => {
Expand All @@ -38,26 +39,33 @@ server.on("connect", (client, data) => {
});

server.on("disconnect", (client, reason) => {
console.log(`client id ${client.id} disconnected with reason ${reason}`)
console.log(`client id ${client.id} disconnected with reason ${reason}`);
});

server.on("message", async (message, client) => {
console.log(`received message ${message} from client id ${client.id}`); //hi
if(message === "execute broadcast") {
await server.broadcast("hello everyone!");
}
// received when any client uses .send()
console.log(`received message ${message} from client id ${client.id}`);
});

server.on("request", async (req, res, client) => {
console.log(`received request from client id ${client.id} containing ${req}`); // did you receive this? // haha
if(req === "did you receive this?") {
await res("yes abcdefg");
} else if(req === "run survey") {
let data = await server.survey("survey");
res(data);
}
server.on("request", (req, res, client) => {
// received when any client uses .request()
console.log(`received request from client id ${client.id} containing ${req}`);
// reply to this request. client will receive "something" in the promise returned by .request()
// res is an async function, will reject if the reply fails
res("something").catch(console.error);
});

// send a message to all clients. each client will receive it in a message event
server.broadcast("hello everyone!");

// send a request to all clients. each client will receive it in a request event
server.survey("survey").then(results => {
// returns an array of promise outcomes according to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
});

// all connected clients are accessible in the server.connections array and can be independently interacted with
server.connections.find(connection => connection.id === "someid")?.send("hi");

server.start().catch(console.error);
```
Expand All @@ -67,35 +75,36 @@ server.start().catch(console.error);
const { Client } = require("net-ipc");

const client = new Client({
url:"localhost:8333", // for TCP
//path:"mypath", // for sockets
//compress:true // enable zlib-stream compression (requires installing "fast-zlib")
url: "localhost:8333", // for TCP
// path: "mypath", // for sockets
// compress: true // enable zlib-stream compression (requires installing "fast-zlib")
// reconnect: true // autoreconenct on unnatural disconnections (default true)
// retries: 5 // number of retries in case of unnatural disconnections (default 3)
});

client.on("ready", async data => {
console.log(`established new connection, received id ${data.id} from server`);
await client.send("hi");

let response = await client.request("did you receive this?");
console.log(response) // yes abcdefg

let response2 = await client.request("haha", 1000).catch(e => "no response");
console.log(response2) // no response, the server has no listener for "haha" requests
// send a message to the server
await client.send("execute broadcast").catch(console.error);

await client.send("execute broadcast");

let results = await client.request("run survey");
console.log(results) // [1]
// send a request to the server
// will reject after a timeout if the server does not respond
// will reject immediately if the server does not listen to the request event
let response = await client.request("did you receive this?").catch(e => `oops: ${e}`);
console.log(response);
});

client.on("message", message => {
console.log(message) // hello everyone!
// messages sent by the server via server.broadcast() or connection.send()
console.log(message);
});

client.on("request", async (req, res) => {
if(req === "survey") {
await res(1);
}
client.on("request", (req, res) => {
// requests sent by the server via server.survey() or connection.request()
console.log(`received request from server containing ${req}`);
// res is an async function, will reject if the reply fails
res("response").catch(console.error);
});

client.connect("hi").catch(console.error);
Expand All @@ -105,50 +114,77 @@ client.connect("hi").catch(console.error);
* **`Class Server extends EventEmitter`** - Server class.
* **`Class Client extends EventEmitter`** - Client class.
* **`Class Connection`** - Server-side Client class.
### Server Events
* **`ready -> (address:string)`** - Emitted when the server starts listening.
* **`error -> (Error)`** - Emitted when an error occures. If there is no listener, the error will be swallowed.
* **`connect -> (Client, payload:any)`** - Emitted when a new client connects. Includes the initial payload if one exists.
* **`disconnect -> (Client, reason:any)`** - Emitted when a client disconnects. Includes the reason for disconnect if one exists.
* **`close -> ()`** - Emitted when the server is closed.
* **`message -> (message:any, Client)`** - Emitted when the server receives a message from a client.
* **`request -> (request:any, response:asyncFunction, Client)`** - Emitted when the server receives a request from a client.
* **`error -> (Error, Connection)`** - Emitted when an error occures. If there is no listener, the error will be swallowed to avoid crashing the server.
* **`connect -> (Connection, payload?:any)`** - Emitted when a new client connects. Includes the initial payload if one exists.
* **`disconnect -> (Connection, reason?:any)`** - Emitted when a client disconnects. Includes the reason for disconnect if one exists.
* **`close -> ()`** - Emitted when the server is shut down.
* **`message -> (message:any, Connection)`** - Emitted when the server receives a message from a client.
* **`request -> (request:any, response:asyncFunction, Connection)`** - Emitted when the server receives a request from a client.
### Server Methods
* **`.start() -> promise<Server>`** - Starts the server.
* **`.close() -> promise<Server>`** - Disconnects all clients and closes the server.
* **`.close() -> promise<Server>`** - Gracefully disconnects all clients and closes the server.
* **`.broadcast(data:any) -> promise<void>`** - Sends a message to all clients. Errors will be forwarded to the error event and wont reject the promise.
* **`.survey(data:any, timeout:integer) -> promise<object[]>`** - Sends a request to all clients and waits for them to respond. Returns an array of objects containing promise statuses and results.
* **`.survey(data:any, timeout?:integer) -> promise<object[]>`** - Sends a request to all clients and waits for them to respond. Returns an array of objects containing promise statuses and results. Timeout is 10 seconds by default. Set to 0 to wait forever.
* **`.ping(data:any) -> promise<object[]>`** - Sends a ping request to all clients and waits for them to respond. Returns an array of objects containing the promise statuses and results.
### Server Properties
* **`.connections -> Client[]`** - Array of currently connected clients. Client instances are bidirectional, the same methods can be used from both ends.
* **`.connections -> Connection[]`** - Array of currently connected clients. Connection instances are also Clients and can use the same methods for bidirectional communication.
* **`.options -> object`** - Current server options.
* **`.server -> net.Server`** - Internal instance of net.Server.
### Connection Methods
* **`.send(data:any) -> promise<void>`** - Sends a message to the corresponding client.
* **`.request(data:any, timeout?:integer) -> promise<any>`** - Sends a request to the corresponding client and waits for a response. Timeout is 10 seconds by default. Set to 0 to wait forever.
* **`.ping(data:any) -> promise<integer>`** - Sends a ping request to the corresponding client.
* **`.close(reason:any) -> promise<bool>`** - Finishes all pending jobs then closes the connection.
* **`.destroy(reason:any) -> bool`** - Rejects all pending jobs and closes the connection.
### Connection Properties
* **`.id -> string?`** - The ID assigned to the client by the server after connecting.
* **`.server -> Server`** - Reference to the parent Server instance.
* **`.connection -> net.Client`** - Internal instance of net.Client.
### Client Events
* **`ready -> (response:object)`** - Emitted when the client connects to the server. Includes a server assigned id and compression status.
* **`error -> (error)`** - Emitted when an error occures. If there is no listener, the error will be swallowed.
* **`error -> (error)`** - Emitted when an error occures. If there is no listener, the error will be swallowed but the connection might still be closed depending on the error.
* **`close -> (reason:any)`** - Emitted when the connection is closed. Includes the reason for closing if any.
* **`message -> (message:any, Client)`** - Emitted when the server receives a message from a client.
* **`request -> (request:any, response:asyncFunction, Client)`** - Emitted when the server receives a request from a client.
* **`status -> (status:integer)`** - Emitted when the connection suffers a status change, including disconnections and reconnections.
* **`message -> (message:any)`** - Emitted when the client receives a message from a server.
* **`request -> (request:any, response:asyncFunction)`** - Emitted when the client receives a request from a server.
### Client Methods
* **`.connect(payload:any) -> promise<Client>`** - connects to the server and optionally sends an initial payload.
* **`.send(data:any) -> promise<void>`** - Sends a message to the server.
* **`.request(data:any, timeout:integer) -> promise<any>`** - Sends a request to the server and waits for a response.
* **`.request(data:any, timeout?:integer) -> promise<any>`** - Sends a request to the server and waits for a response. Timeout is 10 seconds by default. Set to 0 to wait forever.
* **`.ping(data:any) -> promise<integer>`** - Sends a ping request to the server.
* **`.close(reason:any) -> promise<bool>`** - Finishes all pending jobs then closes the connection.
* **`.destroy(reason:any) -> bool`** - Rejects all pending jobs and closes the connection.
### Client Properties
* **`.id -> string?`** - The ID assigned to the client by the server after connecting.
* **`.options -> object`** - Current client options.
* **`.status -> integer`** - Current client status.
* **`.connection -> net.Client`** - Internal instance of net.Client.
### Client Statuses
```js
IDLE: 0
CONNECTING: 1
CONNECTED: 2
READY: 3
DISCONNECTED: 4
RECONNECTING: 5
```
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
},
"license": "MIT",
"devDependencies": {
"eslint": "^7.16.0",
"@yarnpkg/pnpify": "^2.4.0"
"eslint": "^7.25.0"
}
}
Loading

0 comments on commit b8f9d80

Please sign in to comment.