Skip to content

Commit

Permalink
Merge pull request #64 from lxzan/testing
Browse files Browse the repository at this point in the history
v1.7.0
  • Loading branch information
lxzan authored Nov 21, 2023
2 parents dbc3727 + 7159f0d commit b62a261
Show file tree
Hide file tree
Showing 26 changed files with 273 additions and 209 deletions.
73 changes: 55 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

GWS (Go WebSocket) is a very simple, fast, reliable and feature-rich WebSocket implementation written in Go. It is
designed to be used in highly-concurrent environments, and it is suitable for
building `API`, `PROXY`, `GAME`, `Live Video`, `MESSAGE`, etc. It supports both server and client side with a simple API
building `API`, `Proxy`, `Game`, `Live Video`, `Message`, etc. It supports both server and client side with a simple API
which mean you can easily write a server or client by yourself.

GWS developed base on Event-Driven model. every connection has a goroutine to handle the event, and the event is able
Expand All @@ -26,18 +26,19 @@ to be processed in a non-blocking way.
### Why GWS

- <font size=3>Simplicity and Ease of Use</font>
- **User-Friendly API**: Straightforward and easy-to-understand API, making server and client setup hassle-free.
- **Code Efficiency**: Minimizes the amount of code needed to implement complex WebSocket solutions.

- **User-Friendly**: Simple and clear `WebSocket` Event API design makes server-client interaction easy.
- **Code Efficiency**: Minimizes the amount of code needed to implement complex WebSocket solutions.

- <font size=3>High-Performance</font>
- **Zero Allocs IO**: Built-in multi-level memory pool to minimize dynamic memory allocation during reads and
writes.
- **Optimized for Speed**: Designed for rapid data transmission and reception, ideal for time-sensitive
applications.

- **High IOPS Low Latency**: Designed for rapid data transmission and reception, ideal for time-sensitive
applications.
- **Low Memory Usage**: Highly optimized memory multiplexing system to minimize memory usage and reduce your cost of ownership.

- <font size=3>Reliability and Stability</font>
- **Event-Driven Architecture**: Ensures stable performance even in highly concurrent environments.
- **Robust Error Handling**: Advanced mechanisms to manage and mitigate errors, ensuring continuous operation.
- **Robust Error Handling**: Advanced mechanisms to manage and mitigate errors, ensuring continuous operation.
- **Well-Developed Test Cases**: Passed all `Autobahn` test cases, fully compliant with `RFC 6455`. 99% unit test coverage, covering almost all conditional branches.

### Benchmark

Expand Down Expand Up @@ -68,8 +69,8 @@ PASS
- [Introduction](#introduction)
- [Why GWS](#why-gws)
- [Benchmark](#benchmark)
- [IOPS (Echo Server)](#iops-echo-server)
- [GoBench](#gobench)
- [IOPS (Echo Server)](#iops-echo-server)
- [GoBench](#gobench)
- [Index](#index)
- [Feature](#feature)
- [Attention](#attention)
Expand All @@ -78,9 +79,10 @@ PASS
- [Quick Start](#quick-start)
- [Best Practice](#best-practice)
- [More Examples](#more-examples)
- [KCP](#kcp)
- [Proxy](#proxy)
- [Broadcast](#broadcast)
- [KCP](#kcp)
- [Proxy](#proxy)
- [Broadcast](#broadcast)
- [Pub / Sub](#pub--sub)
- [Autobahn Test](#autobahn-test)
- [Communication](#communication)
- [Acknowledgments](#acknowledgments)
Expand Down Expand Up @@ -110,11 +112,11 @@ go get -v github.com/lxzan/gws@latest

```go
type Event interface {
OnOpen(socket *Conn) // the connection is established
OnOpen(socket *Conn) // connection is established
OnClose(socket *Conn, err error) // received a close frame or I/O error occurs
OnPing(socket *Conn, payload []byte) // receive a ping frame
OnPong(socket *Conn, payload []byte) // receive a pong frame
OnMessage(socket *Conn, message *Message) // receive a text/binary frame
OnPing(socket *Conn, payload []byte) // received a ping frame
OnPong(socket *Conn, payload []byte) // received a pong frame
OnMessage(socket *Conn, message *Message) // received a text/binary frame
}
```

Expand Down Expand Up @@ -287,6 +289,41 @@ func Broadcast(conns []*gws.Conn, opcode gws.Opcode, payload []byte) {
}
```

#### Pub / Sub

Use the event_emitter package to implement the publish-subscribe model. Wrap `gws.Conn` in a structure and implement the GetSubscriberID method to get the subscription ID, which must be unique. The subscription ID is used to identify the subscriber, who can only receive messages on the subject of his subscription.

This example is useful for building chat rooms or push messages using gws. This means that a user can subscribe to one or more topics via websocket, and when a message is posted to that topic, all subscribers will receive the message.

```go
package main

import (
"github.com/lxzan/event_emitter"
"github.com/lxzan/gws"
)

type Socket struct{ *gws.Conn }

// GetSubscriberID gets the subscription ID, which needs to be unique.
func (c *Socket) GetSubscriberID() int64 {
userId, _ := c.Session().Load("userId")
return userId.(int64)
}

func Sub(em *event_emitter.EventEmitter[*Socket], topic string, socket *Socket) {
em.Subscribe(socket, topic, func(subscriber *Socket, msg any) {
_ = msg.(*gws.Broadcaster).Broadcast(subscriber.Conn)
})
}

func Pub(em *event_emitter.EventEmitter[*Socket], topic string, op gws.Opcode, msg []byte) {
var broadcaster = gws.NewBroadcaster(op, msg)
defer broadcaster.Close()
em.Publish(topic, broadcaster)
}
```

### Autobahn Test

```bash
Expand Down
79 changes: 58 additions & 21 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@ GWS(Go WebSocket)是一个用 Go 编写的非常简单、快速、可靠且
### 为什么选择 GWS

- <font size=3>简单易用</font>
- **用户友好的 API 设计**: 简单易懂的应用程序接口,让服务器和客户端的设置变得轻松简单。
- **编码效率**: 最大限度地减少实施复杂的 WebSocket 解决方案所需的代码量。

- <font size=3>性能良好</font>
- **零动态内存分配 I/O**: 内置多级内存池,可最大限度地减少读写过程中的动态内存分配。
- **性能优化**: 专为快速传输和接收数据而设计,是时间敏感型应用的理想之选。
- **用户友好**: 简洁明了的 `WebSocket` 事件接口设计,让服务器和客户端的交互变得轻松简单.
- **编码效率**: 最大限度地减少实施复杂的解决方案所需的代码量.

- <font size=3>性能出众</font>

- **高吞吐低延迟**: 专为快速传输和接收数据而设计,是时间敏感型应用的理想之选.
- **低内存占用**: 高度优化的内存复用系统, 最大限度降低内存使用量,降低您的成本.

- <font size=3>稳定可靠</font>
- **事件驱动式架构**: 即使在高度并发的环境中,也能确保稳定的性能。
- **健壮的错误处理**: 管理和减少错误的先进机制,确保持续运行。
- **健壮的错误处理**: 管理和减少错误的先进机制,确保持续运行.
- **完善的测试用例**: 通过了所有 `Autobahn` 测试用例, 完全符合 `RFC 6455` 标准. 单元测试覆盖率达到 99%, 几乎覆盖所有条件分支.

### 基准测试

#### IOPS (Echo Server)
Expand Down Expand Up @@ -59,8 +61,8 @@ PASS
- [介绍](#介绍)
- [为什么选择 GWS](#为什么选择-gws)
- [基准测试](#基准测试)
- [IOPS (Echo Server)](#iops-echo-server)
- [GoBench](#gobench)
- [IOPS (Echo Server)](#iops-echo-server)
- [GoBench](#gobench)
- [Index](#index)
- [特性](#特性)
- [注意](#注意)
Expand All @@ -69,14 +71,14 @@ PASS
- [快速上手](#快速上手)
- [最佳实践](#最佳实践)
- [更多用例](#更多用例)
- [KCP](#kcp)
- [代理](#代理)
- [广播](#广播)
- [KCP](#kcp)
- [代理](#代理)
- [广播](#广播)
- [发布/订阅](#发布订阅)
- [Autobahn 测试](#autobahn-测试)
- [交流](#交流)
- [致谢](#致谢)


### 特性

- [x] 事件驱动式 API
Expand All @@ -88,9 +90,9 @@ PASS

### 注意

- 所有 gws.Conn 导出的方法错误都是可忽略的, 它们在内部已经被妥善处理了
- 所有 gws.Conn 导出方法返回的错误都是可忽略的, 它们在内部已经被妥善处理了
- 传输大文件有阻塞连接的风险
- 如果复用HTTP服务器, 建议调用ReadLoop时开启新的goroutine, 以避免请求上下文内存不能被回收.
- 如果复用 HTTP 服务器, 建议开启新的 Goroutine 来调用 ReadLoop, 以避免请求上下文内存不能及时回收.

### 安装

Expand All @@ -102,11 +104,11 @@ go get -v github.com/lxzan/gws@latest

```go
type Event interface {
OnOpen(socket *Conn) // the connection is established
OnOpen(socket *Conn) // connection is established
OnClose(socket *Conn, err error) // received a close frame or I/O error occurs
OnPing(socket *Conn, payload []byte) // receive a ping frame
OnPong(socket *Conn, payload []byte) // receive a pong frame
OnMessage(socket *Conn, message *Message) // receive a text/binary frame
OnPing(socket *Conn, payload []byte) // received a ping frame
OnPong(socket *Conn, payload []byte) // received a pong frame
OnMessage(socket *Conn, message *Message) // received a text/binary frame
}
```

Expand Down Expand Up @@ -236,7 +238,7 @@ func main() {

#### 代理

通过代理拨号, 使用socks5协议.
通过代理拨号, 使用 socks5 协议.

```go
package main
Expand Down Expand Up @@ -279,6 +281,41 @@ func Broadcast(conns []*gws.Conn, opcode gws.Opcode, payload []byte) {
}
```

#### 发布/订阅

使用 event_emitter 包实现发布订阅模式。用结构体包装 `gws.Conn`,并实现 GetSubscriberID 方法以获取订阅 ID,该 ID 必须是唯一的。订阅 ID 用于识别订阅者,订阅者只能接收其订阅主题的消息。

此示例对于使用 gws 构建聊天室或消息推送非常有用。这意味着用户可以通过 websocket 订阅一个或多个主题,当向该主题发布消息时,所有订阅用户都会收到消息。

```go
package main

import (
"github.com/lxzan/event_emitter"
"github.com/lxzan/gws"
)

type Socket struct{ *gws.Conn }

// GetSubscriberID 获取订阅ID, 需要保证唯一
func (c *Socket) GetSubscriberID() int64 {
userId, _ := c.Session().Load("userId")
return userId.(int64)
}

func Sub(em *event_emitter.EventEmitter[*Socket], topic string, socket *Socket) {
em.Subscribe(socket, topic, func(subscriber *Socket, msg any) {
_ = msg.(*gws.Broadcaster).Broadcast(subscriber.Conn)
})
}

func Pub(em *event_emitter.EventEmitter[*Socket], topic string, op gws.Opcode, msg []byte) {
var broadcaster = gws.NewBroadcaster(op, msg)
defer broadcaster.Close()
em.Publish(topic, broadcaster)
}
```

### Autobahn 测试

```bash
Expand Down
5 changes: 3 additions & 2 deletions benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import (
"compress/flate"
_ "embed"
"encoding/binary"
klauspost "github.com/klauspost/compress/flate"
"github.com/lxzan/gws/internal"
"io"
"net"
"testing"

klauspost "github.com/klauspost/compress/flate"
"github.com/lxzan/gws/internal"
)

//go:embed assets/github.json
Expand Down
2 changes: 1 addition & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (c *connector) handshake() (*Conn, *http.Response, error) {
return nil, c.resp, ErrCompressionNegotiation
}
socket := &Conn{
SessionStorage: c.option.NewSessionStorage(),
ss: c.option.NewSession(),
isServer: false,
subprotocol: subprotocol,
compressEnabled: compressEnabled,
Expand Down
5 changes: 3 additions & 2 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package gws
import (
"crypto/tls"
"errors"
"github.com/lxzan/gws/internal"
"github.com/stretchr/testify/assert"
"io"
"net"
"net/http"
"testing"
"time"

"github.com/lxzan/gws/internal"
"github.com/stretchr/testify/assert"
)

func TestNewClient(t *testing.T) {
Expand Down
5 changes: 3 additions & 2 deletions compress.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ package gws
import (
"bytes"
"encoding/binary"
"github.com/klauspost/compress/flate"
"github.com/lxzan/gws/internal"
"io"
"math"
"sync"
"sync/atomic"

"github.com/klauspost/compress/flate"
"github.com/lxzan/gws/internal"
)

// FlateTail Add four bytes as specified in RFC
Expand Down
Loading

0 comments on commit b62a261

Please sign in to comment.