Skip to content

Commit a8a3512

Browse files
committed
Updated tests and documentation
1 parent 0192e17 commit a8a3512

21 files changed

Lines changed: 569 additions & 304 deletions

README.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ Features:
99
- 📢 Listen for event dispatched over websocket with simple `on`/`off` event emitter system.
1010
- 💬 Fallback to JSON for easy debugging.
1111

12+
**NEW: experimental Golang port available**
13+
1214
## Requirements
1315

14-
- Node >= v8.0.0
16+
- Node >= v24.0.0
1517

1618
## Installation
1719

@@ -26,8 +28,7 @@ An event is defined by its _unique_ name and the corresponding codec, responsibl
2628

2729
```javascript
2830
// events.js
29-
import UInt8Codec from 'netcode/src/encoder/codec/UInt8Codec';
30-
import StringCodec from 'netcode/src/encoder/codec/StringCodec';
31+
import { UInt8Codec, StringCodec } from 'netcode/encoder';
3132

3233
export default [
3334
['id', new UInt8Codec()],
@@ -53,8 +54,7 @@ We setup a server specifying the port and host on which the server will listen a
5354
Here we use a BinaryEncoder to communicate in binary over websocket, with the previously configured event list.
5455

5556
```javascript
56-
import Server from 'netcode/src/server/Server';
57-
import BinaryEncoder from 'netcode/src/encoder/BinaryEncoder';
57+
import { Server, BinaryEncoder } from 'netcode/server';
5858
import events from './events';
5959

