From 3b610b9049785a69e34c52dfe243d09e2ce96d8e Mon Sep 17 00:00:00 2001 From: Kirill Sysoev Date: Wed, 24 Apr 2024 21:36:20 +0800 Subject: [PATCH 1/3] Brings backs connection registry abstraction, this abstraction will be responsible for managing connection settings --- .mockery.yaml | 1 + Makefile | 5 ++++- README.md | 7 ++++++- channel/channel.go | 5 +++-- channel/channel_test.go | 18 +++++++++--------- examples/http_backend/main.go | 2 +- interfaces.go | 10 ++++++++++ 7 files changed, 34 insertions(+), 14 deletions(-) diff --git a/.mockery.yaml b/.mockery.yaml index c38d7dd..e5dd330 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -12,3 +12,4 @@ packages: Connection: Request: Channel: + ConnectionRegistry: diff --git a/Makefile b/Makefile index 48612fe..c46e249 100644 --- a/Makefile +++ b/Makefile @@ -2,4 +2,7 @@ test: go test -v --race ./... lint: - golangci-lint run \ No newline at end of file + golangci-lint run + +mocks: + mockery --all --keeptree \ No newline at end of file diff --git a/README.md b/README.md index 657b869..6436503 100644 --- a/README.md +++ b/README.md @@ -67,9 +67,14 @@ func main() { dispatcher.Use(ErrHandler) dispatcher.Use(request.NewTrottlerMiddleware(10)) + // We create a new connection registry with channel.NewConnectionRegistry. + // This registry keeps track of all active connections + // and responsible for managing connection's settings. + connRegistry := channel.NewConnectionRegistry() + // We create a new server with wasabi.NewServer and add a channel to it with server.AddChannel. // The server listens on port 8080 and the channel handles all requests to the / path. - channel := channel.NewChannel("/", dispatcher) + channel := channel.NewChannel("/", dispatcher, connRegistry) server := server.NewServer(Port) server.AddChannel(channel) diff --git a/channel/channel.go b/channel/channel.go index 011c75a..c4914fb 100644 --- a/channel/channel.go +++ b/channel/channel.go @@ -12,7 +12,7 @@ import ( type Channel struct { path string disptacher wasabi.Dispatcher - connRegistry *ConnectionRegistry + connRegistry wasabi.ConnectionRegistry ctx context.Context middlewares []Middlewere config channelConfig @@ -33,6 +33,7 @@ type Option func(*channelConfig) func NewChannel( path string, dispatcher wasabi.Dispatcher, + connRegistry wasabi.ConnectionRegistry, opts ...Option, ) *Channel { config := channelConfig{ @@ -46,7 +47,7 @@ func NewChannel( return &Channel{ path: path, disptacher: dispatcher, - connRegistry: NewConnectionRegistry(), + connRegistry: connRegistry, middlewares: make([]Middlewere, 0), config: config, } diff --git a/channel/channel_test.go b/channel/channel_test.go index f9baf05..06c7f5c 100644 --- a/channel/channel_test.go +++ b/channel/channel_test.go @@ -13,7 +13,7 @@ func TestNewChannel(t *testing.T) { path := "/test/path" dispatcher := mocks.NewMockDispatcher(t) - channel := NewChannel(path, dispatcher) + channel := NewChannel(path, dispatcher, NewConnectionRegistry()) if channel.path != path { t.Errorf("Unexpected path: got %q, expected %q", channel.path, path) @@ -31,7 +31,7 @@ func TestChannel_Path(t *testing.T) { path := "/test/path" dispatcher := mocks.NewMockDispatcher(t) - channel := NewChannel(path, dispatcher) + channel := NewChannel(path, dispatcher, NewConnectionRegistry()) if channel.Path() != path { t.Errorf("Unexpected path: got %q, expected %q", channel.Path(), path) @@ -41,7 +41,7 @@ func TestChannel_Handler(t *testing.T) { path := "/test/path" dispatcher := mocks.NewMockDispatcher(t) - channel := NewChannel(path, dispatcher) + channel := NewChannel(path, dispatcher, NewConnectionRegistry()) channel.SetContext(context.Background()) // Call the Handler method @@ -55,7 +55,7 @@ func TestChannel_SetContext(t *testing.T) { path := "/test/path" dispatcher := mocks.NewMockDispatcher(t) - channel := NewChannel(path, dispatcher) + channel := NewChannel(path, dispatcher, NewConnectionRegistry()) ctx := context.Background() channel.SetContext(ctx) @@ -68,7 +68,7 @@ func TestChannel_Use(t *testing.T) { path := "/test/path" dispatcher := mocks.NewMockDispatcher(t) - channel := NewChannel(path, dispatcher) + channel := NewChannel(path, dispatcher, NewConnectionRegistry()) middleware := func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -87,7 +87,7 @@ func TestChannel_wrapMiddleware(t *testing.T) { path := "/test/path" dispatcher := mocks.NewMockDispatcher(t) - channel := NewChannel(path, dispatcher) + channel := NewChannel(path, dispatcher, NewConnectionRegistry()) // Create a mock handler mockHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -122,7 +122,7 @@ func TestChannel_SetContextMiddleware(t *testing.T) { path := "/test/path" dispatcher := mocks.NewMockDispatcher(t) - channel := NewChannel(path, dispatcher) + channel := NewChannel(path, dispatcher, NewConnectionRegistry()) // Create a mock handler var ctx context.Context @@ -156,7 +156,7 @@ func TestChannel_WithOriginPatterns(t *testing.T) { path := "/test/path" dispatcher := mocks.NewMockDispatcher(t) - channel := NewChannel(path, dispatcher) + channel := NewChannel(path, dispatcher, NewConnectionRegistry()) if len(channel.config.originPatterns) != 1 { t.Errorf("Unexpected number of origin patterns: got %d, expected %d", len(channel.config.originPatterns), 1) @@ -166,7 +166,7 @@ func TestChannel_WithOriginPatterns(t *testing.T) { t.Errorf("Unexpected to get default origin pattern: got %s, expected %s", channel.config.originPatterns[0], "*") } - channel = NewChannel(path, dispatcher, WithOriginPatterns("test", "test2")) + channel = NewChannel(path, dispatcher, NewConnectionRegistry(), WithOriginPatterns("test", "test2")) if len(channel.config.originPatterns) != 2 { t.Errorf("Unexpected number of origin patterns: got %d, expected %d", len(channel.config.originPatterns), 1) diff --git a/examples/http_backend/main.go b/examples/http_backend/main.go index c93ae56..5b09655 100644 --- a/examples/http_backend/main.go +++ b/examples/http_backend/main.go @@ -40,7 +40,7 @@ func main() { dispatcher.Use(ErrHandler) dispatcher.Use(request.NewTrottlerMiddleware(100)) - channel := channel.NewChannel("/", dispatcher, channel.WithOriginPatterns("*")) + channel := channel.NewChannel("/", dispatcher, channel.NewConnectionRegistry(), channel.WithOriginPatterns("*")) server := server.NewServer(Port) server.AddChannel(channel) diff --git a/interfaces.go b/interfaces.go index adca635..d213efd 100644 --- a/interfaces.go +++ b/interfaces.go @@ -53,3 +53,13 @@ type Channel interface { SetContext(ctx context.Context) Handler() http.Handler } + +// ConnectionRegistry is interface for connection registries +type ConnectionRegistry interface { + AddConnection( + ctx context.Context, + ws *websocket.Conn, + cb OnMessage, + ) Connection + GetConnection(id string) Connection +} From fefbc216027eec7da88412838c58d43c5221daef Mon Sep 17 00:00:00 2001 From: Kirill Sysoev Date: Wed, 24 Apr 2024 21:38:44 +0800 Subject: [PATCH 2/3] Adds connection registry mocks --- mocks/mock_ConnectionRegistry.go | 139 +++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 mocks/mock_ConnectionRegistry.go diff --git a/mocks/mock_ConnectionRegistry.go b/mocks/mock_ConnectionRegistry.go new file mode 100644 index 0000000..4bd2377 --- /dev/null +++ b/mocks/mock_ConnectionRegistry.go @@ -0,0 +1,139 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + +//go:build !compile + +package mocks + +import ( + context "context" + + wasabi "github.com/ksysoev/wasabi" + mock "github.com/stretchr/testify/mock" + + websocket "nhooyr.io/websocket" +) + +// MockConnectionRegistry is an autogenerated mock type for the ConnectionRegistry type +type MockConnectionRegistry struct { + mock.Mock +} + +type MockConnectionRegistry_Expecter struct { + mock *mock.Mock +} + +func (_m *MockConnectionRegistry) EXPECT() *MockConnectionRegistry_Expecter { + return &MockConnectionRegistry_Expecter{mock: &_m.Mock} +} + +// AddConnection provides a mock function with given fields: ctx, ws, cb +func (_m *MockConnectionRegistry) AddConnection(ctx context.Context, ws *websocket.Conn, cb wasabi.OnMessage) wasabi.Connection { + ret := _m.Called(ctx, ws, cb) + + if len(ret) == 0 { + panic("no return value specified for AddConnection") + } + + var r0 wasabi.Connection + if rf, ok := ret.Get(0).(func(context.Context, *websocket.Conn, wasabi.OnMessage) wasabi.Connection); ok { + r0 = rf(ctx, ws, cb) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(wasabi.Connection) + } + } + + return r0 +} + +// MockConnectionRegistry_AddConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddConnection' +type MockConnectionRegistry_AddConnection_Call struct { + *mock.Call +} + +// AddConnection is a helper method to define mock.On call +// - ctx context.Context +// - ws *websocket.Conn +// - cb wasabi.OnMessage +func (_e *MockConnectionRegistry_Expecter) AddConnection(ctx interface{}, ws interface{}, cb interface{}) *MockConnectionRegistry_AddConnection_Call { + return &MockConnectionRegistry_AddConnection_Call{Call: _e.mock.On("AddConnection", ctx, ws, cb)} +} + +func (_c *MockConnectionRegistry_AddConnection_Call) Run(run func(ctx context.Context, ws *websocket.Conn, cb wasabi.OnMessage)) *MockConnectionRegistry_AddConnection_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*websocket.Conn), args[2].(wasabi.OnMessage)) + }) + return _c +} + +func (_c *MockConnectionRegistry_AddConnection_Call) Return(_a0 wasabi.Connection) *MockConnectionRegistry_AddConnection_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockConnectionRegistry_AddConnection_Call) RunAndReturn(run func(context.Context, *websocket.Conn, wasabi.OnMessage) wasabi.Connection) *MockConnectionRegistry_AddConnection_Call { + _c.Call.Return(run) + return _c +} + +// GetConnection provides a mock function with given fields: id +func (_m *MockConnectionRegistry) GetConnection(id string) wasabi.Connection { + ret := _m.Called(id) + + if len(ret) == 0 { + panic("no return value specified for GetConnection") + } + + var r0 wasabi.Connection + if rf, ok := ret.Get(0).(func(string) wasabi.Connection); ok { + r0 = rf(id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(wasabi.Connection) + } + } + + return r0 +} + +// MockConnectionRegistry_GetConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetConnection' +type MockConnectionRegistry_GetConnection_Call struct { + *mock.Call +} + +// GetConnection is a helper method to define mock.On call +// - id string +func (_e *MockConnectionRegistry_Expecter) GetConnection(id interface{}) *MockConnectionRegistry_GetConnection_Call { + return &MockConnectionRegistry_GetConnection_Call{Call: _e.mock.On("GetConnection", id)} +} + +func (_c *MockConnectionRegistry_GetConnection_Call) Run(run func(id string)) *MockConnectionRegistry_GetConnection_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockConnectionRegistry_GetConnection_Call) Return(_a0 wasabi.Connection) *MockConnectionRegistry_GetConnection_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockConnectionRegistry_GetConnection_Call) RunAndReturn(run func(string) wasabi.Connection) *MockConnectionRegistry_GetConnection_Call { + _c.Call.Return(run) + return _c +} + +// NewMockConnectionRegistry creates a new instance of MockConnectionRegistry. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockConnectionRegistry(t interface { + mock.TestingT + Cleanup(func()) +}) *MockConnectionRegistry { + mock := &MockConnectionRegistry{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} From 639e978fe5c4eae37ab4f3ce3a6968e65e1f8983 Mon Sep 17 00:00:00 2001 From: Kirill Sysoev Date: Wed, 24 Apr 2024 21:40:06 +0800 Subject: [PATCH 3/3] Makes gramarly happy --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6436503..73c808d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Wasabi: A Toolkit for Creating WebSocket API Gateway [![WaSAbi](https://github.com/ksysoev/wasabi/actions/workflows/main.yml/badge.svg)](https://github.com/ksysoev/wasabi/actions/workflows/main.yml) -[![codecov](https://codecov.io/gh/ksysoev/wasabi/graph/badge.svg?token=3KGTO1UINI)](https://codecov.io/gh/ksysoev/wasabi) +[![CodeCov](https://codecov.io/gh/ksysoev/wasabi/graph/badge.svg?token=3KGTO1UINI)](https://codecov.io/gh/ksysoev/wasabi) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) Wasabi is a Go package that provides a comprehensive toolkit for creating WebSocket API gateways. It provides a simple and intuitive API to build robust and scalable WebSocket applications.