Stocking
[WIP] Minimal Websocket Framework with Server(Go) and Client(Javascript)
This is the server-side repository. For the client part, please visit WIP.
Status
Unstable - DO NOT USE IN PRODUCTION
The library is right now under early-stage development for experiment only. APIs may vary at any time.
Installation
go get github.com/afterwind-io/stocking
Documentation
Usage
package main
import "github.com/afterwind-io/stocking"
func main() {
server := stocking.NewStocking("localhost:12345", "")
server.On("echo", echo, nil)
server.On("greet", greet, person{})
server.Otherwise(otherwise)
server.Start()
}
type person struct {
Name string `json:"name"`
}
func echo(p stocking.RouterPackage) (interface{}, error) {
return p.Body, nil
}
func greet(p stocking.RouterPackage) (interface{}, error) {
body, _ := p.Body.(*person)
if body.Name == "doge" {
return "Hello " + body.Name, nil
}
return "Who are you?", nil
}
func otherwise(p stocking.RouterPackage) (interface{}, error) {
return "oops", nil
}
Protocol
Structure
The client and the server communicates based on string formated as following:
[MessageType],[ControlCode],[Content]
eg: 4,0,{e: "echo", p: "doge"}
Client -> Server
MessageType | ControlCode | Payload | Brief |
---|
Connect | 0 | NONE | Initial connection (Not Implemented) |
| 1 | NONE | Reconnection (Not Implemented) |
Close | NONE | NONE | Close connection |
PingPong | NONE | NONE | Start PingPong minigame ¯\(ツ)/¯ |
Message | 0 | (See Below) | Message without callback |
| Int > 0 | (See Below) | Message with callback indexed by CCode |
Broadcast | String | Any | Broadcast to a channel/room named by CCode |
Join | 1 | String | Join a channel/room |
| 0 | String | Leave a channel/room |
Server -> Client
MessageType | ControlCode | Payload | Brief |
---|
Connect | NONE | NONE | Connection confirm |
Error | Int | String | Server error |
Close | NONE | NONE | Close connection |
PingPong | NONE | NONE | Start PingPong minigame ¯\(ツ)/¯ |
Message | Int > 0 | (See Below) | Callback message indexed by CCode |
Broadcast | String | Any | Channel/Room message from CCode |
Message Type
type TextMessageProtocol struct {
Event string `json:"e"`
Payload json.RawMessage `json:"p"`
}
type RouterMessageProtocol struct {
Code int `json:"c"`
Payload interface{} `json:"p"`
}
More details see protocol.go
Middleware
Middleware design in Stocking
is largely inspired by Koa. I managed to mimic similar syntax using goroute
and channel
. The following logger example shows how basic middleware looks like:
func (me *mLogger) Handle(p *HubPackge, next MiddlewareStepFunc) {
log.Println(fmt.Sprintf("<-- [%v] %v, %v, %v", p.client.id, p.mtype, p.ack, p.content))
done := <-next(nil)
log.Println(fmt.Sprintf("--> [%v] %v, %v, %v", p.client.id, p.mtype, p.ack, p.content))
done <- nil
}
Roadmap
Known Flaws
- If an error occurs and breaks the
Read
/Write
loop, there's currently no graceful way to stop the other one. -> client.go - If client route handler panics, the whole server just faint away :( -> mRouter.go
- Route handling stops the world. -> hub.go
Trivia
- Why name it "
Stocking
"?
I'm a fan of white stocking Just put a "t" in "Sock". Besides, Christmas is coming.
License
MIT