6060
// Listen on localhost:8080
@@ -68,15 +68,14 @@ server.on('client:join', client => {
6868

6969
Now we've got a server running at `localhost:8080` that listen for a `say` text event and send a `id` integer event to every client that connects.
7070

71-
_See an [full example of server setup](demo-server.js)._
71+
_See an [full example of server setup](demo/server.js)._
7272

7373
### Write a Client
7474

7575
Now we write a client, for the browser, that connects to our running server on `ws://localhost:8080` and use a BinaryEncoder with the same event list as the server.
7676

7777
```javascript
78-
import Client from 'netcode/src/client/Client';
79-
import BinaryEncoder from 'netcode/src/encoder/BinaryEncoder';
78+
import { Client, BinaryEncoder } from 'netcode/client';
8079
import events from './events';
8180

8281
const client = new Client('ws://localhost:8080', new BinaryEncoder(events))
@@ -91,7 +90,7 @@ Now we've got client that listen for the `id` event and sent a sentence in a `sa
9190

9291
Connection is alive and well!
9392

94-
_See an [full example of client setup](demo-client.js)._
93+
_See an [full example of client setup](demo/client.js)._
9594

9695
## Complete documentation
9796

demo/client.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Client, BinaryEncoder, UInt8Codec, UIntLongCodec, BooleanCodec, StringLongCodec } from 'netcode/client';
1+
import { Client, BinaryEncoder, UInt8Codec, UIntLongCodec, Int16Codec, BooleanCodec, StringLongCodec } from 'netcode/client';
22

33
window.addEventListener('load', () => {
44
const target = document.getElementById('output');
@@ -19,6 +19,7 @@ window.addEventListener('load', () => {
1919
['inverse', new BooleanCodec()],
2020
['greeting', new StringLongCodec()],
2121
['total', new UInt8Codec()],
22+
['int16', new Int16Codec()],
2223
]);
2324

2425

@@ -51,6 +52,12 @@ window.addEventListener('load', () => {
5152
console.info(`There is ${total} people connected.`);
5253
});
5354

55+
// Listen for a "int16" event
56+
client.on('int16', ({ detail: value }) => {
57+
console.info(`int16 codec: ${value}.`);
58+
client.send('int16', -32768);
59+
});
60+
5461
// Listen for an "inverse" event
5562
client.on('inverse', ({ detail: status }) => {
5663
// Answer with an "inverse" event
@@ -59,7 +66,6 @@ window.addEventListener('load', () => {
5966

6067
// Send a "greeting" event
6168
client.send('greeting', 'Hello, I\'m client 😊! Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut imperdiet molestie libero, ut sollicitudin tortor dignissim quis. Nulla iaculis nisi turpis, a malesuada nibh faucibus a. Nunc tellus lorem, varius sit amet tellus eu, dictum consectetur nulla.');
62-
// client.send('greeting', 'Hi!');
6369
});
6470

6571
// Listen for a "greeting" event
@@ -70,7 +76,7 @@ window.addEventListener('load', () => {
7076
// Listen for oppening connection
7177
client.on('open', () => {
7278
console.info('Connection open.');
73-
setTimeout(() => client.close(1000, 'All good :)'), 20 * 1000);
79+
setTimeout(() => client.close(1000, 'All good :)'), 10 * 1000);
7480
});
7581

7682
// Listen for connection close

demo/server.go

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -21,85 +21,88 @@ func main() {
2121

2222
encoder := netcode.CreateBinaryEncoder([]*netcode.RegisteredCodec{
2323
{0, "id", netcode.UInt8Codec{}},
24-
{1, "ping", netcode.UIntLongCodec{6}},
25-
{2, "pong", netcode.UIntLongCodec{6}},
26-
{3, "inverse", netcode.BooleanCodec{}},
27-
{4, "greeting", netcode.StringLongCodec{}},
28-
{5, "total", netcode.UInt8Codec{}},
24+
{0, "ping", netcode.UIntLongCodec{6}},
25+
{0, "pong", netcode.UIntLongCodec{6}},
26+
{0, "inverse", netcode.BooleanCodec{}},
27+
{0, "greeting", netcode.StringLongCodec{}},
28+
{0, "total", netcode.UInt8Codec{}},
29+
{0, "int16", netcode.Int16Codec{}},
2930
}, netcode.UInt8Codec{})
3031

31-
demo := Demo{
32+
d := Demo{
3233
netcode.CreateSockets(encoder, uint(math.Pow(2, 8))),
3334
}
3435

35-
go demo.run()
36+
go d.run()
3637

37-
netcode.Start(*port, "/", func(conn *websocket.Conn, request *http.Request) {
38-
socket, err := demo.sockets.Add(conn)
38+
netcode.Start(*port, "/", d.SocketHandler, netcode.CheckOrigin, netcode.ErrorHandler)
39+
}
3940

40-
if err != nil {
41-
log.Fatal(err)
42-
}
41+
func (d *Demo) SocketHandler(w http.ResponseWriter, r *http.Request, c *websocket.Conn) {
42+
socket, err := d.sockets.Add(c)
4343

44-
netcode.CreateBeacon(socket, time.Second*3, func(ping time.Duration) {
45-
log.Printf("Client #%d ping: %s.", socket.ID, ping)
46-
})
44+
if err != nil {
45+
log.Fatal(err)
46+
}
4747

48-
demo.onClientJoin(socket)
48+
netcode.CreateBeacon(socket, time.Second*3, func(ping time.Duration) {
49+
log.Printf("Client #%d ping: %s.", socket.ID, ping)
4950
})
51+
52+
d.onClientJoin(socket)
5053
}
5154

52-
func (demo *Demo) run() {
55+
func (d *Demo) run() {
5356
log.Printf("Demo is running")
5457
for {
5558
select {
56-
case m := <-demo.sockets.In:
59+
case m := <-d.sockets.In:
5760
switch m.Message.Name {
5861
case "ping":
59-
demo.handlePing(m.Socket, m.Message)
62+
d.handlePing(m.Socket, m.Message)
6063
case "greeting":
61-
demo.handleGreeting(m.Socket, m.Message)
64+
d.handleGreeting(m.Socket, m.Message)
65+
case "int16":
66+
d.handleInt16(m.Socket, m.Message)
6267
default:
6368
log.Printf("[socket #%d] '%s': %v", m.Socket.ID, m.Message.Name, m.Message.Data)
6469
}
65-
case socket := <-demo.sockets.Out:
66-
demo.onClientLeave(socket)
67-
// switch e.Name {
68-
// case "socket:join":
69-
// demo.onClientJoin(e.Data.(*netcode.Socket))
70-
// case "socket:leave":
71-
// demo.onClientLeave(e.Data.(*netcode.Socket))
72-
// default:
73-
// log.Printf("event '%s': %v", e.Name, e.Data)
74-
// }
70+
case socket := <-d.sockets.Out:
71+
d.onClientLeave(socket)
7572
}
7673
}
7774
}
7875

79-
func (demo *Demo) broadcastTotal() {
80-
demo.sockets.SendAll(
81-
&netcode.Message{"total", uint8(demo.sockets.Count())},
76+
func (d *Demo) broadcastTotal() {
77+
d.sockets.SendAll(
78+
&netcode.Message{"total", uint8(d.sockets.Count())},
8279
)
8380
}
8481

85-
func (demo *Demo) onClientJoin(s *netcode.Socket) {
82+
func (d *Demo) onClientJoin(s *netcode.Socket) {
8683
log.Printf("Client #%d joined.", s.ID)
8784
s.Send(&netcode.Message{"id", uint8(s.ID)})
88-
demo.broadcastTotal()
85+
d.broadcastTotal()
86+
87+
s.Send(&netcode.Message{"int16", int16(math.MaxInt16)})
8988
}
9089

91-
func (demo *Demo) onClientLeave(s *netcode.Socket) {
90+
func (d *Demo) onClientLeave(s *netcode.Socket) {
9291
log.Printf("Client #%d left.", s.ID)
93-
demo.broadcastTotal()
92+
d.broadcastTotal()
9493
}
9594

96-
func (demo *Demo) handlePing(s *netcode.Socket, m *netcode.Message) {
97-
log.Printf("Client #%d ping: %d.", s.ID, m.Data)
95+
func (d *Demo) handlePing(s *netcode.Socket, m *netcode.Message) {
96+
log.Printf("Client #%d ping: %d.", s.ID, m.Data.(uint))
9897
s.Send(&netcode.Message{"pong", uint(time.Now().UnixMilli())})
9998
s.Send(&netcode.Message{"inverse", true})
10099
}
101100

102-
func (demo *Demo) handleGreeting(s *netcode.Socket, m *netcode.Message) {
103-
log.Printf("Client #%d greets you: '%s'.", s.ID, m.Data)
101+
func (d *Demo) handleGreeting(s *netcode.Socket, m *netcode.Message) {
102+
log.Printf("Client #%d greets you: '%s'.", s.ID, m.Data.(string))
104103
s.Send(&netcode.Message{"greeting", "Hello, I'm server! 😊 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut imperdiet molestie libero, ut sollicitudin tortor dignissim quis. Nulla iaculis nisi turpis, a malesuada nibh faucibus a. Nunc tellus lorem, varius sit amet tellus eu, dictum consectetur nulla."})
105104
}
105+
106+
func (d *Demo) handleInt16(s *netcode.Socket, m *netcode.Message) {
107+
log.Printf("Client #%d sends int16: %d.", s.ID, m.Data.(int16))
108+
}

demo/server.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
BinaryEncoder,
44
UInt8Codec,
55
UIntLongCodec,
6+
Int16Codec,
67
BooleanCodec,
78
StringLongCodec,
89
} from 'netcode/server';
@@ -15,6 +16,7 @@ const encoder = new BinaryEncoder([
1516
['inverse', new BooleanCodec()],
1617
['greeting', new StringLongCodec()],
1718
['total', new UInt8Codec()],
19+
['int16', new Int16Codec()],
1820
]);
1921

2022
// Create the server
@@ -47,10 +49,17 @@ server.on('client:join', client => {
4749
client.send('greeting', 'Hello, I\'m server! 😊 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut imperdiet molestie libero, ut sollicitudin tortor dignissim quis. Nulla iaculis nisi turpis, a malesuada nibh faucibus a. Nunc tellus lorem, varius sit amet tellus eu, dictum consectetur nulla.');
4850
});
4951

52+
// Listen for "int16" event
53+
client.on('int16', message => {
54+
console.info('Client %s sends int16: %s', client.id, message);
55+
});
56+
5057
// Send event "id" to the client
5158
client.send('id', client.id);
5259

5360
broadcastTotal();
61+
62+
client.send('int16', 32767);
5463
});
5564

5665
// Listen for disconnecting clients

doc/API.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ The `Server` class takes the following arguments:
99
| port | _Number_ | 8080 | Port to listen on. |
1010
| host | _String_ | 0.0.0.0 | Host to listen on. |
1111
| encoder | _BinaryEncoder \| JsonEncoder_ | new JsonEncoder() | Encoder to use to read/write event messages. |
12-
| ping | _Number_ | 30 | Ping frequency in seconds (0 for no ping). |
13-
| maxLength | _Number_ | 512 | Paquet max length in bit (should be a power of two). |
14-
| protocols | _Array String[]_ | `['websocket']` | Protocols tu use |
12+
| pingInterval | _Number_ | 30 | Ping frequency in seconds (0 for no ping). |
13+
| maxPayload | _Number_ | 512 | Paquet max length in bit (should be a power of two). |
14+
| clients | _ClientDirectory_ | `new MapClientDirectory()` | Client directory |
15+
| autoStart | _Boolean_ | `true` | Should the server start listening immediatly? |
1516

1617
### Methods
1718

@@ -27,8 +28,6 @@ Listen for event.
2728

2829
Remove listener for this event / callback.
2930

30-
_Note: If you're on node `< 10.0.0`, use `removeListener` method instead of `off`_
31-
3231
### Events
3332

3433
| Name | Callback parameters | Description |
@@ -76,4 +75,4 @@ _Note: If you're on node `< 10.0.0`, use `removeListener` method instead of `off
7675
| `close` | client _{Client_} | Client connection is closed. |
7776
| * | - eventData _{Number\|String\|Boolean\|Object}_<br />- client _Client_ | Every event sent through the websocket pipe will emit an event on the other end of the socket. |
7877

79-
_Note: `open`, `error` and `close` are reserved event names and the Encoder will throw an exeption if you define a custom event with either of these names._
78+
_Note: `open`, `error` and `close` are reserved event names and the Encoder will throw an exeption if you define a custom event with either of these names._

doc/codecs.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,20 @@ Packaged codecs are available in the `netcode/server` and `netcode/client` packa
1010

1111
| Class | Data format | Example | Size (in byte) |
1212
| -------------------------- | ---------------------------------- | ------------------------------------------------------------ | ----------------------- |
13-
| `Codec` | No data (just send the event name) | `['pause', new Codec()]`<br />`send('pause')` | 0 |
14-
| `BooleanCodec` | `true\|false` | `['active', new BooleanCodec()]`<br />`send('active', true)` | 1 |
15-
| `StringCodec` | String up to 255 characters | `['player:name', new StringCodec()]`<br />`send('player:name', 'DarkShadow73')` | 1 + (String length * 2) |
16-
| `StringLongCodec` | String up to 65536 characters | `['url', new StringLongCodec()]`<br />`send('url', 'https://my.long.url/hash/xxx...')` | 2 + (String length * 2) |
13+
| `NullCodec` | No data (just send the event name) | `['pause', new NullCodec()]`<br />`send('pause')` | 0 |
14+
| `BooleanCodec` | `true\|false` | `['active', new BooleanCodec()]`<br />`send('active', true)` | |
1715
| `UInt8Codec` | Integer from 0 to 255 | `['id', new UInt8Codec()]`<br />`send('id', 42)` | 1 |
1816
| `UInt16Codec` | Integer from 0 to 65536 | `['score', new UInt16Codec()]`<br />`send('score', 9999)` | 2 |
1917
| `UInt32Codec` | Integer from 0 to 4294967295 | `['position', new UInt32Codec()]`<br />`send('position', 4294967295)` | 4 |
2018
| `UIntLongCodec(byteLength)` | Integer encoded as string | `['timestamp', new UIntLongCodec(13)`]<br />`send('timestamp', Date.now())` | byteLength |
19+
| `Int8Codec` | Integer from -128 to 127 | `['value', new Int8Codec()]`<br />`send('value', -42)` | 1 |
20+
| `Int16Codec` | Integer from -32768 to 32767 | `['malus', new Int16Codec()]`<br />`send('malus', -999)` | 2 |
21+
| `Int32Codec` | Integer from -2147483648 to 2147483647 | `['position', new Int32Codec()]`<br />`send('position', -123456)` | 4 |1 |
22+
| `Float32Codec`<br />⚠ Subject to precision issues | Float on 32bit | `['position', new Float32Codec()]`<br />`send('position', 84.19999694824219)` | 4 |
23+
| `Float64Codec` | Float on 64bit | `['position', new Float64Codec()]`<br />`send('position', -12456789.123456789087654321012345678901)` | 2 |
24+
| `FloatPrecisionCodec(IntCodec, precision)` | Float encoded as int | `['position', FloatPrecisionCodec(Int8Codec, 3)]`<br />`send('position', -0.657)` | 2
25+
| `StringCodec` | String up to 255 characters | `['player:name', new StringCodec()]`<br />`send('player:name', 'DarkShadow73')` | 1 + (String length * 2) |
26+
| `StringLongCodec` | String up to 65536 characters | `['url', new StringLongCodec()]`<br />`send('url', 'https://my.long.url/hash/xxx...')` | 2 + (String length * 2) |
2127

2228
## Custom codecs
2329

doc/go.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Go port
2+
3+
Netcode server is also available in Golang.
4+
5+
It's fully compatible with the netcode browser client.
6+
7+
## Current features
8+
9+
- [x] Server
10+
- [x] Sockets (equivalent of Client / Client Directory)
11+
- [x] Binary encoder
12+
- [ ] Json encoder
13+
- [x] Packaged codecs (compatible with javascript codec)
14+
- [x] Beacon (ping at regular interval)
15+
16+
## Notes
17+
18+
Netcode in golang is relying on [github.com/gorilla/websocket](github.com/gorilla/websocket) for Websocket implementation.

0 commit comments

Comments
 (0)