Skip to content

Repository files navigation

Cira

A lightweight, event-driven WebSocket framework for Go.

Cira provides an ergonomic abstraction over WebSocket connections with event routing, request-response messaging, synchronous RPC-style calls, and long-lived streams.

Languages

Features

  • Event-driven routing — named events with dot-separated scoping and middleware
  • Bidirectional communication — supports both listening and outbound dialing
  • Five messaging patterns — Push, Request, Response, Call, and Stream
  • Streaming transport — long-lived message streams identified by user-defined IDs
  • Connection management — connection lookup, close callbacks, and contextual execution
  • Customizable — pluggable codec, ID generator, and WebSocket upgrader
  • Lightweight — built on top of gorilla/websocket

Installation

go get github.com/AtoriUzawa/cira

Quick Start

Server

package main

import "github.com/AtoriUzawa/cira"

func main() {
	server := cira.New()

	server.On("hello", func(c *cira.Context) {
		c.Resp(map[string]string{
			"message": "world",
		})
	})

	panic(server.Run(":8080"))
}

Client

package main

import (
	"github.com/AtoriUzawa/cira"
)

func main() {
	client := cira.New()

	conn, err := client.Dial("ws://localhost:8080/ws")
	if err != nil {
		panic(err)
	}

	conn.Do(func(c *cira.Context) {
		_ = c.Push("hello", "world")
	})

	select {}
}

Messaging Patterns

Pattern Description Response
Push One-way event delivery No
Request Request event Optional
Response Reply to a request Yes
Call Request and wait for response Yes
Stream Continuous message transport Multiple

Push

Send a one-way event.

ctx.Push("chat.message", map[string]string{
	"user": "alice",
	"text": "hello",
})

Request

Send a request event without waiting for a response.

ctx.Req("status.update", map[string]bool{
	"online": true,
})

Response

Reply to the current request.

server.On("ping", func(c *cira.Context) {
	c.Resp("pong")
})

Call

Send a request and wait synchronously for a response.

var resp map[string]any

err := ctx.Call(
	"user.info",
	map[string]string{
		"id": "123",
	},
	&resp,
)

if err != nil {
	return
}

Timeout

ctx.Timeout = 5 * time.Second

Default timeout:

30 * time.Second

Stream

Streams provide a long-lived communication channel identified by a stream ID.

Sender

stream := ctx.OpenStream("upload.file")

defer ctx.CloseStream()

_ = stream.Send("chunk_1")
_ = stream.Send("chunk_2")
_ = stream.Send("chunk_3")

Receiver

stream := ctx.OpenStream("upload.file")

defer ctx.CloseStream()

for {
	var chunk string

	err := stream.Recv(&chunk)
	if err != nil {
		break
	}

	fmt.Println(chunk)
}

Stream Timeout

err := stream.RecvTimeout(&chunk)

Default timeout uses:

ctx.Timeout

Middleware

func Logger(next cira.HandlerFunc) cira.HandlerFunc {
	return func(c *cira.Context) {
		log.Println(c.Message.Route)
		next(c)
	}
}

server.Use(Logger)

Middleware executes in reverse registration order.


Routing

Routes support dot-separated grouping.

api := server.Group("api")

api.On("user.list", handler)

Resulting route:

api.user.list

Connection Management

Access Current Connection

server.On("hello", func(c *cira.Context) {
	fmt.Println(c.Conn.ID())
})

Lookup Connection

conn, err := server.Conn(id)
if err != nil {
	return
}

Close Connection

conn.Close()

On Close

conn.OnClose(func() {
	log.Println("connection closed")
})

Configuration

Custom Codec

engine := cira.New(
	cira.WithCodec(myCodec),
)

Custom ID Generator

engine := cira.New(
	cira.WithIDGenerator(myGenerator),
)

Custom WebSocket Upgrader

engine := cira.New(
	cira.WithUpgrader(myUpgrader),
)

Examples

Example Description
examples/hello Minimal server
examples/push Push messaging
examples/request Request messaging
examples/call RPC-style call
examples/stream Stream communication
examples/client Client dial and file upload stream
examples/middleware Middleware usage
examples/connection Connection lifecycle
examples/chatroom Multi-client chatroom

Architecture

┌─────────┐
│ Engine  │
└────┬────┘
     │
┌────▼────┐
│  Peer   │
└────┬────┘
     │
┌────▼────┐
│ Context │
└────┬────┘
     │
 ┌───┴───┐
 │Message│
 │Stream │
 └───────┘

A connection is represented internally as a Peer. Business logic interacts through Conn and Context abstractions.


License

MIT

About

A lightweight WebSocket framework for Go with routing, middleware, push, request-response, and RPC-style communication.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages