기능: 브라우저 WebSocket 진입점을 추가한다
브라우저 번들에서 Node 전용 ws 의존성을 분리하고 Go 모듈 경로를 현재 저장소명과 맞추기 위해 진입점과 import 경로를 정리한다.
This commit is contained in:
parent
9872ebac87
commit
8daf53003d
49 changed files with 574 additions and 133 deletions
|
|
@ -107,8 +107,8 @@ import (
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
protoSocket "git.toki-labs.com/toki/common-proto-socket/go"
|
protoSocket "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parserMap() protoSocket.ParserMap {
|
func parserMap() protoSocket.ParserMap {
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ const PacketBase$json = {
|
||||||
|
|
||||||
/// Descriptor for `PacketBase`. Decode as a `google.protobuf.DescriptorProto`.
|
/// Descriptor for `PacketBase`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
final $typed_data.Uint8List packetBaseDescriptor = $convert.base64Decode(
|
final $typed_data.Uint8List packetBaseDescriptor = $convert.base64Decode(
|
||||||
'CgpQYWNrZXRCYXNlEhoKCHR5cGVOYW1lGAEgASgJUgh0eXBlTmFtZRIUCgVub25jZRgCIAEoBVIF'
|
'CgpQYWNrZXRCYXNlEhoKCHR5cGVOYW1lGAEgASgJUgh0eXBlTmFtZRIUCgVub25jZRgCIAEoBV'
|
||||||
'bm9uY2USEgoEZGF0YRgDIAEoDFIEZGF0YRIkCg1yZXNwb25zZU5vbmNlGAQgASgFUg1yZXNwb25z'
|
'IFbm9uY2USEgoEZGF0YRgDIAEoDFIEZGF0YRIkCg1yZXNwb25zZU5vbmNlGAQgASgFUg1yZXNw'
|
||||||
'ZU5vbmNl');
|
'b25zZU5vbmNl');
|
||||||
|
|
||||||
@$core.Deprecated('Use heartBeatDescriptor instead')
|
@$core.Deprecated('Use heartBeatDescriptor instead')
|
||||||
const HeartBeat$json = {
|
const HeartBeat$json = {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ git config --global url."https://toki@git.toki-labs.com/".insteadOf "https://git
|
||||||
## Install Or Update
|
## Install Or Update
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go get git.toki-labs.com/toki/common-proto-socket/go@latest
|
go get git.toki-labs.com/toki/proto-socket/go@latest
|
||||||
go mod tidy
|
go mod tidy
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ module example.com/proto-socket-go-consumer
|
||||||
|
|
||||||
go 1.22
|
go 1.22
|
||||||
|
|
||||||
require git.toki-labs.com/toki/common-proto-socket/go v0.0.0-20260501220005-284b66a22300
|
require git.toki-labs.com/toki/proto-socket/go v0.0.0-20260501220005-284b66a22300
|
||||||
|
|
||||||
require (
|
require (
|
||||||
google.golang.org/protobuf v1.36.5 // indirect
|
google.golang.org/protobuf v1.36.5 // indirect
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
git.toki-labs.com/toki/common-proto-socket/go v0.0.0-20260501220005-284b66a22300 h1:wvESR2WEz1yPqWRGZB2ORUewbI2K71++zOKyfpHcAkc=
|
|
||||||
git.toki-labs.com/toki/common-proto-socket/go v0.0.0-20260501220005-284b66a22300/go.mod h1:rEQJuwkoWQgOHXU4ijUinhhNzq92f+xzAkHti3CD3pA=
|
|
||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
protoSocket "git.toki-labs.com/toki/common-proto-socket/go"
|
protoSocket "git.toki-labs.com/toki/proto-socket/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrNotConnected = errors.New("not connected")
|
var ErrNotConnected = errors.New("not connected")
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
type nonceTestTransport struct {
|
type nonceTestTransport struct {
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ import (
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import (
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import (
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import (
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import (
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ import (
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ import (
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ import (
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
module git.toki-labs.com/toki/common-proto-socket/go
|
module git.toki-labs.com/toki/proto-socket/go
|
||||||
|
|
||||||
go 1.22
|
go 1.22
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ const file_packets_message_common_proto_rawDesc = "" +
|
||||||
"\tHeartBeat\":\n" +
|
"\tHeartBeat\":\n" +
|
||||||
"\bTestData\x12\x14\n" +
|
"\bTestData\x12\x14\n" +
|
||||||
"\x05index\x18\x01 \x01(\x05R\x05index\x12\x18\n" +
|
"\x05index\x18\x01 \x01(\x05R\x05index\x12\x18\n" +
|
||||||
"\amessage\x18\x02 \x01(\tR\amessageB7Z5git.toki-labs.com/toki/common-proto-socket/go/packetsb\x06proto3"
|
"\amessage\x18\x02 \x01(\tR\amessageB0Z.git.toki-labs.com/toki/proto-socket/go/packetsb\x06proto3"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_packets_message_common_proto_rawDescOnce sync.Once
|
file_packets_message_common_proto_rawDescOnce sync.Once
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
option go_package = "git.toki-labs.com/toki/common-proto-socket/go/packets";
|
option go_package = "git.toki-labs.com/toki/proto-socket/go/packets";
|
||||||
|
|
||||||
message PacketBase {
|
message PacketBase {
|
||||||
string typeName = 1;
|
string typeName = 1;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const MaxPacketSize = 64 << 20
|
const MaxPacketSize = 64 << 20
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import (
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fakeTransport struct {
|
type fakeTransport struct {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHeartbeatDisconnectsWithoutResponse(t *testing.T) {
|
func TestHeartbeatDisconnectsWithoutResponse(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTcpRequestResponse(t *testing.T) {
|
func TestTcpRequestResponse(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTypeNameMatchesDartConvention(t *testing.T) {
|
func TestTypeNameMatchesDartConvention(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import (
|
||||||
|
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTLSTcp(t *testing.T) {
|
func TestTLSTcp(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ import (
|
||||||
|
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
|
|
||||||
toki "git.toki-labs.com/toki/common-proto-socket/go"
|
toki "git.toki-labs.com/toki/proto-socket/go"
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWsRequestResponse(t *testing.T) {
|
func TestWsRequestResponse(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
|
|
||||||
"git.toki-labs.com/toki/common-proto-socket/go/packets"
|
"git.toki-labs.com/toki/proto-socket/go/packets"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,29 @@ This package implements Proto Socket protocol version `0.1` for TypeScript.
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
- Runtime targets: Node.js TCP, Node.js WebSocket, browser-friendly core types.
|
- Runtime targets: Node.js TCP, Node.js WebSocket, browser native WebSocket.
|
||||||
- Currently in scope: `Communicator`, `BaseClient`, TCP/WS client and server helpers, Go cross-language tests.
|
- Browser entrypoint (`proto-socket`): `Communicator`, `BaseClient`, `BrowserWsClient`, `connectBrowserWs`. Has no `ws`, `node:*`, or `Buffer` dependency.
|
||||||
- Out of scope for this iteration: TLS+TCP, WSS, browser WebSocket transport wrapper.
|
- Node entrypoint (`proto-socket/node`): all of the above plus `TcpClient`/`TcpServer`, `NodeWsClient`/`NodeWsServer`, `connectNodeWs`/`connectNodeWss`.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// browser
|
||||||
|
import { connectBrowserWs } from "proto-socket";
|
||||||
|
|
||||||
|
// node
|
||||||
|
import { connectNodeWs, NodeWsServer, TcpClient } from "proto-socket/node";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Runtime Dependencies
|
||||||
|
|
||||||
|
`ws` is declared as an optional peer dependency. Install it only when using the Node WebSocket entrypoint (`NodeWsClient`/`NodeWsServer`/`connectNodeWs`/`connectNodeWss`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install ws
|
||||||
|
```
|
||||||
|
|
||||||
|
The browser entrypoint and Node TCP-only consumers do not need `ws`.
|
||||||
|
|
||||||
## Proto Generation
|
## Proto Generation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
||||||
} from "../src/communicator.js";
|
} from "../src/communicator.js";
|
||||||
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
||||||
import { connectTcp, connectTcpTls } from "../src/tcp_client.js";
|
import { connectTcp, connectTcpTls } from "../src/tcp_client.js";
|
||||||
import { connectWs, connectWss } from "../src/ws_client.js";
|
import { connectNodeWs, connectNodeWss } from "../src/node_ws_client.js";
|
||||||
|
|
||||||
const HOST = "127.0.0.1";
|
const HOST = "127.0.0.1";
|
||||||
const WS_PATH = "/";
|
const WS_PATH = "/";
|
||||||
|
|
@ -101,7 +101,7 @@ async function dial(mode: Mode, port: number, cert?: string): Promise<BaseClient
|
||||||
return connectTcp(HOST, port, 0, 0, parserMap);
|
return connectTcp(HOST, port, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
if (mode === "ws") {
|
if (mode === "ws") {
|
||||||
return connectWs(HOST, port, WS_PATH, 0, 0, parserMap);
|
return connectNodeWs(HOST, port, WS_PATH, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
if (cert === undefined || cert.length === 0) {
|
if (cert === undefined || cert.length === 0) {
|
||||||
throw new Error(`--cert is required for ${mode} mode`);
|
throw new Error(`--cert is required for ${mode} mode`);
|
||||||
|
|
@ -110,7 +110,7 @@ async function dial(mode: Mode, port: number, cert?: string): Promise<BaseClient
|
||||||
if (mode === "tls") {
|
if (mode === "tls") {
|
||||||
return connectTcpTls(HOST, port, { ca }, 0, 0, parserMap);
|
return connectTcpTls(HOST, port, { ca }, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
return connectWss(HOST, port, WS_PATH, { ca }, 0, 0, parserMap);
|
return connectNodeWss(HOST, port, WS_PATH, { ca }, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runSendPush(client: BaseClient): Promise<boolean> {
|
async function runSendPush(client: BaseClient): Promise<boolean> {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
||||||
} from "../src/communicator.js";
|
} from "../src/communicator.js";
|
||||||
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
||||||
import { connectTcp, connectTcpTls } from "../src/tcp_client.js";
|
import { connectTcp, connectTcpTls } from "../src/tcp_client.js";
|
||||||
import { connectWs, connectWss } from "../src/ws_client.js";
|
import { connectNodeWs, connectNodeWss } from "../src/node_ws_client.js";
|
||||||
|
|
||||||
const HOST = "127.0.0.1";
|
const HOST = "127.0.0.1";
|
||||||
const WS_PATH = "/";
|
const WS_PATH = "/";
|
||||||
|
|
@ -101,7 +101,7 @@ async function dial(mode: Mode, port: number, cert?: string): Promise<BaseClient
|
||||||
return connectTcp(HOST, port, 0, 0, parserMap);
|
return connectTcp(HOST, port, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
if (mode === "ws") {
|
if (mode === "ws") {
|
||||||
return connectWs(HOST, port, WS_PATH, 0, 0, parserMap);
|
return connectNodeWs(HOST, port, WS_PATH, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
if (cert === undefined || cert.length === 0) {
|
if (cert === undefined || cert.length === 0) {
|
||||||
throw new Error(`--cert is required for ${mode} mode`);
|
throw new Error(`--cert is required for ${mode} mode`);
|
||||||
|
|
@ -110,7 +110,7 @@ async function dial(mode: Mode, port: number, cert?: string): Promise<BaseClient
|
||||||
if (mode === "tls") {
|
if (mode === "tls") {
|
||||||
return connectTcpTls(HOST, port, { ca }, 0, 0, parserMap);
|
return connectTcpTls(HOST, port, { ca }, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
return connectWss(HOST, port, WS_PATH, { ca }, 0, 0, parserMap);
|
return connectNodeWss(HOST, port, WS_PATH, { ca }, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runSendPush(client: BaseClient): Promise<boolean> {
|
async function runSendPush(client: BaseClient): Promise<boolean> {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
||||||
} from "../src/communicator.js";
|
} from "../src/communicator.js";
|
||||||
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
||||||
import { connectTcp, connectTcpTls } from "../src/tcp_client.js";
|
import { connectTcp, connectTcpTls } from "../src/tcp_client.js";
|
||||||
import { connectWs, connectWss } from "../src/ws_client.js";
|
import { connectNodeWs, connectNodeWss } from "../src/node_ws_client.js";
|
||||||
|
|
||||||
const HOST = "127.0.0.1";
|
const HOST = "127.0.0.1";
|
||||||
const WS_PATH = "/";
|
const WS_PATH = "/";
|
||||||
|
|
@ -103,7 +103,7 @@ async function dial(mode: Mode, port: number, cert?: string): Promise<BaseClient
|
||||||
return connectTcp(HOST, port, 0, 0, parserMap);
|
return connectTcp(HOST, port, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
if (mode === "ws") {
|
if (mode === "ws") {
|
||||||
return connectWs(HOST, port, WS_PATH, 0, 0, parserMap);
|
return connectNodeWs(HOST, port, WS_PATH, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
if (cert === undefined || cert.length === 0) {
|
if (cert === undefined || cert.length === 0) {
|
||||||
throw new Error(`--cert is required for ${mode} mode`);
|
throw new Error(`--cert is required for ${mode} mode`);
|
||||||
|
|
@ -112,7 +112,7 @@ async function dial(mode: Mode, port: number, cert?: string): Promise<BaseClient
|
||||||
if (mode === "tls") {
|
if (mode === "tls") {
|
||||||
return connectTcpTls(HOST, port, { ca }, 0, 0, parserMap);
|
return connectTcpTls(HOST, port, { ca }, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
return connectWss(HOST, port, WS_PATH, { ca }, 0, 0, parserMap);
|
return connectNodeWss(HOST, port, WS_PATH, { ca }, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runSendPush(client: BaseClient): Promise<boolean> {
|
async function runSendPush(client: BaseClient): Promise<boolean> {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
||||||
} from "../src/communicator.js";
|
} from "../src/communicator.js";
|
||||||
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
||||||
import { connectTcp, connectTcpTls } from "../src/tcp_client.js";
|
import { connectTcp, connectTcpTls } from "../src/tcp_client.js";
|
||||||
import { connectWs, connectWss } from "../src/ws_client.js";
|
import { connectNodeWs, connectNodeWss } from "../src/node_ws_client.js";
|
||||||
|
|
||||||
const HOST = "127.0.0.1";
|
const HOST = "127.0.0.1";
|
||||||
const WS_PATH = "/";
|
const WS_PATH = "/";
|
||||||
|
|
@ -101,7 +101,7 @@ async function dial(mode: Mode, port: number, cert?: string): Promise<BaseClient
|
||||||
return connectTcp(HOST, port, 0, 0, parserMap);
|
return connectTcp(HOST, port, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
if (mode === "ws") {
|
if (mode === "ws") {
|
||||||
return connectWs(HOST, port, WS_PATH, 0, 0, parserMap);
|
return connectNodeWs(HOST, port, WS_PATH, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
if (cert === undefined || cert.length === 0) {
|
if (cert === undefined || cert.length === 0) {
|
||||||
throw new Error(`--cert is required for ${mode} mode`);
|
throw new Error(`--cert is required for ${mode} mode`);
|
||||||
|
|
@ -110,7 +110,7 @@ async function dial(mode: Mode, port: number, cert?: string): Promise<BaseClient
|
||||||
if (mode === "tls") {
|
if (mode === "tls") {
|
||||||
return connectTcpTls(HOST, port, { ca }, 0, 0, parserMap);
|
return connectTcpTls(HOST, port, { ca }, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
return connectWss(HOST, port, WS_PATH, { ca }, 0, 0, parserMap);
|
return connectNodeWss(HOST, port, WS_PATH, { ca }, 0, 0, parserMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runSendPush(client: BaseClient): Promise<boolean> {
|
async function runSendPush(client: BaseClient): Promise<boolean> {
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ import {
|
||||||
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
||||||
import { TcpClient } from "../src/tcp_client.js";
|
import { TcpClient } from "../src/tcp_client.js";
|
||||||
import { TcpServer } from "../src/tcp_server.js";
|
import { TcpServer } from "../src/tcp_server.js";
|
||||||
import { WsClient } from "../src/ws_client.js";
|
import { NodeWsClient } from "../src/node_ws_client.js";
|
||||||
import { WsServer } from "../src/ws_server.js";
|
import { NodeWsServer } from "../src/node_ws_server.js";
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const repoRoot = path.resolve(path.dirname(__filename), "../..");
|
const repoRoot = path.resolve(path.dirname(__filename), "../..");
|
||||||
|
|
@ -121,7 +121,7 @@ async function runWsSendPush(): Promise<void> {
|
||||||
const received = new Promise<boolean>((resolve) => {
|
const received = new Promise<boolean>((resolve) => {
|
||||||
resolveReceived = resolve;
|
resolveReceived = resolve;
|
||||||
});
|
});
|
||||||
const server = new WsServer(HOST, WS_PORT, WS_PATH, (ws) => new WsClient(ws, 0, 0, parserMap()));
|
const server = new NodeWsServer(HOST, WS_PORT, WS_PATH, (ws) => new NodeWsClient(ws, 0, 0, parserMap()));
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
addListenerTyped(client.communicator, TestDataSchema, (data) => {
|
addListenerTyped(client.communicator, TestDataSchema, (data) => {
|
||||||
console.log(`SERVER_RECEIVED index=${data.index} message=${data.message}`);
|
console.log(`SERVER_RECEIVED index=${data.index} message=${data.message}`);
|
||||||
|
|
@ -150,7 +150,7 @@ async function runWsSendPush(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runWsRequests(): Promise<void> {
|
async function runWsRequests(): Promise<void> {
|
||||||
const server = new WsServer(HOST, WS_PORT, WS_PATH, (ws) => new WsClient(ws, 0, 0, parserMap()));
|
const server = new NodeWsServer(HOST, WS_PORT, WS_PATH, (ws) => new NodeWsClient(ws, 0, 0, parserMap()));
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
addRequestListenerTyped(client.communicator, TestDataSchema, (req) =>
|
addRequestListenerTyped(client.communicator, TestDataSchema, (req) =>
|
||||||
create(TestDataSchema, {
|
create(TestDataSchema, {
|
||||||
|
|
@ -223,11 +223,11 @@ async function runWssSendPush(): Promise<void> {
|
||||||
const received = new Promise<boolean>((resolve) => {
|
const received = new Promise<boolean>((resolve) => {
|
||||||
resolveReceived = resolve;
|
resolveReceived = resolve;
|
||||||
});
|
});
|
||||||
const server = new WsServer(
|
const server = new NodeWsServer(
|
||||||
HOST,
|
HOST,
|
||||||
WSS_PORT,
|
WSS_PORT,
|
||||||
WS_PATH,
|
WS_PATH,
|
||||||
(ws) => new WsClient(ws, 0, 0, parserMap()),
|
(ws) => new NodeWsClient(ws, 0, 0, parserMap()),
|
||||||
serverTlsOptions(),
|
serverTlsOptions(),
|
||||||
);
|
);
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
|
|
@ -258,11 +258,11 @@ async function runWssSendPush(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runWssRequests(): Promise<void> {
|
async function runWssRequests(): Promise<void> {
|
||||||
const server = new WsServer(
|
const server = new NodeWsServer(
|
||||||
HOST,
|
HOST,
|
||||||
WSS_PORT,
|
WSS_PORT,
|
||||||
WS_PATH,
|
WS_PATH,
|
||||||
(ws) => new WsClient(ws, 0, 0, parserMap()),
|
(ws) => new NodeWsClient(ws, 0, 0, parserMap()),
|
||||||
serverTlsOptions(),
|
serverTlsOptions(),
|
||||||
);
|
);
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ import {
|
||||||
import { TestDataSchema } from "../src/packets/message_common_pb.js";
|
import { TestDataSchema } from "../src/packets/message_common_pb.js";
|
||||||
import { TcpClient } from "../src/tcp_client.js";
|
import { TcpClient } from "../src/tcp_client.js";
|
||||||
import { TcpServer } from "../src/tcp_server.js";
|
import { TcpServer } from "../src/tcp_server.js";
|
||||||
import { WsClient } from "../src/ws_client.js";
|
import { NodeWsClient } from "../src/node_ws_client.js";
|
||||||
import { WsServer } from "../src/ws_server.js";
|
import { NodeWsServer } from "../src/node_ws_server.js";
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const repoRoot = path.resolve(path.dirname(__filename), "../..");
|
const repoRoot = path.resolve(path.dirname(__filename), "../..");
|
||||||
|
|
@ -121,7 +121,7 @@ async function runWsSendPush(): Promise<void> {
|
||||||
const received = new Promise<boolean>((resolve) => {
|
const received = new Promise<boolean>((resolve) => {
|
||||||
resolveReceived = resolve;
|
resolveReceived = resolve;
|
||||||
});
|
});
|
||||||
const server = new WsServer(HOST, WS_PORT, WS_PATH, (ws) => new WsClient(ws, 0, 0, parserMap()));
|
const server = new NodeWsServer(HOST, WS_PORT, WS_PATH, (ws) => new NodeWsClient(ws, 0, 0, parserMap()));
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
addListenerTyped(client.communicator, TestDataSchema, (data) => {
|
addListenerTyped(client.communicator, TestDataSchema, (data) => {
|
||||||
console.log(`SERVER_RECEIVED index=${data.index} message=${data.message}`);
|
console.log(`SERVER_RECEIVED index=${data.index} message=${data.message}`);
|
||||||
|
|
@ -150,7 +150,7 @@ async function runWsSendPush(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runWsRequests(): Promise<void> {
|
async function runWsRequests(): Promise<void> {
|
||||||
const server = new WsServer(HOST, WS_PORT, WS_PATH, (ws) => new WsClient(ws, 0, 0, parserMap()));
|
const server = new NodeWsServer(HOST, WS_PORT, WS_PATH, (ws) => new NodeWsClient(ws, 0, 0, parserMap()));
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
addRequestListenerTyped(client.communicator, TestDataSchema, (req) =>
|
addRequestListenerTyped(client.communicator, TestDataSchema, (req) =>
|
||||||
create(TestDataSchema, {
|
create(TestDataSchema, {
|
||||||
|
|
@ -223,11 +223,11 @@ async function runWssSendPush(): Promise<void> {
|
||||||
const received = new Promise<boolean>((resolve) => {
|
const received = new Promise<boolean>((resolve) => {
|
||||||
resolveReceived = resolve;
|
resolveReceived = resolve;
|
||||||
});
|
});
|
||||||
const server = new WsServer(
|
const server = new NodeWsServer(
|
||||||
HOST,
|
HOST,
|
||||||
WSS_PORT,
|
WSS_PORT,
|
||||||
WS_PATH,
|
WS_PATH,
|
||||||
(ws) => new WsClient(ws, 0, 0, parserMap()),
|
(ws) => new NodeWsClient(ws, 0, 0, parserMap()),
|
||||||
serverTlsOptions(),
|
serverTlsOptions(),
|
||||||
);
|
);
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
|
|
@ -258,11 +258,11 @@ async function runWssSendPush(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runWssRequests(): Promise<void> {
|
async function runWssRequests(): Promise<void> {
|
||||||
const server = new WsServer(
|
const server = new NodeWsServer(
|
||||||
HOST,
|
HOST,
|
||||||
WSS_PORT,
|
WSS_PORT,
|
||||||
WS_PATH,
|
WS_PATH,
|
||||||
(ws) => new WsClient(ws, 0, 0, parserMap()),
|
(ws) => new NodeWsClient(ws, 0, 0, parserMap()),
|
||||||
serverTlsOptions(),
|
serverTlsOptions(),
|
||||||
);
|
);
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ import {
|
||||||
import { TestDataSchema } from "../src/packets/message_common_pb.js";
|
import { TestDataSchema } from "../src/packets/message_common_pb.js";
|
||||||
import { TcpClient } from "../src/tcp_client.js";
|
import { TcpClient } from "../src/tcp_client.js";
|
||||||
import { TcpServer } from "../src/tcp_server.js";
|
import { TcpServer } from "../src/tcp_server.js";
|
||||||
import { WsClient } from "../src/ws_client.js";
|
import { NodeWsClient } from "../src/node_ws_client.js";
|
||||||
import { WsServer } from "../src/ws_server.js";
|
import { NodeWsServer } from "../src/node_ws_server.js";
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const repoRoot = path.resolve(path.dirname(__filename), "../..");
|
const repoRoot = path.resolve(path.dirname(__filename), "../..");
|
||||||
|
|
@ -125,7 +125,7 @@ async function runWsSendPush(): Promise<void> {
|
||||||
const received = new Promise<boolean>((resolve) => {
|
const received = new Promise<boolean>((resolve) => {
|
||||||
resolveReceived = resolve;
|
resolveReceived = resolve;
|
||||||
});
|
});
|
||||||
const server = new WsServer(HOST, WS_PORT, WS_PATH, (ws) => new WsClient(ws, 0, 0, parserMap()));
|
const server = new NodeWsServer(HOST, WS_PORT, WS_PATH, (ws) => new NodeWsClient(ws, 0, 0, parserMap()));
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
addListenerTyped(client.communicator, TestDataSchema, (data) => {
|
addListenerTyped(client.communicator, TestDataSchema, (data) => {
|
||||||
console.log(`SERVER_RECEIVED index=${data.index} message=${data.message}`);
|
console.log(`SERVER_RECEIVED index=${data.index} message=${data.message}`);
|
||||||
|
|
@ -154,7 +154,7 @@ async function runWsSendPush(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runWsRequests(): Promise<void> {
|
async function runWsRequests(): Promise<void> {
|
||||||
const server = new WsServer(HOST, WS_PORT, WS_PATH, (ws) => new WsClient(ws, 0, 0, parserMap()));
|
const server = new NodeWsServer(HOST, WS_PORT, WS_PATH, (ws) => new NodeWsClient(ws, 0, 0, parserMap()));
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
addRequestListenerTyped(client.communicator, TestDataSchema, (req) =>
|
addRequestListenerTyped(client.communicator, TestDataSchema, (req) =>
|
||||||
create(TestDataSchema, {
|
create(TestDataSchema, {
|
||||||
|
|
@ -227,11 +227,11 @@ async function runWssSendPush(): Promise<void> {
|
||||||
const received = new Promise<boolean>((resolve) => {
|
const received = new Promise<boolean>((resolve) => {
|
||||||
resolveReceived = resolve;
|
resolveReceived = resolve;
|
||||||
});
|
});
|
||||||
const server = new WsServer(
|
const server = new NodeWsServer(
|
||||||
HOST,
|
HOST,
|
||||||
WSS_PORT,
|
WSS_PORT,
|
||||||
WS_PATH,
|
WS_PATH,
|
||||||
(ws) => new WsClient(ws, 0, 0, parserMap()),
|
(ws) => new NodeWsClient(ws, 0, 0, parserMap()),
|
||||||
serverTlsOptions(),
|
serverTlsOptions(),
|
||||||
);
|
);
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
|
|
@ -262,11 +262,11 @@ async function runWssSendPush(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runWssRequests(): Promise<void> {
|
async function runWssRequests(): Promise<void> {
|
||||||
const server = new WsServer(
|
const server = new NodeWsServer(
|
||||||
HOST,
|
HOST,
|
||||||
WSS_PORT,
|
WSS_PORT,
|
||||||
WS_PATH,
|
WS_PATH,
|
||||||
(ws) => new WsClient(ws, 0, 0, parserMap()),
|
(ws) => new NodeWsClient(ws, 0, 0, parserMap()),
|
||||||
serverTlsOptions(),
|
serverTlsOptions(),
|
||||||
);
|
);
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ import {
|
||||||
import { TestDataSchema } from "../src/packets/message_common_pb.js";
|
import { TestDataSchema } from "../src/packets/message_common_pb.js";
|
||||||
import { TcpClient } from "../src/tcp_client.js";
|
import { TcpClient } from "../src/tcp_client.js";
|
||||||
import { TcpServer } from "../src/tcp_server.js";
|
import { TcpServer } from "../src/tcp_server.js";
|
||||||
import { WsClient } from "../src/ws_client.js";
|
import { NodeWsClient } from "../src/node_ws_client.js";
|
||||||
import { WsServer } from "../src/ws_server.js";
|
import { NodeWsServer } from "../src/node_ws_server.js";
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const repoRoot = path.resolve(path.dirname(__filename), "../..");
|
const repoRoot = path.resolve(path.dirname(__filename), "../..");
|
||||||
|
|
@ -121,7 +121,7 @@ async function runWsSendPush(): Promise<void> {
|
||||||
const received = new Promise<boolean>((resolve) => {
|
const received = new Promise<boolean>((resolve) => {
|
||||||
resolveReceived = resolve;
|
resolveReceived = resolve;
|
||||||
});
|
});
|
||||||
const server = new WsServer(HOST, WS_PORT, WS_PATH, (ws) => new WsClient(ws, 0, 0, parserMap()));
|
const server = new NodeWsServer(HOST, WS_PORT, WS_PATH, (ws) => new NodeWsClient(ws, 0, 0, parserMap()));
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
addListenerTyped(client.communicator, TestDataSchema, (data) => {
|
addListenerTyped(client.communicator, TestDataSchema, (data) => {
|
||||||
console.log(`SERVER_RECEIVED index=${data.index} message=${data.message}`);
|
console.log(`SERVER_RECEIVED index=${data.index} message=${data.message}`);
|
||||||
|
|
@ -150,7 +150,7 @@ async function runWsSendPush(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runWsRequests(): Promise<void> {
|
async function runWsRequests(): Promise<void> {
|
||||||
const server = new WsServer(HOST, WS_PORT, WS_PATH, (ws) => new WsClient(ws, 0, 0, parserMap()));
|
const server = new NodeWsServer(HOST, WS_PORT, WS_PATH, (ws) => new NodeWsClient(ws, 0, 0, parserMap()));
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
addRequestListenerTyped(client.communicator, TestDataSchema, (req) =>
|
addRequestListenerTyped(client.communicator, TestDataSchema, (req) =>
|
||||||
create(TestDataSchema, {
|
create(TestDataSchema, {
|
||||||
|
|
@ -223,11 +223,11 @@ async function runWssSendPush(): Promise<void> {
|
||||||
const received = new Promise<boolean>((resolve) => {
|
const received = new Promise<boolean>((resolve) => {
|
||||||
resolveReceived = resolve;
|
resolveReceived = resolve;
|
||||||
});
|
});
|
||||||
const server = new WsServer(
|
const server = new NodeWsServer(
|
||||||
HOST,
|
HOST,
|
||||||
WSS_PORT,
|
WSS_PORT,
|
||||||
WS_PATH,
|
WS_PATH,
|
||||||
(ws) => new WsClient(ws, 0, 0, parserMap()),
|
(ws) => new NodeWsClient(ws, 0, 0, parserMap()),
|
||||||
serverTlsOptions(),
|
serverTlsOptions(),
|
||||||
);
|
);
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
|
|
@ -258,11 +258,11 @@ async function runWssSendPush(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runWssRequests(): Promise<void> {
|
async function runWssRequests(): Promise<void> {
|
||||||
const server = new WsServer(
|
const server = new NodeWsServer(
|
||||||
HOST,
|
HOST,
|
||||||
WSS_PORT,
|
WSS_PORT,
|
||||||
WS_PATH,
|
WS_PATH,
|
||||||
(ws) => new WsClient(ws, 0, 0, parserMap()),
|
(ws) => new NodeWsClient(ws, 0, 0, parserMap()),
|
||||||
serverTlsOptions(),
|
serverTlsOptions(),
|
||||||
);
|
);
|
||||||
server.onClientConnected = (client) => {
|
server.onClientConnected = (client) => {
|
||||||
|
|
|
||||||
15
typescript/package-lock.json
generated
15
typescript/package-lock.json
generated
|
|
@ -8,8 +8,7 @@
|
||||||
"name": "proto-socket",
|
"name": "proto-socket",
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bufbuild/protobuf": "^2.2.5",
|
"@bufbuild/protobuf": "^2.2.5"
|
||||||
"ws": "^8.18.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@bufbuild/protoc-gen-es": "^2.2.5",
|
"@bufbuild/protoc-gen-es": "^2.2.5",
|
||||||
|
|
@ -17,7 +16,16 @@
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"tsx": "^4.19.3",
|
"tsx": "^4.19.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vitest": "^3.1.3"
|
"vitest": "^3.1.3",
|
||||||
|
"ws": "^8.18.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"ws": "^8.18.1"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ws": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@bufbuild/protobuf": {
|
"node_modules/@bufbuild/protobuf": {
|
||||||
|
|
@ -1748,6 +1756,7 @@
|
||||||
"version": "8.20.0",
|
"version": "8.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
|
||||||
"integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==",
|
"integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,39 @@
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/src/index.d.ts",
|
||||||
|
"default": "./dist/src/index.js"
|
||||||
|
},
|
||||||
|
"./node": {
|
||||||
|
"types": "./dist/src/node.d.ts",
|
||||||
|
"default": "./dist/src/node.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -p tsconfig.json",
|
"build": "tsc -p tsconfig.json",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"check": "tsc --noEmit"
|
"check": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bufbuild/protobuf": "^2.2.5",
|
"@bufbuild/protobuf": "^2.2.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
"ws": "^8.18.1"
|
"ws": "^8.18.1"
|
||||||
},
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ws": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@bufbuild/protoc-gen-es": "^2.2.5",
|
"@bufbuild/protoc-gen-es": "^2.2.5",
|
||||||
"@types/node": "^22.15.21",
|
"@types/node": "^22.15.21",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"tsx": "^4.19.3",
|
"tsx": "^4.19.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vitest": "^3.1.3"
|
"vitest": "^3.1.3",
|
||||||
|
"ws": "^8.18.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
131
typescript/src/browser_ws_client.ts
Normal file
131
typescript/src/browser_ws_client.ts
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
import { fromBinary, toBinary } from "@bufbuild/protobuf";
|
||||||
|
|
||||||
|
import { BaseClient } from "./base_client.js";
|
||||||
|
import { type ParserMap } from "./communicator.js";
|
||||||
|
import { PacketBaseSchema, type PacketBase } from "./packets/message_common_pb.js";
|
||||||
|
|
||||||
|
export interface BrowserWsConnectOptions {
|
||||||
|
WebSocketCtor?: typeof WebSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BrowserWsClient extends BaseClient {
|
||||||
|
private readonly ws: WebSocket;
|
||||||
|
private readonly handleMessage: (event: MessageEvent) => void;
|
||||||
|
private readonly handleClose: () => void;
|
||||||
|
private readonly handleError: () => void;
|
||||||
|
|
||||||
|
constructor(ws: WebSocket, intervalSec: number, waitSec: number, parserMap: ParserMap) {
|
||||||
|
super(intervalSec, waitSec, () => closeBrowserWebSocket(ws));
|
||||||
|
this.ws = ws;
|
||||||
|
this.ws.binaryType = "arraybuffer";
|
||||||
|
this.initBase(parserMap);
|
||||||
|
|
||||||
|
this.handleMessage = (event: MessageEvent) => {
|
||||||
|
void this.onMessage(event.data);
|
||||||
|
};
|
||||||
|
this.handleClose = () => {
|
||||||
|
void this.onDisconnected();
|
||||||
|
};
|
||||||
|
this.handleError = () => {
|
||||||
|
void this.onDisconnected();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.addEventListener("message", this.handleMessage);
|
||||||
|
this.ws.addEventListener("close", this.handleClose);
|
||||||
|
this.ws.addEventListener("error", this.handleError);
|
||||||
|
}
|
||||||
|
|
||||||
|
async writePacket(base: PacketBase): Promise<void> {
|
||||||
|
const data = toBinary(PacketBaseSchema, base);
|
||||||
|
try {
|
||||||
|
this.ws.send(data);
|
||||||
|
} catch (err) {
|
||||||
|
throw err instanceof Error ? err : new Error(String(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async onMessage(data: unknown): Promise<void> {
|
||||||
|
let bytes: Uint8Array;
|
||||||
|
try {
|
||||||
|
bytes = await toUint8Array(data);
|
||||||
|
} catch {
|
||||||
|
void this.onDisconnected();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const base = fromBinary(PacketBaseSchema, bytes);
|
||||||
|
this.communicator.onReceivedData(base.typeName, base.data, base.nonce, base.responseNonce);
|
||||||
|
void this.sendHeartbeat();
|
||||||
|
} catch {
|
||||||
|
void this.onDisconnected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function connectBrowserWs(
|
||||||
|
url: string,
|
||||||
|
intervalSec: number,
|
||||||
|
waitSec: number,
|
||||||
|
parserMap: ParserMap,
|
||||||
|
options?: BrowserWsConnectOptions,
|
||||||
|
): Promise<BrowserWsClient> {
|
||||||
|
const Ctor = options?.WebSocketCtor ?? globalThis.WebSocket;
|
||||||
|
if (Ctor === undefined) {
|
||||||
|
throw new Error("global WebSocket is not available; provide WebSocketCtor option");
|
||||||
|
}
|
||||||
|
return new Promise<BrowserWsClient>((resolve, reject) => {
|
||||||
|
const ws = new Ctor(url);
|
||||||
|
ws.binaryType = "arraybuffer";
|
||||||
|
const onOpen = () => {
|
||||||
|
cleanup();
|
||||||
|
resolve(new BrowserWsClient(ws, intervalSec, waitSec, parserMap));
|
||||||
|
};
|
||||||
|
const onError = () => {
|
||||||
|
cleanup();
|
||||||
|
reject(new Error(`failed to connect ${url}`));
|
||||||
|
};
|
||||||
|
const cleanup = () => {
|
||||||
|
ws.removeEventListener("open", onOpen);
|
||||||
|
ws.removeEventListener("error", onError);
|
||||||
|
};
|
||||||
|
ws.addEventListener("open", onOpen);
|
||||||
|
ws.addEventListener("error", onError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function toUint8Array(data: unknown): Promise<Uint8Array> {
|
||||||
|
if (data instanceof ArrayBuffer) {
|
||||||
|
return new Uint8Array(data);
|
||||||
|
}
|
||||||
|
if (data instanceof Uint8Array) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
if (typeof Blob !== "undefined" && data instanceof Blob) {
|
||||||
|
const buf = await data.arrayBuffer();
|
||||||
|
return new Uint8Array(buf);
|
||||||
|
}
|
||||||
|
throw new Error("unsupported WebSocket frame: text or unknown payload");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function closeBrowserWebSocket(ws: WebSocket): Promise<void> {
|
||||||
|
if (ws.readyState === ws.CLOSED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
const onDone = () => {
|
||||||
|
ws.removeEventListener("close", onDone);
|
||||||
|
ws.removeEventListener("error", onDone);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
ws.addEventListener("close", onDone);
|
||||||
|
ws.addEventListener("error", onDone);
|
||||||
|
if (ws.readyState === ws.CLOSING) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ws.close(1000, "");
|
||||||
|
} catch {
|
||||||
|
onDone();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,4 @@
|
||||||
export * from "./base_client.js";
|
export * from "./base_client.js";
|
||||||
export * from "./communicator.js";
|
export * from "./communicator.js";
|
||||||
export * from "./packets/message_common_pb.js";
|
export * from "./packets/message_common_pb.js";
|
||||||
export * from "./tcp_client.js";
|
export * from "./browser_ws_client.js";
|
||||||
export * from "./tcp_server.js";
|
|
||||||
export * from "./ws_client.js";
|
|
||||||
export * from "./ws_server.js";
|
|
||||||
|
|
|
||||||
7
typescript/src/node.ts
Normal file
7
typescript/src/node.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
export * from "./base_client.js";
|
||||||
|
export * from "./communicator.js";
|
||||||
|
export * from "./packets/message_common_pb.js";
|
||||||
|
export * from "./tcp_client.js";
|
||||||
|
export * from "./tcp_server.js";
|
||||||
|
export * from "./node_ws_client.js";
|
||||||
|
export * from "./node_ws_server.js";
|
||||||
|
|
@ -6,7 +6,7 @@ import { BaseClient } from "./base_client.js";
|
||||||
import { type ParserMap } from "./communicator.js";
|
import { type ParserMap } from "./communicator.js";
|
||||||
import { PacketBaseSchema, type PacketBase } from "./packets/message_common_pb.js";
|
import { PacketBaseSchema, type PacketBase } from "./packets/message_common_pb.js";
|
||||||
|
|
||||||
export class WsClient extends BaseClient {
|
export class NodeWsClient extends BaseClient {
|
||||||
private readonly ws: WebSocket;
|
private readonly ws: WebSocket;
|
||||||
|
|
||||||
constructor(ws: WebSocket, intervalSec: number, waitSec: number, parserMap: ParserMap) {
|
constructor(ws: WebSocket, intervalSec: number, waitSec: number, parserMap: ParserMap) {
|
||||||
|
|
@ -49,19 +49,19 @@ export class WsClient extends BaseClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function connectWs(
|
export async function connectNodeWs(
|
||||||
host: string,
|
host: string,
|
||||||
port: number,
|
port: number,
|
||||||
path: string,
|
path: string,
|
||||||
intervalSec: number,
|
intervalSec: number,
|
||||||
waitSec: number,
|
waitSec: number,
|
||||||
parserMap: ParserMap,
|
parserMap: ParserMap,
|
||||||
): Promise<WsClient> {
|
): Promise<NodeWsClient> {
|
||||||
return new Promise<WsClient>((resolve, reject) => {
|
return new Promise<NodeWsClient>((resolve, reject) => {
|
||||||
const ws = new WebSocket(`ws://${host}:${port}${path}`);
|
const ws = new WebSocket(`ws://${host}:${port}${path}`);
|
||||||
const onOpen = () => {
|
const onOpen = () => {
|
||||||
cleanup();
|
cleanup();
|
||||||
resolve(new WsClient(ws, intervalSec, waitSec, parserMap));
|
resolve(new NodeWsClient(ws, intervalSec, waitSec, parserMap));
|
||||||
};
|
};
|
||||||
const onError = (err: Error) => {
|
const onError = (err: Error) => {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
@ -77,7 +77,7 @@ export async function connectWs(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function connectWss(
|
export async function connectNodeWss(
|
||||||
host: string,
|
host: string,
|
||||||
port: number,
|
port: number,
|
||||||
path: string,
|
path: string,
|
||||||
|
|
@ -85,12 +85,12 @@ export async function connectWss(
|
||||||
intervalSec: number,
|
intervalSec: number,
|
||||||
waitSec: number,
|
waitSec: number,
|
||||||
parserMap: ParserMap,
|
parserMap: ParserMap,
|
||||||
): Promise<WsClient> {
|
): Promise<NodeWsClient> {
|
||||||
return new Promise<WsClient>((resolve, reject) => {
|
return new Promise<NodeWsClient>((resolve, reject) => {
|
||||||
const ws = new WebSocket(`wss://${host}:${port}${path}`, wsOptions);
|
const ws = new WebSocket(`wss://${host}:${port}${path}`, wsOptions);
|
||||||
const onOpen = () => {
|
const onOpen = () => {
|
||||||
cleanup();
|
cleanup();
|
||||||
resolve(new WsClient(ws, intervalSec, waitSec, parserMap));
|
resolve(new NodeWsClient(ws, intervalSec, waitSec, parserMap));
|
||||||
};
|
};
|
||||||
const onError = (err: Error) => {
|
const onError = (err: Error) => {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
@ -3,20 +3,20 @@ import * as https from "node:https";
|
||||||
import { type Message } from "@bufbuild/protobuf";
|
import { type Message } from "@bufbuild/protobuf";
|
||||||
import WebSocket, { WebSocketServer } from "ws";
|
import WebSocket, { WebSocketServer } from "ws";
|
||||||
|
|
||||||
import { WsClient } from "./ws_client.js";
|
import { NodeWsClient } from "./node_ws_client.js";
|
||||||
|
|
||||||
export class WsServer {
|
export class NodeWsServer {
|
||||||
private wss: WebSocketServer | null = null;
|
private wss: WebSocketServer | null = null;
|
||||||
private httpsServer: https.Server | null = null;
|
private httpsServer: https.Server | null = null;
|
||||||
private readonly clients = new Set<WsClient>();
|
private readonly clients = new Set<NodeWsClient>();
|
||||||
|
|
||||||
onClientConnected: (client: WsClient) => void = () => {};
|
onClientConnected: (client: NodeWsClient) => void = () => {};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly host: string,
|
private readonly host: string,
|
||||||
private readonly listenPort: number,
|
private readonly listenPort: number,
|
||||||
private readonly path: string,
|
private readonly path: string,
|
||||||
private readonly newClient: (ws: WebSocket) => WsClient,
|
private readonly newClient: (ws: WebSocket) => NodeWsClient,
|
||||||
private readonly tlsOptions?: https.ServerOptions,
|
private readonly tlsOptions?: https.ServerOptions,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|
@ -113,7 +113,7 @@ export class WsServer {
|
||||||
await Promise.all([...this.clients].map(async (client) => client.communicator.send(msg)));
|
await Promise.all([...this.clients].map(async (client) => client.communicator.send(msg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeClient(client: WsClient): void {
|
private removeClient(client: NodeWsClient): void {
|
||||||
this.clients.delete(client);
|
this.clients.delete(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
260
typescript/test/browser_ws_client.test.ts
Normal file
260
typescript/test/browser_ws_client.test.ts
Normal file
|
|
@ -0,0 +1,260 @@
|
||||||
|
import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
|
||||||
|
import { afterEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
import {
|
||||||
|
addListenerTyped,
|
||||||
|
addRequestListenerTyped,
|
||||||
|
parserFromSchema,
|
||||||
|
sendRequestTyped,
|
||||||
|
} from "../src/communicator.js";
|
||||||
|
import {
|
||||||
|
PacketBaseSchema,
|
||||||
|
TestDataSchema,
|
||||||
|
type TestData,
|
||||||
|
} from "../src/packets/message_common_pb.js";
|
||||||
|
import { BrowserWsClient, connectBrowserWs } from "../src/browser_ws_client.js";
|
||||||
|
|
||||||
|
type Listener = (event: { data?: unknown; code?: number; reason?: string }) => void;
|
||||||
|
|
||||||
|
class FakeWebSocket {
|
||||||
|
static instances: FakeWebSocket[] = [];
|
||||||
|
|
||||||
|
static readonly CONNECTING = 0 as const;
|
||||||
|
static readonly OPEN = 1 as const;
|
||||||
|
static readonly CLOSING = 2 as const;
|
||||||
|
static readonly CLOSED = 3 as const;
|
||||||
|
|
||||||
|
readonly CONNECTING = FakeWebSocket.CONNECTING;
|
||||||
|
readonly OPEN = FakeWebSocket.OPEN;
|
||||||
|
readonly CLOSING = FakeWebSocket.CLOSING;
|
||||||
|
readonly CLOSED = FakeWebSocket.CLOSED;
|
||||||
|
|
||||||
|
url: string;
|
||||||
|
binaryType = "blob";
|
||||||
|
readyState: number = FakeWebSocket.CONNECTING;
|
||||||
|
sentFrames: Uint8Array[] = [];
|
||||||
|
sendShouldThrow: Error | null = null;
|
||||||
|
closedWith: { code: number; reason: string } | null = null;
|
||||||
|
|
||||||
|
private readonly listeners = new Map<string, Set<Listener>>();
|
||||||
|
|
||||||
|
constructor(url: string) {
|
||||||
|
this.url = url;
|
||||||
|
FakeWebSocket.instances.push(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener(type: string, fn: Listener): void {
|
||||||
|
if (!this.listeners.has(type)) {
|
||||||
|
this.listeners.set(type, new Set());
|
||||||
|
}
|
||||||
|
this.listeners.get(type)!.add(fn);
|
||||||
|
}
|
||||||
|
removeEventListener(type: string, fn: Listener): void {
|
||||||
|
this.listeners.get(type)?.delete(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
send(data: ArrayBuffer | Uint8Array): void {
|
||||||
|
if (this.sendShouldThrow !== null) {
|
||||||
|
throw this.sendShouldThrow;
|
||||||
|
}
|
||||||
|
const buf =
|
||||||
|
data instanceof Uint8Array ? new Uint8Array(data) : new Uint8Array(data as ArrayBuffer);
|
||||||
|
this.sentFrames.push(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(code = 1000, reason = ""): void {
|
||||||
|
if (this.readyState === FakeWebSocket.CLOSED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.closedWith = { code, reason };
|
||||||
|
this.readyState = FakeWebSocket.CLOSED;
|
||||||
|
this.dispatch("close", { code, reason });
|
||||||
|
}
|
||||||
|
|
||||||
|
fireOpen(): void {
|
||||||
|
this.readyState = FakeWebSocket.OPEN;
|
||||||
|
this.dispatch("open", {});
|
||||||
|
}
|
||||||
|
fireMessage(data: unknown): void {
|
||||||
|
this.dispatch("message", { data });
|
||||||
|
}
|
||||||
|
fireError(): void {
|
||||||
|
this.dispatch("error", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
private dispatch(type: string, event: { data?: unknown; code?: number; reason?: string }): void {
|
||||||
|
const set = this.listeners.get(type);
|
||||||
|
if (set === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const fn of [...set]) {
|
||||||
|
fn(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parserMap() {
|
||||||
|
return new Map([[TestDataSchema.typeName, parserFromSchema(TestDataSchema)]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeFrame(buf: Uint8Array): { typeName: string; nonce: number; responseNonce: number; payload: Uint8Array } {
|
||||||
|
const base = fromBinary(PacketBaseSchema, buf);
|
||||||
|
return {
|
||||||
|
typeName: base.typeName,
|
||||||
|
nonce: base.nonce,
|
||||||
|
responseNonce: base.responseNonce,
|
||||||
|
payload: base.data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeTestData(msg: TestData, nonce: number, responseNonce = 0): Uint8Array {
|
||||||
|
return toBinary(
|
||||||
|
PacketBaseSchema,
|
||||||
|
create(PacketBaseSchema, {
|
||||||
|
typeName: TestDataSchema.typeName,
|
||||||
|
nonce,
|
||||||
|
responseNonce,
|
||||||
|
data: toBinary(TestDataSchema, msg),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("BrowserWsClient", () => {
|
||||||
|
const cleanup: Array<() => Promise<void>> = [];
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
FakeWebSocket.instances.length = 0;
|
||||||
|
while (cleanup.length > 0) {
|
||||||
|
const fn = cleanup.pop();
|
||||||
|
if (fn) {
|
||||||
|
await fn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("connectBrowserWs resolves after open and sends binary frames", async () => {
|
||||||
|
const pending = connectBrowserWs("ws://test/", 0, 0, parserMap(), {
|
||||||
|
WebSocketCtor: FakeWebSocket as unknown as typeof WebSocket,
|
||||||
|
});
|
||||||
|
expect(FakeWebSocket.instances).toHaveLength(1);
|
||||||
|
const ws = FakeWebSocket.instances[0]!;
|
||||||
|
expect(ws.binaryType).toBe("arraybuffer");
|
||||||
|
ws.fireOpen();
|
||||||
|
const client = await pending;
|
||||||
|
cleanup.push(async () => client.close());
|
||||||
|
expect(client).toBeInstanceOf(BrowserWsClient);
|
||||||
|
|
||||||
|
await client.communicator.send(create(TestDataSchema, { index: 11, message: "hi" }));
|
||||||
|
expect(ws.sentFrames).toHaveLength(1);
|
||||||
|
const decoded = decodeFrame(ws.sentFrames[0]!);
|
||||||
|
expect(decoded.typeName).toBe(TestDataSchema.typeName);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("routes ArrayBuffer message to communicator listener", async () => {
|
||||||
|
const pending = connectBrowserWs("ws://test/", 0, 0, parserMap(), {
|
||||||
|
WebSocketCtor: FakeWebSocket as unknown as typeof WebSocket,
|
||||||
|
});
|
||||||
|
const ws = FakeWebSocket.instances[0]!;
|
||||||
|
ws.fireOpen();
|
||||||
|
const client = await pending;
|
||||||
|
cleanup.push(async () => client.close());
|
||||||
|
|
||||||
|
const received = new Promise<TestData>((resolve) => {
|
||||||
|
addListenerTyped(client.communicator, TestDataSchema, resolve);
|
||||||
|
});
|
||||||
|
|
||||||
|
const frame = encodeTestData(create(TestDataSchema, { index: 7, message: "push" }), 1);
|
||||||
|
ws.fireMessage(frame.buffer.slice(frame.byteOffset, frame.byteOffset + frame.byteLength));
|
||||||
|
|
||||||
|
await expect(received).resolves.toMatchObject({ index: 7, message: "push" });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("routes Blob message", async () => {
|
||||||
|
const pending = connectBrowserWs("ws://test/", 0, 0, parserMap(), {
|
||||||
|
WebSocketCtor: FakeWebSocket as unknown as typeof WebSocket,
|
||||||
|
});
|
||||||
|
const ws = FakeWebSocket.instances[0]!;
|
||||||
|
ws.fireOpen();
|
||||||
|
const client = await pending;
|
||||||
|
cleanup.push(async () => client.close());
|
||||||
|
|
||||||
|
const received = new Promise<TestData>((resolve) => {
|
||||||
|
addListenerTyped(client.communicator, TestDataSchema, resolve);
|
||||||
|
});
|
||||||
|
|
||||||
|
const frame = encodeTestData(create(TestDataSchema, { index: 8, message: "blob" }), 1);
|
||||||
|
ws.fireMessage(new Blob([new Uint8Array(frame).slice().buffer]));
|
||||||
|
|
||||||
|
await expect(received).resolves.toMatchObject({ index: 8, message: "blob" });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("sendRequest resolves on response frame", async () => {
|
||||||
|
const pending = connectBrowserWs("ws://test/", 0, 0, parserMap(), {
|
||||||
|
WebSocketCtor: FakeWebSocket as unknown as typeof WebSocket,
|
||||||
|
});
|
||||||
|
const ws = FakeWebSocket.instances[0]!;
|
||||||
|
ws.fireOpen();
|
||||||
|
const client = await pending;
|
||||||
|
cleanup.push(async () => client.close());
|
||||||
|
|
||||||
|
const promise = sendRequestTyped(
|
||||||
|
client.communicator,
|
||||||
|
create(TestDataSchema, { index: 21, message: "req" }),
|
||||||
|
TestDataSchema,
|
||||||
|
500,
|
||||||
|
);
|
||||||
|
|
||||||
|
// wait a microtask for queued send
|
||||||
|
await new Promise<void>((r) => setTimeout(r, 0));
|
||||||
|
expect(ws.sentFrames).toHaveLength(1);
|
||||||
|
const sent = decodeFrame(ws.sentFrames[0]!);
|
||||||
|
const responseFrame = encodeTestData(
|
||||||
|
create(TestDataSchema, { index: 42, message: "echo: req" }),
|
||||||
|
99,
|
||||||
|
sent.nonce,
|
||||||
|
);
|
||||||
|
ws.fireMessage(
|
||||||
|
responseFrame.buffer.slice(responseFrame.byteOffset, responseFrame.byteOffset + responseFrame.byteLength),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(promise).resolves.toMatchObject({ index: 42, message: "echo: req" });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("disconnects on string frame", async () => {
|
||||||
|
const pending = connectBrowserWs("ws://test/", 0, 0, parserMap(), {
|
||||||
|
WebSocketCtor: FakeWebSocket as unknown as typeof WebSocket,
|
||||||
|
});
|
||||||
|
const ws = FakeWebSocket.instances[0]!;
|
||||||
|
ws.fireOpen();
|
||||||
|
const client = await pending;
|
||||||
|
cleanup.push(async () => client.close());
|
||||||
|
|
||||||
|
expect(client.communicator.isAlive()).toBe(true);
|
||||||
|
ws.fireMessage("not binary");
|
||||||
|
await new Promise<void>((r) => setTimeout(r, 0));
|
||||||
|
expect(client.communicator.isAlive()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("server registers request handlers via communicator", async () => {
|
||||||
|
const pending = connectBrowserWs("ws://test/", 0, 0, parserMap(), {
|
||||||
|
WebSocketCtor: FakeWebSocket as unknown as typeof WebSocket,
|
||||||
|
});
|
||||||
|
const ws = FakeWebSocket.instances[0]!;
|
||||||
|
ws.fireOpen();
|
||||||
|
const client = await pending;
|
||||||
|
cleanup.push(async () => client.close());
|
||||||
|
|
||||||
|
addRequestListenerTyped(client.communicator, TestDataSchema, (req) =>
|
||||||
|
create(TestDataSchema, { index: req.index * 2, message: `echo: ${req.message}` }),
|
||||||
|
);
|
||||||
|
|
||||||
|
const reqFrame = encodeTestData(create(TestDataSchema, { index: 3, message: "ping" }), 77);
|
||||||
|
ws.fireMessage(reqFrame.buffer.slice(reqFrame.byteOffset, reqFrame.byteOffset + reqFrame.byteLength));
|
||||||
|
|
||||||
|
await new Promise<void>((r) => setTimeout(r, 5));
|
||||||
|
expect(ws.sentFrames.length).toBeGreaterThanOrEqual(1);
|
||||||
|
const responses = ws.sentFrames.map((f) => decodeFrame(f));
|
||||||
|
const match = responses.find((r) => r.responseNonce === 77);
|
||||||
|
expect(match).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -12,8 +12,8 @@ import {
|
||||||
sendRequestTyped,
|
sendRequestTyped,
|
||||||
} from "../src/communicator.js";
|
} from "../src/communicator.js";
|
||||||
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
import { TestDataSchema, type TestData } from "../src/packets/message_common_pb.js";
|
||||||
import { connectWs, connectWss, WsClient } from "../src/ws_client.js";
|
import { connectNodeWs, connectNodeWss, NodeWsClient } from "../src/node_ws_client.js";
|
||||||
import { WsServer } from "../src/ws_server.js";
|
import { NodeWsServer } from "../src/node_ws_server.js";
|
||||||
|
|
||||||
const certsDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "certs");
|
const certsDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "certs");
|
||||||
const cert = fs.readFileSync(path.join(certsDir, "server.crt"));
|
const cert = fs.readFileSync(path.join(certsDir, "server.crt"));
|
||||||
|
|
@ -23,7 +23,7 @@ function parserMap() {
|
||||||
return new Map([[TestDataSchema.typeName, parserFromSchema(TestDataSchema)]]);
|
return new Map([[TestDataSchema.typeName, parserFromSchema(TestDataSchema)]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function waitForClientMessage(client: WsClient): Promise<TestData> {
|
async function waitForClientMessage(client: NodeWsClient): Promise<TestData> {
|
||||||
return new Promise<TestData>((resolve) => {
|
return new Promise<TestData>((resolve) => {
|
||||||
addListenerTyped(client.communicator, TestDataSchema, (msg) => resolve(msg));
|
addListenerTyped(client.communicator, TestDataSchema, (msg) => resolve(msg));
|
||||||
});
|
});
|
||||||
|
|
@ -42,7 +42,7 @@ describe("WS", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("connectWs sends and receives TestData", async () => {
|
test("connectWs sends and receives TestData", async () => {
|
||||||
const server = new WsServer("127.0.0.1", 0, "/", (ws) => new WsClient(ws, 0, 0, parserMap()));
|
const server = new NodeWsServer("127.0.0.1", 0, "/", (ws) => new NodeWsClient(ws, 0, 0, parserMap()));
|
||||||
cleanup.push(async () => server.stop());
|
cleanup.push(async () => server.stop());
|
||||||
await server.start();
|
await server.start();
|
||||||
|
|
||||||
|
|
@ -56,7 +56,7 @@ describe("WS", () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = await connectWs("127.0.0.1", server.port, "/", 0, 0, parserMap());
|
const client = await connectNodeWs("127.0.0.1", server.port, "/", 0, 0, parserMap());
|
||||||
cleanup.push(async () => client.close());
|
cleanup.push(async () => client.close());
|
||||||
|
|
||||||
const pushed = waitForClientMessage(client);
|
const pushed = waitForClientMessage(client);
|
||||||
|
|
@ -69,7 +69,7 @@ describe("WS", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("sendRequest/response roundtrip over WS", async () => {
|
test("sendRequest/response roundtrip over WS", async () => {
|
||||||
const server = new WsServer("127.0.0.1", 0, "/", (ws) => new WsClient(ws, 0, 0, parserMap()));
|
const server = new NodeWsServer("127.0.0.1", 0, "/", (ws) => new NodeWsClient(ws, 0, 0, parserMap()));
|
||||||
cleanup.push(async () => server.stop());
|
cleanup.push(async () => server.stop());
|
||||||
await server.start();
|
await server.start();
|
||||||
|
|
||||||
|
|
@ -82,7 +82,7 @@ describe("WS", () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = await connectWs("127.0.0.1", server.port, "/", 0, 0, parserMap());
|
const client = await connectNodeWs("127.0.0.1", server.port, "/", 0, 0, parserMap());
|
||||||
cleanup.push(async () => client.close());
|
cleanup.push(async () => client.close());
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
|
|
@ -99,7 +99,7 @@ describe("WS", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("connectWss sends and receives TestData", async () => {
|
test("connectWss sends and receives TestData", async () => {
|
||||||
const server = new WsServer("127.0.0.1", 0, "/", (ws) => new WsClient(ws, 0, 0, parserMap()), {
|
const server = new NodeWsServer("127.0.0.1", 0, "/", (ws) => new NodeWsClient(ws, 0, 0, parserMap()), {
|
||||||
cert,
|
cert,
|
||||||
key,
|
key,
|
||||||
});
|
});
|
||||||
|
|
@ -116,7 +116,7 @@ describe("WS", () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = await connectWss(
|
const client = await connectNodeWss(
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
server.port,
|
server.port,
|
||||||
"/",
|
"/",
|
||||||
|
|
@ -137,7 +137,7 @@ describe("WS", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("WSS sendRequest/response roundtrip", async () => {
|
test("WSS sendRequest/response roundtrip", async () => {
|
||||||
const server = new WsServer("127.0.0.1", 0, "/", (ws) => new WsClient(ws, 0, 0, parserMap()), {
|
const server = new NodeWsServer("127.0.0.1", 0, "/", (ws) => new NodeWsClient(ws, 0, 0, parserMap()), {
|
||||||
cert,
|
cert,
|
||||||
key,
|
key,
|
||||||
});
|
});
|
||||||
|
|
@ -153,7 +153,7 @@ describe("WS", () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = await connectWss(
|
const client = await connectNodeWss(
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
server.port,
|
server.port,
|
||||||
"/",
|
"/",
|
||||||
|
|
@ -178,7 +178,7 @@ describe("WS", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("concurrent sendRequest/response roundtrip over WS", async () => {
|
test("concurrent sendRequest/response roundtrip over WS", async () => {
|
||||||
const server = new WsServer("127.0.0.1", 0, "/", (ws) => new WsClient(ws, 0, 0, parserMap()));
|
const server = new NodeWsServer("127.0.0.1", 0, "/", (ws) => new NodeWsClient(ws, 0, 0, parserMap()));
|
||||||
cleanup.push(async () => server.stop());
|
cleanup.push(async () => server.stop());
|
||||||
await server.start();
|
await server.start();
|
||||||
|
|
||||||
|
|
@ -191,7 +191,7 @@ describe("WS", () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = await connectWs("127.0.0.1", server.port, "/", 0, 0, parserMap());
|
const client = await connectNodeWs("127.0.0.1", server.port, "/", 0, 0, parserMap());
|
||||||
cleanup.push(async () => client.close());
|
cleanup.push(async () => client.close());
|
||||||
|
|
||||||
const results = await Promise.all(
|
const results = await Promise.all(
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
|
"lib": ["ES2022", "DOM"],
|
||||||
"types": ["node"]
|
"types": ["node"]
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "test/**/*.ts", "crosstest/**/*.ts"]
|
"include": ["src/**/*.ts", "test/**/*.ts", "crosstest/**/*.ts"]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue