# Toki Socket Binary socket protocol library for bidirectional, heterogeneous communication across languages and platforms. Built on Protocol Buffers with TCP length-prefixed framing, WebSocket binary frames, type-based message routing, request-response correlation, and built-in heartbeat. --- ## Design Principles - Keep the core transport layer thin and stable - Provide only the minimum common foundation for cross-language communication - Standardize framing, serialization, routing, request-response correlation, and heartbeat - Do not embed application semantics into the protocol core - Domain-specific concerns such as auth, session, agent workflow, chat features, and game logic belong in upper-layer implementations --- ## Protocol See [PROTOCOL.md](PROTOCOL.md) for the full wire format specification. ``` [4-byte big-endian length] [PacketBase protobuf bytes] ``` For WebSocket/WSS transports, each binary frame contains one `PacketBase` protobuf payload without the TCP length header. --- ## Implementations | Language | Status | Path | Use case | |----------|--------|------|----------| | Dart | Available | [dart/](dart/) | Flutter, Dart server | | C# | Planned | `csharp/` | Unity, .NET | | Kotlin | Planned | `kotlin/` | Android | | Swift | Planned | `swift/` | iOS, macOS | | Go | Available | [go/](go/) | Server, tooling, scripting | | Python | Planned | `python/` | Server, tooling, scripting | | Rust | Planned | `rust/` | High-performance server, embedded | --- ## Quick Start (Dart) ```dart import 'package:toki_socket/toki_socket.dart'; // 1. Define your message in message_common.proto, generate with protoc // 2. Implement a client class MyClient extends ProtobufClient { MyClient(Socket socket) : super(socket, 30, 10, { MyMessage.getDefault().info_.qualifiedMessageName: MyMessage.fromBuffer, }); } // 3. Implement a server class MyServer extends ProtobufServer { MyServer() : super('0.0.0.0', 9090, (socket) => MyClient(socket)); @override void onClientConnected(ProtobufClient client) { client.addListener((msg) => print('Received: ${msg}')); } } // 4. Start final server = MyServer(); await server.start(); // 5. Connect and send final socket = await Socket.connect('localhost', 9090); final client = MyClient(socket); await client.send(MyMessage()..text = 'hello'); ``` --- ## Adding Message Types Edit `dart/lib/src/packets/message_common.proto` and regenerate: ```bash cd dart dart pub global activate protoc_plugin protoc --dart_out=lib/src/packets lib/src/packets/message_common.proto ``` For Go, keep `go/packets/message_common.proto` in sync with the canonical Dart proto. The Go copy includes `option go_package`, then regenerate from the Go module root: ```bash cd go protoc --go_out=. --go_opt=paths=source_relative packets/message_common.proto ``` --- ## Quick Start (Go) ```go package main import ( "context" "net" "time" "google.golang.org/protobuf/proto" toki "toki-labs.com/toki_socket/go" "toki-labs.com/toki_socket/go/packets" ) func parserMap() toki.ParserMap { return toki.ParserMap{ toki.TypeNameOf(&packets.TestData{}): func(b []byte) (proto.Message, error) { m := &packets.TestData{} return m, proto.Unmarshal(b, m) }, } } func main() { ctx := context.Background() server := toki.NewTcpServer("127.0.0.1", 9090, func(conn net.Conn) *toki.TcpClient { return toki.NewTcpClient(conn, 30, 10, parserMap()) }) server.OnClientConnected = func(client *toki.TcpClient) { toki.AddRequestListenerTyped[*packets.TestData, *packets.TestData]( &client.Communicator, func(req *packets.TestData) (*packets.TestData, error) { return &packets.TestData{Index: req.GetIndex(), Message: "echo: " + req.GetMessage()}, nil }, ) } if err := server.Start(ctx); err != nil { panic(err) } defer server.Stop() client, err := toki.DialTcp(ctx, "127.0.0.1", 9090, 30, 10, parserMap()) if err != nil { panic(err) } defer client.Close() res, err := toki.SendRequestTyped[*packets.TestData, *packets.TestData]( &client.Communicator, &packets.TestData{Index: 1, Message: "hello"}, 2*time.Second, ) if err != nil { panic(err) } println(res.GetMessage()) } ``` Go also provides: - TCP: `NewTcpServer`, `DialTcp`, `NewTcpServerTLS`, `DialTcpTLS` - WebSocket: `NewWsServer`, `DialWs`, `NewWsServerTLS`, `DialWss` - Shared helpers: `Send`, `SendRequest`, `AddListenerTyped`, `AddRequestListenerTyped`, `Broadcast` --- ## Running Tests ```bash cd dart dart pub get dart test ``` ```bash cd go go test ./... ```