tcpx

package module
v0.0.0-...-59f5a4e Latest Latest
Warning

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

Go to latest
Published: Nov 5, 2020 License: MIT Imports: 25 Imported by: 0

README

A very convenient tcp framework in golang.

Supporting protocols

Declaration

Since some dependencies, (github.com/xtaci/kcp-go --> github.com/klauspost/reedsolomon, github.com/xtaci/kcp-go --> github.com/templexxx/*), ,stop supporting old go versions, which conflicts to my opinion, tcpx decides stop supporting kcp.And tcp.v3.0.0 is the last version to use it running kcp server.

Table of Contents generated with DocToc

Why designing tcp framwork rather than the official?

Golang has greate support of tcp protocol in official libraries, but users still need to consider details, most profiling way will make project heavier and heavier.Tpcx aims to use tcp in a most friendly way.Most ussage paterns are like github.com/gin-gonic/gin.Users don't consider details. All they are advised touching is a context, most apis in gin are also accessable in tcpx.

1. Start

go get github.com/fwhezfwhez/tcpx

Dependency

if you want to run program in this repo,you should prepare protoc,proto-gen-go environment. It's good to compile yourself from these repos,but there is already release versions referring to their doc. Make sure run protoc --version available.

protoc: https://github.com/golang/protobuf

proto-gen-go:https://github.com/golang/protobuf/tree/master/protoc-gen-go

Benchmark

https://github.com/fwhezfwhez/tcpx/blob/master/benchmark_test.go

cases exec times cost time per loop cost mem per loop cost object num per loop url
OnMessage 2000000 643 ns/op 1368 B/op 5 allocs/op click to location
Mux without middleware 2000000 761 ns/op 1368 B/op 5 allocs/op click to location
Mux with middleware 2000000 768 ns/op 1368 B/op 5 allocs/op click to location

2. Example

https://github.com/fwhezfwhez/tcpx/tree/master/examples/sayHello

Helloworld

server:

package main

import (
	"fmt"

	"github.com/fwhezfwhez/tcpx"
)

func main() {
	srv := tcpx.NewTcpX(nil)
	srv.OnMessage = func(c *tcpx.Context) {
		var message []byte
		c.Bind(&message)
		fmt.Println(string(message))
	}
	srv.ListenAndServe("tcp", "localhost:8080")
}

client:

package main

import (
	"fmt"
	"net"

	"github.com/fwhezfwhez/tcpx"
	//"tcpx"
)

func main() {
	conn, e := net.Dial("tcp", "localhost:8080")

	if e != nil {
		panic(e)
	}
	var message = []byte("hello world")
	buf, e := tcpx.PackWithMarshaller(tcpx.Message{
		MessageID: 1,
		Header:    nil,
		Body:      message,
	}, nil)
	if e != nil {
		fmt.Println(e.Error())
		return
	}
	_, e = conn.Write(buf)
	if e != nil {
		fmt.Println(e.Error())
		return
	}
}

2.1 Heartbeat

https://github.com/fwhezfwhez/tcpx/tree/master/examples/modules/heartbeat

tcpx has built-in heartbeat handler. Default heartbeat messageID is 1392.It means client should send heartbeat pack in specific interval.When fail received more than 3 times, connection will break by server.

srv side

    srv := tcpx.NewTcpX(nil)
    srv.HeartBeatModeDetail(true, 10 * time.Second, false, tcpx.DEFAULT_HEARTBEAT_MESSAGEID)

client side

        var heartBeat []byte
        heartBeat, e = tcpx.PackWithMarshaller(tcpx.Message{
            MessageID: tcpx.DEFAULT_HEARTBEAT_MESSAGEID,
            Header:    nil,
            Body:      nil,
        }, nil)
        for {
            conn.Write(heartBeat)
            time.Sleep(10 * time.Second)
        }

rewrite heartbeat handler

    srv.RewriteHeartBeatHandler(1300, func(c *tcpx.Context) {
        fmt.Println("rewrite heartbeat handler")
        c.RecvHeartBeat()
    })
2.2 Online/Offline

https://github.com/fwhezfwhez/tcpx/tree/master/examples/modules/online-offline

2.3 Graceful

https://github.com/fwhezfwhez/tcpx/tree/master/examples/modules/graceful

  • Graceful exit

Catch signal and do jobs arranged

  • Graceful stop

two strategies:

  1. closeAllConnection = false :Stop listen on, but no effect to existed connection

  2. closeAllConnection = true :Stop listen on, stops all connection including connected clients.

  • Graceful restart:

Contains graceful stop and graceful start. Between them, you can add jobs you want.

2.4 Middleware

https://github.com/fwhezfwhez/tcpx/tree/master/examples/modules/middleware

It tells usages of using middleware.

2.5 Pack-detail

https://github.com/fwhezfwhez/tcpx/tree/master/examples/modules/pack-detail

Provides tcpx pack detail.

2.6 Chat

https://github.com/fwhezfwhez/tcpx/tree/master/examples/modules/chat

It examples a chat using tcpx.

2.7 Raw

https://github.com/fwhezfwhez/tcpx/tree/master/examples/modules/raw

It examples how to send stream without rule, nothing to do with messageID system. You can send all stream you want. Global middleware and anchor middleware are still working as the example said.

2.8 ClientPool

https://github.com/fwhezfwhez/tcpx/tree/master/examples/modules/online-offline

Example shares with 2.2.

Tcpx has its built-in pool to help manage online and offline users. Note that :

  • To use built-in pool, you need to run srv.WithBuiltInPool(true).
  • To online/offline a user, you can do it like ctx.Offline(),ctx.Online(username string).

Official built-in pool will not extend much. If it doesn't fit your requirement, you should design your own pool.

2.9 Auth

https://github.com/fwhezfwhez/tcpx/tree/master/examples/modules/auth

Auth makes different sense comparing with middleware. A middleware can easily stop a invalid request after a connection has been established, but It can't avoid a client keep sending heartbeat but do nothing.It still occupy a connection resource.

Auth will start a goroutine once a connection is on. In a specific interval not receiving signal, connection will be forcely dropped by server side.

3. Ussages

Now tcpx advises two modes handling stream, using OnMessage requires user handling stream by himself

Using OnMessage

func main(){
    srv := tcpx.NewTcpX(tcpx.JsonMarshaller{})
    srv.OnClose = OnClose
    srv.OnConnect = OnConnect
    srv.OnMessage = OnMessage

    go func(){
        fmt.Println("tcp srv listen on 7171")
        if e := srv.ListenAndServe("tcp", ":7171"); e != nil {
            panic(e)
        }
    }()

    // udp
    go func(){
        fmt.Println("udp srv listen on 7172")
        if e := srv.ListenAndServe("udp", ":7172"); e != nil {
            panic(e)
        }
    }()
    // kcp
    go func(){
        fmt.Println("kcp srv listen on 7173")
        if e := srv.ListenAndServe("kcp", ":7173"); e != nil {
            panic(e)
        }
    }()
    select {}
}

func OnConnect(c *tcpx.Context) {
    fmt.Println(fmt.Sprintf("connecting from remote host %s network %s", c.ClientIP(), c.Network()))
}
func OnClose(c *tcpx.Context) {
    fmt.Println(fmt.Sprintf("connecting from remote host %s network %s has stoped", c.ClientIP(), c.Network())
}
var packx = tcpx.NewPackx(tcpx.JsonMarshaller{})
func OnMessage(c *tcpx.Context) {
    // handle c.Stream
    type ServiceA struct{
        Username string `json:"username"`
    }
    type ServiceB struct{
        ServiceName string `json:"service_name"`
    }

    messageID, e :=packx.MessageIDOf(c.Stream)
    if e!=nil {
        fmt.Println(errorx.Wrap(e).Error())
        return
    }

    switch messageID {
    case 7:
        var serviceA ServiceA
        // block, e := packx.Unpack(c.Stream, &serviceA)
        block, e :=c.Bind(&serviceA)
        fmt.Println(block, e)
        c.Reply(8, "success")
    case 9:
        var serviceB ServiceB
        //block, e := packx.Unpack(c.Stream, &serviceB)
        block, e :=c.Bind(&serviceB)
        fmt.Println(block, e)
        c.JSON(10, "success")
    }
}

Using routine mux

func main(){
    srv := tcpx.NewTcpX(tcpx.JsonMarshaller{})
    srv.OnClose = OnClose
    srv.OnConnect = OnConnect
    // srv.OnMessage = OnMessage

    srv.UseGlobal(MiddlewareGlobal)
    srv.Use("middleware1", Middleware1, "middleware2", Middleware2)
    srv.AddHandler(1, SayHello)

    srv.UnUse("middleware2")
    srv.AddHandler(3, SayGoodBye)

    if e := srv.ListenAndServe("tcp", ":7171"); e != nil {
        panic(e)
    }
}

func OnConnect(c *tcpx.Context) {
    fmt.Println(fmt.Sprintf("connecting from remote host %s network %s", c.ClientIP(), c.Network()))
}
func OnClose(c *tcpx.Context) {
    fmt.Println(fmt.Sprintf("connecting from remote host %s network %s has stoped", c.ClientIP(), c.Network())
}
// func OnMessage(c *tcpx.Context) {
    // handle c.Stream
// }
func SayHello(c *tcpx.Context) {
    var messageFromClient string
    var messageInfo tcpx.Message
    messageInfo, e := c.Bind(&messageFromClient)
    if e != nil {
        panic(e)
    }
    fmt.Println("receive messageID:", messageInfo.MessageID)
    fmt.Println("receive header:", messageInfo.Header)
    fmt.Println("receive body:", messageInfo.Body)

    var responseMessageID int32 = 2
    e = c.Reply(responseMessageID, "hello")
    fmt.Println("reply:", "hello")
    if e != nil {
        fmt.Println(e.Error())
    }
}

func SayGoodBye(c *tcpx.Context) {
    var messageFromClient string
    var messageInfo tcpx.Message
    messageInfo, e := c.Bind(&messageFromClient)
    if e != nil {
        panic(e)
    }
    fmt.Println("receive messageID:", messageInfo.MessageID)
    fmt.Println("receive header:", messageInfo.Header)
    fmt.Println("receive body:", messageInfo.Body)

    var responseMessageID int32 = 4
    e = c.Reply(responseMessageID, "bye")
    fmt.Println("reply:", "bye")
    if e != nil {
        fmt.Println(e.Error())
    }
}
func Middleware1(c *tcpx.Context) {
    fmt.Println("I am middleware 1 exampled by 'srv.Use(\"middleware1\", Middleware1)'")
}

func Middleware2(c *tcpx.Context) {
    fmt.Println("I am middleware 2 exampled by 'srv.Use(\"middleware2\", Middleware2),srv.UnUse(\"middleware2\")'")
}

func Middleware3(c *tcpx.Context) {
    fmt.Println("I am middleware 3 exampled by 'srv.AddHandler(5, Middleware3, SayName)'")
}

func MiddlewareGlobal(c *tcpx.Context) {
    fmt.Println("I am global middleware exampled by 'srv.UseGlobal(MiddlewareGlobal)'")
}

3.1 How to add middlewares?

Middlewares in tcpx has three types: GlobalTypeMiddleware, MessageIDSelfRelatedTypeMiddleware,AnchorTypeMiddleware. GlobalTypeMiddleware:

    srv := tcpx.NewTcpX(tcpx.JsonMarshaller{})
    srv.UseGlobal(MiddlewareGlobal)

MessageIDSelfRelatedTypeMiddleware:

    srv := tcpx.NewTcpX(tcpx.JsonMarshaller{})
    srv.AddHandler(5, Middleware3, SayName)

AnchorTypeMiddleware:

    srv := tcpx.NewTcpX(tcpx.JsonMarshaller{})
    srv.Use("middleware1", Middleware1, "middleware2", Middleware2)
    srv.AddHandler(5, SayName)

middleware example:

func Middleware1(c *tcpx.Context) {
    fmt.Println("I am middleware 1 exampled by 'srv.Use(\"middleware1\", Middleware1)'")
    // c.Next()
    // c.Abort()
}

middleware order: GlobalTypeMiddleware -> AnchorTypeMiddleware -> MessageIDSelfRelatedTypeMiddleware. if one of middleware has called c.Abort(), middleware chain stops.

ATTENTION: If srv.OnMessage is not nil, only GlobalTypeMiddleware and AnchorTypeMiddleware will make sense regardless of AnchorTypeMiddleware being UnUsed or not.

3.2 When to use OnMessage callback?

OnMessage 's minimum unit block is each message, whenOnMessage is not nil, mux will lose its effects.

srv.OnMessage = OnMessage
srv.AddHandler(1, SayName) // no use, because OnMessage is not nil, user should handle c.Stream by himself

In the mean time, global middlewares and anchor middlewares will all make sense regardless of anchor middlewares being unUsed or not. Here is part of source code:

go func(ctx *Context, tcpx *TcpX) {
        if tcpx.OnMessage != nil {
            ...
        } else {
            messageID, e := tcpx.Packx.MessageIDOf(ctx.Stream)
            if e != nil {
                Logger.Println(errorx.Wrap(e).Error())
                return
            }
            handler, ok := tcpx.Mux.Handlers[messageID]
            if !ok {
                Logger.Println(fmt.Sprintf("messageID %d handler not found", messageID))
                return
            }
            ...
        }
    }(ctx, tcpx)

As you can see,it's ok if you do it like:

func main(){
    ...
    srv := tcpx.NewTcpX(tcpx.JsonMarshaller{})
    srv.OnMessage = onMessage
    ...
}
func onMessage(c *tcpx.Context){
    func(stream []byte){
        // handle raw stream
    }(c.Stream)
}

Attention: Stream has been packed per request, no pack stuck probelm.

3.3 How to design a message?

You don't need to design message block yourself.Instead do it like: client

func main(){
    var packx = tcpx.NewPackx(tcpx.JsonMarshaller{})
    buf1, e := packx.Pack(5, "hello,I am client xiao ming")
    buf2, e := packx.Pack(7, struct{
    Username string
    Age int
    }{"xiaoming", 5})
    ...
}

If you're not golang client, see 3.5 How client (not only golang) builds expected stream?

3.4 How to specific marshal type?

Now, tcpx supports json,xml,protobuf,toml,yaml like:

client

var packx = tcpx.NewPackx(tcpx.JsonMarshaller{})
// var packx = tcpx.NewPackx(tcpx.XmlMarshaller{})
// var packx = tcpx.NewPackx(tcpx.ProtobufMarshaller{})
// var packx = tcpx.NewPackx(tcpx.TomlMarshaller{})
// var packx = tcpx.NewPackx(tcpx.YamlMarshaller{})

server

srv := tcpx.NewTcpX(tcpx.JsonMarshaller{})
// srv := tcpx.NewTcpX(tcpx.XmlMarshaller{})
// srv := tcpx.NewTcpX(tcpx.ProtobufMarshaller{})
// srv := tcpx.NewTcpX(tcpx.TomlMarshaller{})
// srv := tcpx.NewTcpX(tcpx.YamlMarshaller{})

if you want any marshal way else, design it like:

type OtherMarshaller struct{}
func (om OtherMarshaller) Marshal(v interface{}) ([]byte, error) {
    return []byte(""), nil
}
func (om OtherMarshaller) Unmarshal(data []byte, dest interface{}) error {
    return nil
}
func (om OtherMarshaller) MarshalName() string{
    return "other_marshaller"
}

client

var packx = tcpx.NewPackx(OtherMarshaller{})

server

srv := tcpx.NewTcpX(tcpx.OtherMarshaller{})

3.5 How client (not only golang) builds expected stream?

Tcpx now only provide packx realized in golang to build a client sender.If you wants to send message from other language client, you'll have two ways:

  1. Be aware of messageID block system and build expected stream in specific language.Refer -> 2.5 pack-detail.
  2. Using http gateway,refers to 5. cross-language gateway

messageID block system:

[4]byte -- length             fixed_size,binary big endian encode
[4]byte -- messageID          fixed_size,binary big endian encode
[4]byte -- headerLength       fixed_size,binary big endian encode
[4]byte -- bodyLength         fixed_size,binary big endian encode
[]byte -- header              marshal by json
[]byte -- body                marshal by marshaller

Since not all marshal ways support marshal map, header are fixedly using json. Here are some language building stream: java:

//

js:

//

ruby:

//

Welcome to provides all language pack example via pull request, you can valid you result stream refers to unpack http gateway 5. cross-language gateway

3.6 Can user design his own message rule rather than tcpx.Message pack rule?

Yes! But you can't share the advantages of messageID usage.

way 1: Refer to 2.7 Raw.In this case, you must start another port and use srv.HandleRaw.

If you have your own format stream style, which different from messageID system, you can do it like:

way 2: developing……

3.7 How to separate handlers?

tcpx's official advised routing way is separating handlers by messageID, like

func main(){
    srv := tcpx.NewTcpX(tcpx.JsonMarshaller{})
    // request messageID 1
    // response messageID 2
    srv.AddHandler(1, SayHello)
    if e := srv.ListenAndServe("tcp", ":7171"); e != nil {
        panic(e)
    }
}
func SayHello(c *tcpx.Context) {
    var messageFromClient string
    var messageInfo tcpx.Message
    messageInfo, e := c.Bind(&messageFromClient)
    if e != nil {
        panic(e)
    }
    fmt.Println("receive messageID:", messageInfo.MessageID)
    fmt.Println("receive header:", messageInfo.Header)
    fmt.Println("receive body:", messageInfo.Body)

    var responseMessageID int32 = 2
    e = c.Reply(responseMessageID, "hello")
    fmt.Println("reply:", "hello")
    if e != nil {
        fmt.Println(e.Error())
    }
}

4. Frequently used methods

All methods can be refered in https://godoc.org/github.com/fwhezfwhez/tcpx Here are those frequently used methods apart by their receiver type. args omit

4.1 tcpx.TcpX

srv := tcpx.NewTcpX(tcpx.JsonMarshaller{})
methods desc
srv.GlobalUse() use global middleware
srv.Use() use a middleware
srv.UnUse() unUse a middleware, handlers added before this still work on unUsed middleware, handlers after don't
srv.AddHandler() add routed handler by messageID(int32)
srv.ListenAndServe() start listen on

4.2 tcpx.Context

var c *tcpx.Context
methods desc
c.Bind() bind data of stream into official message type
c.Reply() reply to client via c.Conn, marshalled by c.Packx.Marshaller
c.Next() middleware goes to next
c.Abort() middleware chain stops
c.JSON() reply to client via c.Conn, marshalled by tcpx.JsonMarshaller
c.XML() reply to client via c.Conn, marshalled by tcpx.XmlMarshaller
c.YAML() reply to client via c.Conn, marshalled by tcpx.YamlMarshaller
c.Protobuf() reply to client via c.Conn, marshalled by tcpx.ProtobufMarshaller
c.TOML() reply to client via c.Conn, marshalled by tcpx.TomlMarshaller

4.3 tcpx.Packx

var packx *tcpx.Packx
methods desc
packx.Pack() pack data into expected stream
packx.UnPack() reverse above returns official message type
packx. MessageIDOf() get messageID of a stream block
packx.LengthOf() length of stream except total length, total length +4 or len(c.Stream)

4.4 tcpx.Message

var message tcpx.Message
methods desc
message.Get() get header value by key
message.Set() set header value

5. Cross-language gateway

gateway repo: https://github.com/fwhezfwhez/tcpx/tree/master/gateway/pack-transfer

example: https://github.com/fwhezfwhez/tcpx/tree/master/examples/use-gateway

go run main.go -port 7000 run the gateway locally in port 7000 or else.

5.1 Gateway pack detail

note: Each message should call once

POST http://localhost:7000/gateway/pack/transfer/
application/json

body:

{
    "marshal_name":<marshal_name>,
    "stream": <stream>,
    "message_id": <message_id>,
    "header": <header>
}
field type desc example nessessary
marshal_name string ranges in "json","xml", "toml", "yaml", "protobuf" "json" yes
stream []byte stream should be well marshalled by one of marshal_name yes
message_id int32 int32 type messageID 1 yes
header map/object key-value pairs {"k1":"v1"} no

returns:

{
    "message":<message>,
    "stream":<stream>
}
field type desc example nessessary
message string "success" when status 200, "success", "error message" when 400/500 "success" yes
stream []byte packed stream,when error or status not 200, no stream field no

example:

payload:

{"username": "hello, tcpx"}   ---json-->  "eyJ1c2VybmFtZSI6ImhlbGxvLCB0Y3B4In0="

request:

{
    "marshal_name": "json",
    "stream": "eyJ1c2VybmFtZSI6ImhlbGxvLCB0Y3B4In0=",
    "message_id": 1,
    "header": {
      "api": "/pack/"
    }
}

example response:

{
    "stream": "AAAANgAAAAEAAAAQAAAAGnsiYXBpIjoiL3BhY2svIn17InVzZXJuYW1lIjoiaGVsbG8sIHRjcHgifQ=="
}
5.2 Gateway unpack detail

note: able to unpack many messages once.

POST http://localhost:7000/gateway/unpack/transfer/
application/json

body:

{
    "marshal_name": <marshal_name>,
    "stream": <stream>
}
field type desc example nessessary
marshal_name string ranges in "json","xml", "toml", "yaml", "protobuf" "json" yes
stream []byte packed stream no

returns:

{
    "message": <message>,
    "blocks" <blocks>
}
field type desc example nessessary
message string "success" when status 200, "success", "error message" when 400/500 "success" yes
blocks []block unpacked blocks, when status not 200, no this field no
block obj each message block information, when status not 200,no this field ++ look below++ no

block example:

{
    "message_id": 1,
    "header": {"k1":"v1"},
    "marshal_name": "json",
    "stream": "eyJ1c2VybmFtZSI6ImhlbGxvLCB0Y3B4In0="
}

example request:

{
    "marshal_name": "json",
    "stream": "AAAANgAAAAEAAAAQAAAAGnsiYXBpIjoiL3BhY2svIn17InVzZXJuYW1lIjoiaGVsbG8sIHRjcHgifQ=="
}

example response:

{
    "message": "success",
    "blocks": [
      {
        "message_id": 1,
        "header": {
          "k1": "v1"
        },
        "marshal_name": "json",
        "stream": "eyJ1c2VybmFtZSI6ImhlbGxvLCB0Y3B4In0="
      }
    ]
}

to payload:

"eyJ1c2VybmFtZSI6ImhlbGxvLCB0Y3B4In0="   ---json-->  {"username": "hello, tcpx"}

Documentation

Overview

Package tcpx provides udp,tcp,kcp three kinds of protocol.

Index

Constants

View Source
const (
	// debug mode, logger of tcpx will print
	DEBUG = 1 + iota
	// release mode, logger of tcpx will not print
	RELEASE
)
View Source
const (
	SERVER_ERROR = 500
	CLIENT_ERROR = 400
	OK           = 200
	NOT_AUTH     = 403
)
View Source
const (
	DEFAULT_HEARTBEAT_MESSAGEID = 1392
	DEFAULT_AUTH_MESSAGEID      = 1393

	STATE_RUNNING = 1
	STATE_STOP    = 2

	PIPED = "[tcpx-buffer-in-serial]"
)
View Source
const ABORT = 2019
View Source
const CONTEXT_OFFLINE = 2
View Source
const CONTEXT_ONLINE = 1
View Source
const (
	// context's anchor middleware will expire when call UnUse(),
	// middleware added by Use() will be set 2019 anchor index by default
	NOT_EXPIRE = 2019
)

Variables

View Source
var Logger = Log{
	Logger: log.New(os.Stderr, "[tcpx] ", log.LstdFlags|log.Llongfile),
	Mode:   DEBUG,
}

Global instance of logger

View Source
var PackJSON = NewPackx(JsonMarshaller{})
View Source
var PackProtobuf = NewPackx(ProtobufMarshaller{})
View Source
var PackTOML = NewPackx(TomlMarshaller{})
View Source
var PackYAML = NewPackx(YamlMarshaller{})

Functions

func BindJSON

func BindJSON(bodyBuf []byte, dest interface{}) error

func BodyBytesOf

func BodyBytesOf(stream []byte) ([]byte, error)

body bytes of a block

func BodyLengthOf

func BodyLengthOf(stream []byte) (int32, error)

Body length of a stream received

func CloseChanel

func CloseChanel(f func())

CloseChanel(func(){close(chan)})

func Debug

func Debug(src interface{}) string

func Defer

func Defer(f func(), handlePanicError ...func(interface{}))

Defer eliminates all panic cases and handle panic reason by handlePanicError

func FirstBlockOf

func FirstBlockOf(r io.Reader) ([]byte, error)

Since FirstBlockOf has nothing to do with packx instance, so make it alone, for old usage remaining useful, old packx.FirstBlockOf is still useful

func FirstBlockOfBytes

func FirstBlockOfBytes(buffer []byte) ([]byte, error)

func HeaderBytesOf

func HeaderBytesOf(stream []byte) ([]byte, error)

Header bytes of a block

func HeaderLengthOf

func HeaderLengthOf(stream []byte) (int32, error)

Header length of a stream received

func HeaderOf

func HeaderOf(stream []byte) (map[string]interface{}, error)

header of a block

func In

func In(s string, arr []string) bool

Whether s in arr Support %%

func LengthOf

func LengthOf(stream []byte) (int32, error)

Length of the stream starting validly. Length doesn't include length flag itself, it refers to a valid message length after it.

func MD5

func MD5(rawMsg string) string

func MessageIDOf

func MessageIDOf(stream []byte) (int32, error)

messageID of a stream. Use this to choose which struct for unpacking.

func PackHeartbeat

func PackHeartbeat() []byte

func PackStuff

func PackStuff(messageID int32) []byte

pack short signal which only contains messageID

func PackWithMarshaller

func PackWithMarshaller(message Message, marshaller Marshaller) ([]byte, error)

PackWithMarshaller will encode message into blocks of length,messageID,headerLength,header,bodyLength,body. Users don't need to know how pack serializes itself if users use UnpackPWithMarshaller.

If users want to use this protocol across languages, here are the protocol details: (they are ordered as list) [0 0 0 24 0 0 0 1 0 0 0 6 0 0 0 6 2 1 19 18 13 11 11 3 1 23 12 132] header: [0 0 0 24] mesageID: [0 0 0 1] headerLength, bodyLength [0 0 0 6] header: [2 1 19 18 13 11] body: [11 3 1 23 12 132] [4]byte -- length fixed_size,binary big endian encode [4]byte -- messageID fixed_size,binary big endian encode [4]byte -- headerLength fixed_size,binary big endian encode [4]byte -- bodyLength fixed_size,binary big endian encode []byte -- header marshal by json []byte -- body marshal by marshaller

func PackWithMarshallerAndBody

func PackWithMarshallerAndBody(message Message, body []byte) ([]byte, error)

This method is used to pack message whose body is well-marshaled.

func PackWithMarshallerName

func PackWithMarshallerName(message Message, marshallerName string) ([]byte, error)

same as above

func PipeJSON

func PipeJSON(conn net.Conn, args ...interface{}) error

func ReadAllUDP

func ReadAllUDP(conn net.PacketConn, maxBufferSize ...int) ([]byte, net.Addr, error)

func SetLogFlags

func SetLogFlags(flags int)

Set global instance logger flags

func SetLogMode

func SetLogMode(mode int)

Set global instance logger mode

func TCPCallOnceJSON

func TCPCallOnceJSON(network string, url string, messageID int, data interface{}) error

func TCPConnect

func TCPConnect(network string, url string) (net.Conn, error)

TCPConnect will establish a tcp connection and return it

func UnPackFromReader

func UnPackFromReader(r io.Reader) (int32, map[string]interface{}, []byte, error)

returns the first block's messageID, header, body marshalled stream, error.

func UnpackToBlockFromReader

func UnpackToBlockFromReader(reader io.Reader) ([]byte, error)

unpack the first block from the reader. protocol is PackWithMarshaller(). [4]byte -- length fixed_size,binary big endian encode [4]byte -- messageID fixed_size,binary big endian encode [4]byte -- headerLength fixed_size,binary big endian encode [4]byte -- bodyLength fixed_size,binary big endian encode []byte -- header marshal by json []byte -- body marshal by marshaller ussage:

for {
    blockBuf, e:= UnpackToBlockFromReader(reader)
	   go func(buf []byte){
        // handle a message block apart
    }(blockBuf)
    continue
}

func WriteConn

func WriteConn(buf []byte, conn net.Conn) error

Write full buf In case buf is too big and conn can't write once.

if len(buf)>65535 {
    connLock.Lock()
    WriteConn(buf, conn)
    connLock.Unlock()
 } else {
    conn.Write(buf)
}

func WriteJSON

func WriteJSON(conn net.Conn, messageID int32, message interface{}) error

WriteJSON will write conn a message wrapped by tcpx.JSONMarshaller

Types

type AnchorMiddlewareInfo

type AnchorMiddlewareInfo struct {
	WhereUse   []string
	WhereUnUse []string
}

type ClientPool

type ClientPool struct {
	Clients map[string]*Context
	// contains filtered or unexported fields
}
var GlobalClientPool *ClientPool

func NewClientPool

func NewClientPool() *ClientPool

func (*ClientPool) DeleteFromClientPool

func (cp *ClientPool) DeleteFromClientPool(username string)

func (*ClientPool) GetClientPool

func (cp *ClientPool) GetClientPool(username string) *Context

func (*ClientPool) Offline

func (cp *ClientPool) Offline(username string)

func (*ClientPool) Online

func (cp *ClientPool) Online(username string, ctx *Context)

func (*ClientPool) SetClientPool

func (cp *ClientPool) SetClientPool(username string, ctx *Context)

type Context

type Context struct {
	// for tcp conn
	Conn net.Conn
	// context scope lock
	L *sync.RWMutex

	// for udp conn
	PacketConn net.PacketConn
	Addr       net.Addr

	// for k-v pair shared in connection/request scope
	PerConnectionContext *sync.Map
	PerRequestContext    *sync.Map

	// for pack and unpack
	Packx *Packx

	// for raw message
	ConnReader io.Reader
	ConnWriter io.Writer

	Stream []byte
	// contains filtered or unexported fields
}

Context has two concurrently safe context: PerConnectionContext is used for connection, once the connection is built ,this is connection scope. PerRequestContext is used for request, when connection was built, then many requests can be sent between client and server. Each request has an independently scoped context , this is PerRequestContext. Packx used to save a marshaller helping marshal and unMarshal stream Stream is read from net.Conn per request

func NewContext

func NewContext(conn net.Conn, marshaller Marshaller) *Context

New a context. This is used for new a context for tcp server.

func NewTCPContext

func NewTCPContext(conn net.Conn, marshaller Marshaller) *Context

New a context. This is used for new a context for tcp server.

func NewUDPContext

func NewUDPContext(conn net.PacketConn, addr net.Addr, marshaller Marshaller) *Context

New a context. This is used for new a context for udp server.

func (*Context) Abort

func (ctx *Context) Abort()

stop middleware chain

func (*Context) AuthChan

func (ctx *Context) AuthChan() <-chan int

func (*Context) Bind

func (ctx *Context) Bind(dest interface{}) (Message, error)

func (*Context) BindWithMarshaller

func (ctx *Context) BindWithMarshaller(dest interface{}, marshaller Marshaller) (Message, error)

BindWithMarshaller will specific marshaller. in contract, c.Bind() will use its inner packx object marshaller

func (Context) ClientIP

func (ctx Context) ClientIP() string

client ip

func (*Context) CloseConn

func (ctx *Context) CloseConn() error

Close its connection

func (*Context) ConnectionProtocolType

func (ctx *Context) ConnectionProtocolType() string

ConnectionProtocol returns server protocol, tcp, udp, kcp

func (*Context) GetCtxPerConn

func (ctx *Context) GetCtxPerConn(k interface{}) (interface{}, bool)

When context serves for tcp, get context k-v pair of PerConnectionContext. When context serves for udp, get context k-v pair of PerRequestContext.

func (*Context) GetCtxPerRequest

func (ctx *Context) GetCtxPerRequest(k interface{}) (interface{}, bool)

func (*Context) GetPoolRef

func (ctx *Context) GetPoolRef() *ClientPool

func (*Context) HeartBeatChan

func (ctx *Context) HeartBeatChan() chan int

HeartBeatChan returns a prepared chan int to save heart-beat signal. It will never be nil, if not exist the channel, it will auto-make.

func (*Context) InitReaderAndWriter

func (ctx *Context) InitReaderAndWriter() error

func (*Context) IsOffline

func (ctx *Context) IsOffline() bool

func (*Context) IsOnline

func (ctx *Context) IsOnline() bool

func (*Context) JSON

func (ctx *Context) JSON(messageID int32, src interface{}, headers ...map[string]interface{}) error

Reply to client using json marshaller. Whatever ctx.Packx.Marshaller.MarshalName is 'json' or not , message block will marshal its header and body by json marshaller.

func (Context) Network

func (ctx Context) Network() string

func (*Context) Next

func (ctx *Context) Next()

Since middlewares are divided into 3 kinds: global, messageIDSelfRelated, anchorType, offset can't be used straightly to control middlewares like middlewares[offset](). Thus, c.Next() means actually do nothing.

func (*Context) Offline

func (ctx *Context) Offline() error

Only used when tcpX instance's builtInPool is true, otherwise you should design your own client pool(github.com/fwhezfwhez/tcpx/clientPool/client-pool.go), and manage it yourself, like: ```

var myPool = clientPool.NewClientPool()
func main() {
    srv := tcpx.NewTcpX(nil)
    srv.AddHandler(1, func(c *tcpx.Context){
        type Login struct{
           Username string
        }
        var userLogin Login
        c.Bind(&userLogin)
        myPool.Online(userLogin.Username, c)
    })
    srv.AddHandler(2, func(c *tcpx.Context){
        myPool.Offline(userLogin.Username)
    })
}

```

func (*Context) Online

func (ctx *Context) Online(username string) error

No strategy to ensure username repeat or not , if username exists, it will replace the old connection context in the pool. Only used when tcpX instance's builtInPool is true, otherwise you should design your own client pool(github.com/fwhezfwhez/tcpx/clientPool/client-pool.go), and manage it yourself, like: ```

var myPool = clientPool.NewClientPool()
func main() {
    srv := tcpx.NewTcpX(nil)
    srv.AddHandler(1, func(c *tcpx.Context){
        type Login struct{
           Username string
        }
        var userLogin Login
        c.Bind(&userLogin)
        myPool.Online(userLogin.Username, c)
    })
    srv.AddHandler(2, func(c *tcpx.Context){
        username, ok := ctx.Username()
        if !ok {
            fmt.Println("anonymous user no need to offline")
        }
        myPool.Offline(username)
    })
}

```

func (*Context) ProtoBuf

func (ctx *Context) ProtoBuf(messageID int32, src interface{}, headers ...map[string]interface{}) error

Reply to client using protobuf marshaller. Whatever ctx.Packx.Marshaller.MarshalName is 'protobuf' or not , message block will marshal its header and body by protobuf marshaller.

func (*Context) RawStream

func (ctx *Context) RawStream() ([]byte, error)

ctx.Stream is well marshaled by pack tool. ctx.RawStream is help to access raw stream.

func (*Context) RecvAuthDeny

func (ctx *Context) RecvAuthDeny()

func (*Context) RecvAuthPass

func (ctx *Context) RecvAuthPass()

func (*Context) RecvHeartBeat

func (ctx *Context) RecvHeartBeat()

RecvHeartBeat

func (*Context) Reply

func (ctx *Context) Reply(messageID int32, src interface{}, headers ...map[string]interface{}) error

Reply to client using ctx's well-set Packx.Marshaller.

func (*Context) ReplyWithMarshaller

func (ctx *Context) ReplyWithMarshaller(marshaller Marshaller, messageID int32, src interface{}, headers ...map[string]interface{}) error

func (*Context) Reset

func (ctx *Context) Reset()

func (*Context) ResetOffset

func (ctx *Context) ResetOffset()

func (*Context) SendToConn

func (ctx *Context) SendToConn(anotherCtx *Context, messageID int32, src interface{}, headers ...map[string]interface{}) error

Send to another conn via Context. Make sure called `srv.WithBuiltInPool(true)`

func (*Context) SendToUsername

func (ctx *Context) SendToUsername(username string, messageID int32, src interface{}, headers ...map[string]interface{}) error

Send to another conn index via username. Make sure called `srv.WithBuiltInPool(true)`

func (*Context) SetCtxPerConn

func (ctx *Context) SetCtxPerConn(k, v interface{})

When context serves for tcp, set context k-v pair of PerConnectionContext. When context serves for udp, set context k-v pair of PerRequestContext Key should not start with 'tcpx-', or it will panic.

func (*Context) SetCtxPerRequest

func (ctx *Context) SetCtxPerRequest(k, v interface{})

func (*Context) SetDeadline

func (ctx *Context) SetDeadline(t time.Time) error

set deadline

func (*Context) SetReadDeadline

func (ctx *Context) SetReadDeadline(t time.Time) error

set read deadline

func (*Context) SetUsername

func (ctx *Context) SetUsername(username string)

When you want to tag an username to the context, use it, or it will be regarded as an anonymous user

func (*Context) SetWriteDeadline

func (ctx *Context) SetWriteDeadline(t time.Time) error

set write deadline

func (*Context) TOML

func (ctx *Context) TOML(messageID int32, src interface{}, headers ...map[string]interface{}) error

Reply to client using toml marshaller. Whatever ctx.Packx.Marshaller.MarshalName is 'toml' or not , message block will marshal its header and body by toml marshaller.

func (*Context) Username

func (ctx *Context) Username() (string, bool)

Context's connection scope saves an unique key to the connection pool Before using this, ctx.SetUsername should be call first

func (*Context) XML

func (ctx *Context) XML(messageID int32, src interface{}, headers ...map[string]interface{}) error

Reply to client using xml marshaller. Whatever ctx.Packx.Marshaller.MarshalName is 'xml' or not , message block will marshal its header and body by xml marshaller.

func (*Context) YAML

func (ctx *Context) YAML(messageID int32, src interface{}, headers ...map[string]interface{}) error

Reply to client using yaml marshaller. Whatever ctx.Packx.Marshaller.MarshalName is 'yaml' or not , message block will marshal its header and body by yaml marshaller.

type H

type H map[string]interface{}

type JsonMarshaller

type JsonMarshaller struct{}

func (JsonMarshaller) Marshal

func (js JsonMarshaller) Marshal(v interface{}) ([]byte, error)

func (JsonMarshaller) MarshalName

func (js JsonMarshaller) MarshalName() string

func (JsonMarshaller) Unmarshal

func (js JsonMarshaller) Unmarshal(data []byte, dest interface{}) error

type Log

type Log struct {
	Logger *log.Logger
	Mode   int
}

tcpx logger

func (Log) Println

func (l Log) Println(info ...interface{})

Println info in debug mode, do nothing in release mode

func (*Log) SetLogFlags

func (l *Log) SetLogFlags(flags int)

Set logger flags, value of flags are the same as the official log

func (*Log) SetLogMode

func (l *Log) SetLogMode(mode int)

Set mode of logger, value is tcpx.DEBUG, tcpx.RELEASE

type Marshaller

type Marshaller interface {
	Marshal(interface{}) ([]byte, error)
	Unmarshal([]byte, interface{}) error
	MarshalName() string
}

func GetMarshallerByMarshalName

func GetMarshallerByMarshalName(marshalName string) (Marshaller, error)

type Message

type Message struct {
	MessageID int32                  `json:"message_id"`
	Header    map[string]interface{} `json:"header"`
	Body      interface{}            `json:"body"`
}

Message contains the necessary parts of tcpx protocol MessagID is defining a message routing flag. Header is an attachment of a message. Body is the message itself, it should be raw message not serialized yet, like "hello", not []byte("hello")

func UnpackWithMarshaller

func UnpackWithMarshaller(stream []byte, dest interface{}, marshaller Marshaller) (Message, error)

unpack stream from PackWithMarshaller If users want to use this protocol across languages, here are the protocol details: (they are ordered as list) [4]byte -- length fixed_size,binary big endian encode [4]byte -- messageID fixed_size,binary big endian encode [4]byte -- headerLength fixed_size,binary big endian encode [4]byte -- bodyLength fixed_size,binary big endian encode []byte -- header marshal by json []byte -- body marshal by marshaller

func UnpackWithMarshallerName

func UnpackWithMarshallerName(stream []byte, dest interface{}, marshallerName string) (Message, error)

same as above

func (Message) Get

func (msg Message) Get(key string) interface{}

Get value of message's header whose key is 'key' Get and Set don't have lock to ensure concurrently safe, which means if you should never operate the header in multiple goroutines, it's better to design a context yourself per request rather than straightly use message.Header.

func (*Message) Set

func (msg *Message) Set(k string, v interface{})

Get and Set don't have lock to ensure concurrently safe, which means if you should never operate the header in multiple goroutines, it's better to design a context yourself per request rather than straightly use message.Header.

type MessageIDAnchor

type MessageIDAnchor struct {
	MessageID   int32
	AnchorIndex int
}

type MiddlewareAnchor

type MiddlewareAnchor struct {
	MiddlewareKey string
	Middleware    func(c *Context)

	// anchorStartIndexRange.len should >= AnchorEndIndexRange.len, and should not bigger than 1.
	AnchorStartIndexRange []int
	AnchorEndIndexRange   []int
	// contains filtered or unexported fields
}

func (*MiddlewareAnchor) Contains

func (ma *MiddlewareAnchor) Contains(handlerIndex int) bool

func (*MiddlewareAnchor) FormatPath

func (ma *MiddlewareAnchor) FormatPath() string

type Mux

type Mux struct {
	Mutex    *sync.RWMutex
	Handlers map[int32]func(ctx *Context)
	AllowAdd bool

	GlobalMiddlewares       []func(ctx *Context)
	MessageIDSelfMiddleware map[int32][]func(ctx *Context)

	// expired anchors will not remove from it
	MiddlewareAnchors   []MiddlewareAnchor
	MiddlewareAnchorMap map[string]MiddlewareAnchor

	MessageIDAnchorMap map[int32]MessageIDAnchor
	// contains filtered or unexported fields
}

Mux is used to register different request by messageID Middlewares are divided into 3 kinds: 1. global --> GlobalTypeMiddlewares 2. messageIDSelfRelated --> SelfRelatedTypeMiddleware 3. DynamicUsed --> AnchorTypeMiddleware. ATTENTION: Middlewares are executed in order of 1 ->3 -> 2 if OnMessage is not nil, GlobalTypeMiddlewares and AnchorTypeMiddleware will all be executed regardless of unUsed or not

func NewMux

func NewMux() *Mux

New a mux instance, malloc memory for its mutex, handler slice...

func (*Mux) AddGlobalMiddleware

func (mux *Mux) AddGlobalMiddleware(handlers ...func(c *Context))

Add Global middlewares

func (*Mux) AddHandleFunc

func (mux *Mux) AddHandleFunc(messageID int32, handler func(ctx *Context))

AddHandleFunc add routing handlers by messageID.

func (*Mux) AddMessageIDAnchor

func (mux *Mux) AddMessageIDAnchor(anchor MessageIDAnchor)

add messageID anchor

func (*Mux) AddMessageIDSelfMiddleware

func (mux *Mux) AddMessageIDSelfMiddleware(messageID int32, handlers ...func(c *Context))

add middleware by srv.Add(1, middleware1, middleware2, handler)

func (*Mux) AddMiddlewareAnchor

func (mux *Mux) AddMiddlewareAnchor(anchor MiddlewareAnchor)

add anchor index binding to middlewares

func (*Mux) AnchorIndexOfMessageID

func (mux *Mux) AnchorIndexOfMessageID(messageID int32) int

get anchor index of a messageID

func (*Mux) Any

func (mux *Mux) Any(urlPattern string, handlers ...func(c *Context)) error

Any is used to routing message using url-pattern

func (*Mux) CurrentAnchorIndex

func (mux *Mux) CurrentAnchorIndex() int

anchorIndex of current handlers

func (*Mux) ReplaceMiddlewareAnchor

func (mux *Mux) ReplaceMiddlewareAnchor(anchor MiddlewareAnchor)

Used to reset anchor's ExpiredAnchorIndex, avoiding operate map straightly.

type Packx

type Packx struct {
	Marshaller    Marshaller
	MaxPacketSize int32
}

tcpx's tool to help build expected stream for communicating

func NewPackx

func NewPackx(marshaller Marshaller) *Packx

New a packx instance, specific a marshaller for communication. If marshaller is nil, official jsonMarshaller is put to used.

func (Packx) BodyBytesOf

func (packx Packx) BodyBytesOf(stream []byte) ([]byte, error)

body bytes of a block

func (Packx) BodyLengthOf

func (packx Packx) BodyLengthOf(stream []byte) (int32, error)

Body length of a stream received

func (Packx) FirstBlockOf

func (packx Packx) FirstBlockOf(r io.Reader) ([]byte, error)

a stream from a reader can be apart by protocol. FirstBlockOf helps tear apart the first block []byte from reader

func (Packx) FirstBlockOfBytes

func (packx Packx) FirstBlockOfBytes(buffer []byte) ([]byte, error)

a stream from a buffer which can be apart by protocol. FirstBlockOfBytes helps tear apart the first block []byte from a []byte buffer

func (Packx) HeaderBytesOf

func (packx Packx) HeaderBytesOf(stream []byte) ([]byte, error)

Header bytes of a block

func (Packx) HeaderLengthOf

func (packx Packx) HeaderLengthOf(stream []byte) (int32, error)

Header length of a stream received

func (Packx) HeaderOf

func (packx Packx) HeaderOf(stream []byte) (map[string]interface{}, error)

header of a block

func (Packx) LengthOf

func (packx Packx) LengthOf(stream []byte) (int32, error)

Length of the stream starting validly. Length doesn't include length flag itself, it refers to a valid message length after it.

func (Packx) MessageIDOf

func (packx Packx) MessageIDOf(stream []byte) (int32, error)

messageID of a stream. Use this to choose which struct for unpacking.

func (Packx) Pack

func (packx Packx) Pack(messageID int32, src interface{}, headers ...map[string]interface{}) ([]byte, error)

Pack src with specific messageID and optional headers Src has not been marshaled yet.Whatever you put as src, it will be marshaled by packx.Marshaller.

func (Packx) PackWithBody

func (packx Packx) PackWithBody(messageID int32, body []byte, headers ...map[string]interface{}) ([]byte, error)

PackWithBody is used for self design protocol

func (Packx) Unpack

func (packx Packx) Unpack(stream []byte, dest interface{}) (Message, error)

Unpack Stream is a block of length,messageID,headerLength,bodyLength,header,body. Dest refers to the body, it can be dynamic by messageID.

Before use this, users should be aware of which struct used as `dest`. You can use stream's messageID for judgement like: messageID,_:= packx.MessageIDOf(stream)

switch messageID {
    case 1:
      packx.Unpack(stream, &struct1)
    case 2:
      packx.Unpack(stream, &struct2)
    ...
}

type PropertyCache

type PropertyCache struct {
	Network string
	Port    string

	// only when network is 'tcp','kcp', Listener can assert to net.Listener.
	// when network is 'udp', it can assert to net.PackConn
	Listener interface{}
}

type ProtobufMarshaller

type ProtobufMarshaller struct{}

func (ProtobufMarshaller) Marshal

func (pm ProtobufMarshaller) Marshal(v interface{}) ([]byte, error)

v should realize proto.Message

func (ProtobufMarshaller) MarshalName

func (pm ProtobufMarshaller) MarshalName() string

func (ProtobufMarshaller) Unmarshal

func (pm ProtobufMarshaller) Unmarshal(data []byte, dest interface{}) error

dest should realize proto.Message

type Request

type Request struct {
	Body   io.ReadCloser
	URL    string
	Header map[string]interface{}
}

func NewRequest

func NewRequest(url string, reader io.Reader) *Request

func (*Request) Set

func (r *Request) Set(key string, value interface{})

type Route

type Route struct {
	URLPattern string
	MessageId  int
	Whereis    []string
}

func (Route) Location

func (r Route) Location() string

func (*Route) Merge

func (r *Route) Merge(r2 Route) Route

type TcpX

type TcpX struct {
	OnConnect func(ctx *Context)
	OnMessage func(ctx *Context)
	OnClose   func(ctx *Context)
	Mux       *Mux
	Packx     *Packx

	// heartbeat setting
	HeartBeatOn        bool          // whether start a goroutine to spy on each connection
	HeatBeatInterval   time.Duration // heartbeat should receive in the interval
	HeartBeatMessageID int32         // which messageID to listen to heartbeat
	ThroughMiddleware  bool          // whether heartbeat go through middleware

	AuthMessageID         int32
	AuthThroughMiddleware bool // whether auth handler go through middleware

	// external for handle any stream
	// only support tcp/kcp
	HandleRaw func(c *Context)
	// contains filtered or unexported fields
}

OnMessage and mux are opposite. When OnMessage is not nil, users should deal will ctx.Stream themselves. When OnMessage is nil, program will handle ctx.Stream via mux routing by messageID

func NewTcpX

func NewTcpX(marshaller Marshaller) *TcpX

new an tcpx srv instance

func (*TcpX) AddHandler

func (tcpx *TcpX) AddHandler(messageID int32, handlers ...func(ctx *Context))

Middleware typed 'SelfRelatedTypedMiddleware'. Add handlers routing by messageID

func (*TcpX) BeforeExit

func (tcpx *TcpX) BeforeExit(f ...func())

Before exist do ending jobs

func (*TcpX) HeartBeatMode

func (tcpx *TcpX) HeartBeatMode(on bool, duration time.Duration) *TcpX

Set built in heart beat on Default heartbeat handler will be added by messageID tcpx.DEFAULT_HEARTBEAT_MESSAGEID(-1392), and default heartbeat handler will not execute all kinds of middleware.

... srv := tcpx.NewTcpX(nil) srv.HeartBeatMode(true, 10 * time.Second) ...

* If you want specific official heartbeat handler detail: srv.HeartBeatModeDetail(true, 10 * time.Second, true, 1)

* If you want to rewrite heartbeat handler: srv.RewriteHeartBeatHandler(func(c *tcpx.Context){})

* If you think built in heartbeat not good, abandon it: ```

srv.AddHandler(1111, func(c *tcpx.Context){
   //do nothing by default and define your heartbeat yourself
})

```

func (*TcpX) HeartBeatModeDetail

func (tcpx *TcpX) HeartBeatModeDetail(on bool, duration time.Duration, throughMiddleware bool, messageID int32) *TcpX

specific args for heartbeat

func (*TcpX) ListenAndServe

func (tcpx *TcpX) ListenAndServe(network, addr string) error

Start to listen. Serve can decode stream generated by packx. Support tcp and udp

func (*TcpX) ListenAndServeGRPC deprecated

func (tcpx *TcpX) ListenAndServeGRPC(network, addr string) error

grpc developing, do not use. marshaller must be protobuf, clients should send message bytes which body is protobuf bytes

Deprecated: on developing.

func (*TcpX) ListenAndServeHTTP deprecated

func (tcpx *TcpX) ListenAndServeHTTP(network, addr string) error

http developing, do not use.

Deprecated: on developing.

func (*TcpX) ListenAndServeRaw

func (tcpx *TcpX) ListenAndServeRaw(network, addr string) error

raw

func (*TcpX) ListenAndServeTCP

func (tcpx *TcpX) ListenAndServeTCP(network, addr string) error

tcp

func (*TcpX) ListenAndServeUDP

func (tcpx *TcpX) ListenAndServeUDP(network, addr string, maxBufferSize ...int) error

udp maxBufferSize can set buffer length, if receive a message longer than it ,

func (*TcpX) Restart

func (tcpx *TcpX) Restart(closeAllConnection bool, beforeStart ...func()) error

Graceful Restart = Stop and Start.Besides, you can

func (*TcpX) RewriteHeartBeatHandler

func (tcpx *TcpX) RewriteHeartBeatHandler(messageID int32, f func(c *Context)) *TcpX

Rewrite heartbeat handler It will inherit properties of the older heartbeat handler:

  • heartbeatInterval
  • throughMiddleware

func (*TcpX) SetDeadline

func (tcpx *TcpX) SetDeadline(t time.Time)

Set deadline This should be set before server start. If you want change deadline while it's running, use ctx.SetDeadline(t time.Time) instead.

func (*TcpX) SetReadDeadline

func (tcpx *TcpX) SetReadDeadline(t time.Time)

Set read deadline This should be set before server start. If you want change deadline while it's running, use ctx.SetDeadline(t time.Time) instead.

func (*TcpX) SetWriteDeadline

func (tcpx *TcpX) SetWriteDeadline(t time.Time)

Set write deadline This should be set before server start. If you want change deadline while it's running, use ctx.SetDeadline(t time.Time) instead.

func (*TcpX) Start

func (tcpx *TcpX) Start() error

Graceful start an existed tcpx srv, former server is stopped by tcpX.Stop()

func (*TcpX) State

func (tcpx *TcpX) State() int

func (*TcpX) Stop

func (tcpx *TcpX) Stop(closeAllConnection bool) error

Graceful stop server parts generated by `srv.ListenAndServe()`, this will not stop process, if param 'closeAllConnection' is false, only stop server listener. Older connections will remain safe and kept in pool.If param 'closeAllConnection' is true, it will not only stop the listener, but also kill all connections(stops their net.Conn, stop all sub-routine, clear the pool)

func (*TcpX) UnUse

func (tcpx *TcpX) UnUse(middlewareKeys ...string)

UnUse an middleware. a unused middleware will expired among handlers added after it.For example:

	srv := tcpx.NewTcpX(tcpx.JsonMarshaller{})
 srv.Use("middleware1", Middleware1, "middleware2", Middleware2)
	srv.AddHandler(1, SayHello)
	srv.UnUse("middleware2")
	srv.AddHandler(3, SayGoodBye)

middleware1 and middleware2 will both work to handler 'SayHello'. middleware1 will work to handler 'SayGoodBye' but middleware2 will not work to handler 'SayGoodBye'

func (*TcpX) Use

func (tcpx *TcpX) Use(mids ...interface{})

Middleware typed 'AnchorTypedMiddleware'. Add middlewares ruled by (string , func(c *Context),string , func(c *Context),string , func(c *Context)...). Middlewares will be added with an indexed key, which is used to unUse this middleware. Each middleware added will be well set an anchor index, when UnUse this middleware, its expire_anchor_index will be well set too.

func (*TcpX) UseGlobal

func (tcpx *TcpX) UseGlobal(mids ...func(c *Context))

Middleware typed 'GlobalTypedMiddleware'. GlobalMiddleware will work to all handlers.

func (*TcpX) WithAuthDetail

func (tcpx *TcpX) WithAuthDetail(yes bool, duration time.Duration, throughMiddleware bool, messageID int32, f func(c *Context)) *TcpX

func (*TcpX) WithBroadCastSignal

func (tcpx *TcpX) WithBroadCastSignal(yes bool) *TcpX

Whether using signal-broadcast. Used for these situations: closeAllSignal - close all connection and remove them from the built-in pool

func (*TcpX) WithBuiltInPool

func (tcpx *TcpX) WithBuiltInPool(yes bool) *TcpX

whether using built-in pool

type TomlMarshaller

type TomlMarshaller struct{}

func (TomlMarshaller) Marshal

func (tm TomlMarshaller) Marshal(v interface{}) ([]byte, error)

func (TomlMarshaller) MarshalName

func (tm TomlMarshaller) MarshalName() string

func (TomlMarshaller) Unmarshal

func (tm TomlMarshaller) Unmarshal(data []byte, dest interface{}) error

type XmlMarshaller

type XmlMarshaller struct{}

func (XmlMarshaller) Marshal

func (xm XmlMarshaller) Marshal(v interface{}) ([]byte, error)

func (XmlMarshaller) MarshalName

func (xm XmlMarshaller) MarshalName() string

func (XmlMarshaller) Unmarshal

func (xm XmlMarshaller) Unmarshal(data []byte, dest interface{}) error

type YamlMarshaller

type YamlMarshaller struct{}

func (YamlMarshaller) Marshal

func (ym YamlMarshaller) Marshal(v interface{}) ([]byte, error)

func (YamlMarshaller) MarshalName

func (ym YamlMarshaller) MarshalName() string

func (YamlMarshaller) Unmarshal

func (ym YamlMarshaller) Unmarshal(data []byte, dest interface{}) error

Directories

Path Synopsis
export http api to validate stream from all language clients
export http api to validate stream from all language clients
go
Package go provides go client example
Package go provides go client example
examples
sayHello/client
Package client executable file
Package client executable file
sayHello/server
Package server executable file
Package server executable file
sayHelloUDP/client
Package client executable file
Package client executable file
sayHelloUDP/server
Package server executable file
Package server executable file

Jump to

Keyboard shortcuts

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