stocking

package module
v0.0.0-...-ffdfa38 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2018 License: MIT Imports: 10 Imported by: 0

README

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() {
  // Create a standalone server
  server := stocking.NewStocking("localhost:12345", "")

  // Setup routers
  server.On("echo", echo, nil)
  server.On("greet", greet, person{})
  server.Otherwise(otherwise)
  
  // Start serving on ws://localhost:12345/ws
  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
// Message type when sent to server
type TextMessageProtocol struct {
  // The event name
  Event   string          `json:"e"`

  // Payload should be interface{} here.
  // json.RawMessage ensures that we can unmarshal it
  // to the actual type we need later.
  Payload json.RawMessage `json:"p"`
}

// Message type when sent to client through router
type RouterMessageProtocol struct {
  // Code indicates the error type.
  // -1 means no error;
  // 0 is the default error code;
  // You can put other value here by throwing a RouterError;
  Code    int         `json:"c"`

  // The Message body
  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) {
  // [Downstream Jobs] Do some inbound logs here
  log.Println(fmt.Sprintf("<-- [%v] %v, %v, %v", p.client.id, p.mtype, p.ack, p.content))

  // Temporarily suspended and pass the control to the next middleware
  done := <-next(nil)
  
  // Meanwhile downstream middlewares are doing their own jobs now

  // After they finished their jobs, the control flow rewinds,
  // and middlewares are resumed to perform its upstream jobs, in reverse order

  // [Upstream Jobs] Now grab outbound messages and log it
  log.Println(fmt.Sprintf("--> [%v] %v, %v, %v", p.client.id, p.mtype, p.ack, p.content))

  // duty ends here
  done <- nil
}

Roadmap

  • At least it is kinda working
  • Broadcast
  • Channel
  • Auto-Reconnect

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

Documentation

Overview

Package stocking is a minimal websocket framework based on http://github.com/gorilla/websocket. It provides easy-to-use APIs, for those who only wants basic functions to play with, or finish some simple jobs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client represents the... um... websocket client

func (*Client) Close

func (c *Client) Close()

Close the connection

type Hub

type Hub struct {
	// contains filtered or unexported fields
}

Hub TODO

type HubPackge

type HubPackge struct {
	// contains filtered or unexported fields
}

HubPackge TODO

type Middleware

type Middleware interface {
	Handle(p *HubPackge, next MiddlewareStepFunc)
}

Middleware TODO

type MiddlewareStepFunc

type MiddlewareStepFunc = func(err error) chan chan error

MiddlewareStepFunc TODO

type RouterError

type RouterError struct {
	// contains filtered or unexported fields
}

RouterError TODO

func NewTextRouterError

func NewTextRouterError(msg string) RouterError

NewTextRouterError TODO

func (RouterError) Error

func (e RouterError) Error() string

type RouterHandler

type RouterHandler = func(p *RouterPackage) (interface{}, error)

RouterHandler TODO

type RouterMessageProtocol

type RouterMessageProtocol struct {
	Code    int         `json:"c"`
	Payload interface{} `json:"p"`
}

RouterMessageProtocol TODO

type RouterPackage

type RouterPackage struct {
	Client *Client
	Route  string
	Body   interface{}
}

RouterPackage TODO

type Stocking

type Stocking struct {
	// the address for http.ListenAndServe
	Host string
	// the root pattern for connection
	Root string
	// the underlying Upgrader for gorilla/websocket
	Upgrader websocket.Upgrader
}

Stocking is the instance of the websocket server with basic configs

func NewStocking

func NewStocking(host, root string) *Stocking

NewStocking creates and returns a new stocking, server I mean.

func (*Stocking) Attach

func (s *Stocking) Attach()

Attach root handler to an existing http server

func (*Stocking) On

func (s *Stocking) On(route string, handler RouterHandler, typeHint interface{})

On adds a route handler

func (*Stocking) Otherwise

func (s *Stocking) Otherwise(handler RouterHandler)

Otherwise adds a fallback handler when no route hits

func (*Stocking) Start

func (s *Stocking) Start()

Start the server

func (*Stocking) Use

func (s *Stocking) Use(ms ...Middleware)

Use adds a middleware

type TextMessageProtocol

type TextMessageProtocol struct {
	Event   string          `json:"e"`
	Payload json.RawMessage `json:"p"`
}

TextMessageProtocol TODO

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL