Skip to content

cyper98/zsocket

Repository files navigation

zsocket

A small, gorilla-free WebSocket server for Go — clean API, RFC6455 handshake, frames, ping/pong keepalive, JSON helpers, and a simple room hub. Built to be extended (rate limiting, metrics, distributed hub) without leaking third-party types into your code.

Module: github.com/aminofox/zsocket

Features

  • Minimal RFC6455 server-side implementation
  • Clean API:
    • Accept(w, r, cfg) (*Conn, error)
    • Upgrader{Config: cfg}.Upgrade(w, r, responseHeader)
    • Dial(urlStr, header) (*Conn, *http.Response, error)
    • Conn.Read(ctx) (MessageType, []byte, error)
    • Conn.Write(ctx, mt, data)
    • Conn.NextReader()/NextWriter()
    • Conn.ReadMessage()/WriteMessage()
    • Conn.WriteControl(mt, payload, deadline)
    • Conn.ReadJSON/WriteJSON
    • Conn.Close(code, reason)
    • Conn.Subprotocol(), Conn.RemoteAddr(), Conn.LocalAddr()
  • Fragmentation (basic accumulation until FIN)
  • Control frames: ping/pong/close
  • Keepalive: PingInterval + PongWait
  • Hub: rooms & broadcast
  • Configurable read limit, deadlines, origin policy, subprotocols
  • Client dialer with context, TLS and proxy support
  • Optional compression, send queue, and buffer pool

Quick Start

go get github.com/aminofox/zsocket
package main

import (
  "context"
  "log"
  "net/http"
  "github.com/aminofox/zsocket"
)

func main() {
  cfg := zsocket.DefaultConfig()
  hub := zsocket.NewHub()

  http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
    conn, err := zsocket.Accept(w, r, cfg)
    if err != nil {
      http.Error(w, "upgrade failed", http.StatusBadRequest)
      return
    }
    hub.Join("lobby", conn)

    go func() {
      defer func() {
        hub.LeaveAll(conn)
        _ = conn.Close(zsocket.CloseNormalClosure, "bye")
      }()
      ctx := context.Background()
      _ = conn.Write(ctx, zsocket.TextMessage, []byte("hello from zsocket"))

      for {
        mt, msg, err := conn.Read(ctx)
        if err != nil {
          log.Printf("read: %v", err)
          return
        }
        _ = conn.Write(ctx, mt, msg) // echo
        hub.Broadcast(ctx, "lobby", mt, msg)
      }
    }()
  })

  log.Fatal(http.ListenAndServe(":8080", nil))
}

Config

cfg := zsocket.DefaultConfig()
cfg.AllowedOrigins = []string{"https://example.com"} // or nil to allow all
cfg.Subprotocols = []string{"chat", "json"}
cfg.ReadLimit = 16 << 20  // 16 MiB per message
cfg.PingInterval = 30 * time.Second
cfg.PongWait = 15 * time.Second
cfg.WriteTimeout = 10 * time.Second

JSON Helpers

type In struct { Cmd string `json:"cmd"`; Body any `json:"body"` }

var in In
if err := conn.ReadJSON(ctx, &in); err != nil { ... }
if err := conn.WriteJSON(ctx, map[string]any{"ok": true}); err != nil { ... }

Rooms & Broadcast

hub.Join("room-42", conn)
hub.Broadcast(ctx, "room-42", zsocket.TextMessage, []byte("hi all"))
hub.Leave("room-42", conn)

Client Example

d := zsocket.DefaultDialer
conn, resp, err := d.Dial("ws://localhost:8080/ws", nil)
if err != nil {
  // bad handshake still returns HTTP response when available
  _ = resp
}

Compression

cfg := zsocket.DefaultConfig()
cfg.EnableCompression = true

conn, _ := zsocket.Accept(w, r, cfg)
conn.EnableWriteCompression(true)
_ = conn.SetCompressionLevel(1)

Send Queue

conn.EnableSendQueue(128)
_ = conn.Send(ctx, zsocket.TextMessage, []byte("queued"))

Middleware Package

middleware includes lightweight helpers:

  • middleware.Auth(...)
  • middleware.NewRateLimiter(...).Handle(...)
  • middleware.Metrics counters

Distributed Hub Adapter

hub/redis.go provides hub.RedisHub built on a minimal pub/sub interface, so you can plug Redis (or any broker) without forcing a concrete dependency in core.

About

A small, gorilla-free WebSocket server for Go — clean API, RFC6455 handshake, frames, ping/pong keepalive, JSON helpers, and a simple room hub. Built to be extended (rate limiting, metrics, distributed hub) without leaking third-party types into your code.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages