Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ lint-fix:
golangci-lint run --concurrency=2 --fix

test:
CGO_ENABLED=1 go test -count=1 -race -covermode=atomic -coverprofile=.testCoverage.txt -timeout=2m . ./message
CGO_ENABLED=1 go test -count=1 -race -covermode=atomic -coverprofile=.testCoverage.txt -timeout=2m .

test-v:
CGO_ENABLED=1 go test -count=1 -race -covermode=atomic -coverprofile=.testCoverage.txt -timeout=2m -v . ./message
CGO_ENABLED=1 go test -count=1 -race -covermode=atomic -coverprofile=.testCoverage.txt -timeout=2m -v .

cover-view:
go tool cover -func .testCoverage.txt
Expand Down
57 changes: 24 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,10 @@ func main() {
req := c.Request()

// do things...
fmt.Printf("[server] request received | id: %d; size: %d; data: %s\n", req.ID, len(req.Data), req.Data)
fmt.Printf("[server] request received | id: %d; size: %d; data: %s\n", req.ID(), len(req.Data()), req.Data())

// set response
c.SetResponseMessage(&message.Entry{
ID: 1002,
Data: []byte("copy that"),
})
c.SetResponseMessage(easytcp.NewMessage(1002, []byte("copy that")))
})

// Set custom logger (optional).
Expand Down Expand Up @@ -136,11 +133,11 @@ s.AddRoute(1001, func(c easytcp.Context) {

Above is the server side example. There are client and more detailed examples including:

- [broadcasting](./examples/tcp/broadcast)
- [custom packet](./examples/tcp/custom_packet)
- [communicating with protobuf](./examples/tcp/proto_packet)
- [broadcasting](./internal/examples/tcp/broadcast)
- [custom packet](./internal/examples/tcp/custom_packet)
- [communicating with protobuf](./internal/examples/tcp/proto_packet)

in [examples/tcp](./examples/tcp).
in [examples/tcp](./internal/examples/tcp).

## Benchmark

Expand All @@ -150,10 +147,10 @@ goos: darwin
goarch: amd64
pkg: github.com/DarthPestilane/easytcp
cpu: Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz
Benchmark_NoHandler-8 250000 4151 ns/op 81 B/op 2 allocs/op
Benchmark_OneHandler-8 250000 4322 ns/op 82 B/op 2 allocs/op
Benchmark_DefaultPacker_Pack-8 250000 36.37 ns/op 16 B/op 1 allocs/op
Benchmark_DefaultPacker_Unpack-8 250000 110.1 ns/op 96 B/op 3 allocs/op
Benchmark_NoHandler-8 250000 4667 ns/op 84 B/op 2 allocs/op
Benchmark_OneHandler-8 250000 4351 ns/op 82 B/op 2 allocs/op
Benchmark_DefaultPacker_Pack-8 250000 33.57 ns/op 16 B/op 1 allocs/op
Benchmark_DefaultPacker_Unpack-8 250000 104.4 ns/op 96 B/op 3 allocs/op
```

*since easytcp is built on the top of golang `net` library, the benchmark of networks does not make much sense.*
Expand Down Expand Up @@ -219,13 +216,10 @@ s.AddRoute(reqID, func(c easytcp.Context) {
req := c.Request()

// do things...
fmt.Printf("[server] request received | id: %d; size: %d; data: %s\n", req.ID, len(req.Data), req.Data)
fmt.Printf("[server] request received | id: %d; size: %d; data: %s\n", req.ID(), len(req.Data()), req.Data())

// set response
c.SetResponseMessage(&message.Entry{
ID: respID,
Data: []byte("copy that"),
})
c.SetResponseMessage(easytcp.NewMessage(respID, []byte("copy that")))
})
```

Expand Down Expand Up @@ -261,7 +255,7 @@ s := easytcp.NewServer(&easytcp.ServerOption{

We can set our own Packer or EasyTCP uses [`DefaultPacker`](./packer.go).

The `DefaultPacker` considers packet's payload as a `Size(4)|ID(4)|Data(n)` format. (`Size` only represents the length of `Data` instead of the whole payload length)
The `DefaultPacker` considers packet's payload as a `Size(4)|ID(4)|Data(n)` format. **`Size` only represents the length of `Data` instead of the whole payload length**

This may not covery some particular cases, but fortunately, we can create our own Packer.

Expand All @@ -274,16 +268,16 @@ func (p *CustomPacker) bytesOrder() binary.ByteOrder {
return binary.BigEndian
}

func (p *CustomPacker) Pack(entry *message.Entry) ([]byte, error) {
size := len(entry.Data) // only the size of data.
func (p *CustomPacker) Pack(msg *easytcp.Message) ([]byte, error) {
size := len(msg.Data()) // only the size of data.
buffer := make([]byte, 2+2+size)
p.bytesOrder().PutUint16(buffer[:2], uint16(size))
p.bytesOrder().PutUint16(buffer[2:4], entry.ID.(uint16))
copy(buffer[4:], entry.Data)
p.bytesOrder().PutUint16(buffer[2:4], msg.ID().(uint16))
copy(buffer[4:], msg.Data())
return buffer, nil
}

func (p *CustomPacker) Unpack(reader io.Reader) (*message.Entry, error) {
func (p *CustomPacker) Unpack(reader io.Reader) (*easytcp.Message, error) {
headerBuffer := make([]byte, 2+2)
if _, err := io.ReadFull(reader, headerBuffer); err != nil {
return nil, fmt.Errorf("read size and id err: %s", err)
Expand All @@ -296,15 +290,12 @@ func (p *CustomPacker) Unpack(reader io.Reader) (*message.Entry, error) {
return nil, fmt.Errorf("read data err: %s", err)
}

entry := &message.Entry{
// since entry.ID is type of uint16, we need to use uint16 as well when adding routes.
// eg: server.AddRoute(uint16(123), ...)
ID: id,
Data: data,
}
entry.Set("theWholeLength", 2+2+size) // we can set our custom kv data here.
// since msg.ID is type of uint16, we need to use uint16 as well when adding routes.
// eg: server.AddRoute(uint16(123), ...)
msg := easytcp.NewMessage(id, data)
msg.Set("theWholeLength", 2+2+size) // we can set our custom kv data here.
// c.Request().Get("theWholeLength") // and get them in route handler.
return entry, nil
return msg, nil
}
```

Expand Down Expand Up @@ -333,7 +324,7 @@ s.AddRoute(reqID, func(c easytcp.Context) {
// handle error...
}
req := c.Request()
fmt.Printf("[server] request received | id: %d; size: %d; data-decoded: %+v\n", req.ID, len(req.Data), reqData)
fmt.Printf("[server] request received | id: %d; size: %d; data-decoded: %+v\n", req.ID(), len(req.Data()), reqData())
respData := map[string]string{"key": "value"}
if err := c.SetResponse(respID, respData); err != nil {
// handle error...
Expand Down
18 changes: 5 additions & 13 deletions benchmarks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package easytcp

import (
"bytes"
"github.com/DarthPestilane/easytcp/message"
"github.com/stretchr/testify/assert"
"io"
"net"
Expand Down Expand Up @@ -32,10 +31,10 @@ func Benchmark_NoHandler(b *testing.B) {
}
defer client.Close() // nolint

packedMsg, _ := s.Packer.Pack(&message.Entry{ID: 1, Data: []byte("ping")})
packedBytes, _ := s.Packer.Pack(NewMessage(1, []byte("ping")))
beforeBench(b)
for i := 0; i < b.N; i++ {
_, _ = client.Write(packedMsg)
_, _ = client.Write(packedBytes)
}
}

Expand All @@ -56,7 +55,7 @@ func Benchmark_OneHandler(b *testing.B) {
}
defer client.Close() // nolint

packedMsg, _ := s.Packer.Pack(&message.Entry{ID: 1, Data: []byte("ping")})
packedMsg, _ := s.Packer.Pack(NewMessage(1, []byte("ping")))
beforeBench(b)
for i := 0; i < b.N; i++ {
_, _ = client.Write(packedMsg)
Expand All @@ -65,11 +64,7 @@ func Benchmark_OneHandler(b *testing.B) {

func Benchmark_DefaultPacker_Pack(b *testing.B) {
packer := NewDefaultPacker()

msg := &message.Entry{
ID: 1,
Data: []byte("test"),
}
msg := NewMessage(1, []byte("test"))
beforeBench(b)
for i := 0; i < b.N; i++ {
_, _ = packer.Pack(msg)
Expand All @@ -78,10 +73,7 @@ func Benchmark_DefaultPacker_Pack(b *testing.B) {

func Benchmark_DefaultPacker_Unpack(b *testing.B) {
packer := NewDefaultPacker()
msg := &message.Entry{
ID: 1,
Data: []byte("test"),
}
msg := NewMessage(1, []byte("test"))
dataBytes, err := packer.Pack(msg)
assert.NoError(b, err)

Expand Down
27 changes: 0 additions & 27 deletions examples/tcp/custom_packet/common/packer_test.go

This file was deleted.

27 changes: 0 additions & 27 deletions examples/tcp/proto_packet/common/packer_test.go

This file was deleted.

50 changes: 0 additions & 50 deletions examples/tcp/simple/client/main.go

This file was deleted.

File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ package main
import (
"fmt"
"github.com/DarthPestilane/easytcp"
"github.com/DarthPestilane/easytcp/examples/fixture"
"github.com/DarthPestilane/easytcp/examples/tcp/broadcast/common"
"github.com/DarthPestilane/easytcp/message"
"github.com/DarthPestilane/easytcp/internal/examples/fixture"
"github.com/DarthPestilane/easytcp/internal/examples/tcp/broadcast/common"
"github.com/sirupsen/logrus"
"net"
"time"
Expand Down Expand Up @@ -44,12 +43,7 @@ func senderClient() {
for {
time.Sleep(time.Second)
data := []byte(fmt.Sprintf("hello everyone @%d", time.Now().Unix()))
msg := &message.Entry{
ID: common.MsgIdBroadCastReq,
Data: data,
}

packedMsg, _ := packer.Pack(msg)
packedMsg, _ := packer.Pack(easytcp.NewMessage(common.MsgIdBroadCastReq, data))
if _, err := conn.Write(packedMsg); err != nil {
log.Error(err)
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ package main
import (
"fmt"
"github.com/DarthPestilane/easytcp"
"github.com/DarthPestilane/easytcp/examples/fixture"
"github.com/DarthPestilane/easytcp/examples/tcp/broadcast/common"
"github.com/DarthPestilane/easytcp/message"
fixture2 "github.com/DarthPestilane/easytcp/internal/examples/fixture"
"github.com/DarthPestilane/easytcp/internal/examples/tcp/broadcast/common"
"github.com/sirupsen/logrus"
"os"
"os/signal"
Expand Down Expand Up @@ -47,7 +46,7 @@ func main() {
delete(sessions.storage, sess.ID().(int64))
}

s.Use(fixture.RecoverMiddleware(log), logMiddleware)
s.Use(fixture2.RecoverMiddleware(log), logMiddleware)

s.AddRoute(common.MsgIdBroadCastReq, func(ctx easytcp.Context) {
reqData := ctx.Request().Data
Expand All @@ -60,24 +59,21 @@ func main() {
continue
}
respData := fmt.Sprintf("%s (broadcast from %d to %d)", reqData, currentSession.ID(), targetSession.ID())
respEntry := &message.Entry{ID: common.MsgIdBroadCastAck, Data: []byte(respData)}
respMsg := easytcp.NewMessage(common.MsgIdBroadCastAck, []byte(respData))
go func() {
targetSession.AllocateContext().SetResponseMessage(respEntry).Send()
targetSession.AllocateContext().SetResponseMessage(respMsg).Send()
// can also write like this.
// ctx.Copy().SetResponseMessage(respEntry).SendTo(targetSession)
// ctx.Copy().SetResponseMessage(respMsg).SendTo(targetSession)
// or this.
// ctx.Copy().SetSession(targetSession).SetResponseMessage(respEntry).Send()
// ctx.Copy().SetSession(targetSession).SetResponseMessage(respMsg).Send()
}()
}

ctx.SetResponseMessage(&message.Entry{
ID: common.MsgIdBroadCastAck,
Data: []byte("broadcast done"),
})
ctx.SetResponseMessage(easytcp.NewMessage(common.MsgIdBroadCastAck, []byte("broadcast done")))
})

go func() {
if err := s.Serve(fixture.ServerAddr); err != nil {
if err := s.Serve(fixture2.ServerAddr); err != nil {
log.Error(err)
}
}()
Expand All @@ -95,8 +91,8 @@ func logMiddleware(next easytcp.HandlerFunc) easytcp.HandlerFunc {
return func(ctx easytcp.Context) {
log.Infof("recv request | %s", ctx.Request().Data)
defer func() {
var resp = ctx.Response()
log.Infof("send response |sessId: %d; id: %d; size: %d; data: %s", ctx.Session().ID(), resp.ID, len(resp.Data), resp.Data)
var respMsg = ctx.Response()
log.Infof("send response |sessId: %d; id: %d; size: %d; data: %s", ctx.Session().ID(), respMsg.ID(), len(respMsg.Data()), respMsg.Data())
}()
next(ctx)
}
Expand Down
Loading