NoahLan 1 week ago
parent 9687b7b2bf
commit 8d778abbdc

@ -18,7 +18,7 @@
## 安装
```bash
go get github.com/noahlann/nnet
go get git.noahlan.cn/noahlan/nnet/v2
```
## 快速开始
@ -29,7 +29,7 @@ go get github.com/noahlann/nnet
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {
@ -59,7 +59,7 @@ func main() {
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
"time"
"fmt"
)
@ -132,7 +132,7 @@ nnet/
## 链接
- **模块路径**: `github.com/noahlann/nnet`
- **GitHub**: https://github.com/noahlann/nnet
- **模块路径**: `git.noahlan.cn/noahlan/nnet/v2`
- **GitHub**: https://git.noahlan.cn/noahlan/nnet
- **Gitee**: https://gitee.com/noahlann/nnet (镜像)

@ -6,7 +6,7 @@ import (
"os"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {

@ -8,13 +8,13 @@ import (
"syscall"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {
var (
addr = flag.String("addr", "tcp://:8080", "Server address")
protocol = flag.String("protocol", "", "Transport protocol (tcp, udp, websocket, unix, serial). If empty, auto-detect from addr")
addr = flag.String("addr", "tcp://:8080", "Server address")
protocol = flag.String("protocol", "", "Transport protocol (tcp, udp, websocket, unix, serial). If empty, auto-detect from addr")
multicore = flag.Bool("multicore", true, "Enable multicore")
readBuf = flag.Int("read-buf", 4096, "Read buffer size")
writeBuf = flag.Int("write-buf", 4096, "Write buffer size")

@ -129,7 +129,7 @@
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {
@ -152,7 +152,7 @@ func main() {
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {
@ -175,7 +175,7 @@ func main() {
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {
@ -198,7 +198,7 @@ func main() {
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
"time"
)

@ -116,8 +116,8 @@ cfg := &nnet.Config{
package main
import (
"github.com/noahlann/nnet"
ctxpkg "github.com/noahlann/nnet/pkg/context"
"git.noahlan.cn/noahlan/nnet/v2"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
)
type User struct {

@ -229,8 +229,8 @@ if err != nil {
package main
import (
"github.com/noahlann/nnet"
ctxpkg "github.com/noahlann/nnet/pkg/context"
"git.noahlan.cn/noahlan/nnet/v2"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
)
type Response struct {

@ -230,8 +230,8 @@ WriteAnyWithCodec(data interface{}, codecName string) error
package main
import (
"github.com/noahlann/nnet"
ctxpkg "github.com/noahlann/nnet/pkg/context"
"git.noahlan.cn/noahlan/nnet/v2"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
)
type Response struct {

@ -103,8 +103,8 @@ func handler(ctx context.Context) error {
package main
import (
"github.com/noahlann/nnet"
ctxpkg "github.com/noahlann/nnet/pkg/context"
"git.noahlan.cn/noahlan/nnet/v2"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
)
type User struct {

@ -17,7 +17,7 @@
### 1. 创建连接池
```go
import "github.com/noahlann/nnet/pkg/nnet"
import "git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
// 创建连接池配置
poolConfig := &nnet.ClientPoolConfig{

@ -2,7 +2,7 @@
## ⚠️ 注意
**当前项目已改用 GitHub 作为模块路径**`github.com/noahlann/nnet`
**当前项目已改用 GitHub 作为模块路径**`git.noahlan.cn/noahlan/nnet/v2`
本文档仅作为参考,说明如何配置自定义域名。如果您需要使用自定义域名,可以参考本文档。
@ -14,7 +14,7 @@
- 更专业的模块路径
- 更好的控制权
**当前配置**:项目使用 `github.com/noahlann/nnet`,无需域名配置。
**当前配置**:项目使用 `git.noahlan.cn/noahlan/nnet/v2`,无需域名配置。
## 二、域名 DNS 配置

@ -9,7 +9,7 @@
git remote -v
# 添加GitHub远程仓库通常命名为origin
git remote add origin https://github.com/noahlann/nnet.git
git remote add origin https://git.noahlan.cn/noahlan/nnet.git
# 添加Gitee远程仓库
git remote add gitee https://gitee.com/noahlann/nnet.git
@ -31,8 +31,8 @@ git remote -v
输出示例:
```
origin https://github.com/noahlann/nnet.git (fetch)
origin https://github.com/noahlann/nnet.git (push)
origin https://git.noahlan.cn/noahlan/nnet.git (fetch)
origin https://git.noahlan.cn/noahlan/nnet.git (push)
gitee https://gitee.com/noahlann/nnet.git (fetch)
gitee https://gitee.com/noahlann/nnet.git (push)
private https://your-private-git.com/noahlann/nnet.git (fetch)
@ -45,7 +45,7 @@ private https://your-private-git.com/noahlann/nnet.git (push)
```bash
# 修改origin的URL
git remote set-url origin https://github.com/noahlann/nnet.git
git remote set-url origin https://git.noahlan.cn/noahlan/nnet.git
# 修改gitee的URL
git remote set-url gitee https://gitee.com/noahlann/nnet.git
@ -70,7 +70,7 @@ git push private main
```bash
# 为origin添加多个push URL
git remote set-url --add --push origin https://github.com/noahlann/nnet.git
git remote set-url --add --push origin https://git.noahlan.cn/noahlan/nnet.git
git remote set-url --add --push origin https://gitee.com/noahlann/nnet.git
git remote set-url --add --push origin https://your-private-git.com/noahlann/nnet.git
@ -138,7 +138,7 @@ Go的 `go.mod` 中只能有一个 `module` 路径,但不同仓库可能有不
```go
// go.mod
module github.com/noahlann/nnet
module git.noahlan.cn/noahlan/nnet/v2
go 1.25
```
@ -153,7 +153,7 @@ go 1.25
- 如果GitHub不可访问会有问题
**当前配置**
- 模块路径:`github.com/noahlann/nnet`
- 模块路径:`git.noahlan.cn/noahlan/nnet/v2`
- 无需域名配置
#### 方案2使用Gitee作为主路径国内用户
@ -238,7 +238,7 @@ nnet/
```ini
[remote "origin"]
url = https://github.com/noahlann/nnet.git
url = https://git.noahlan.cn/noahlan/nnet.git
fetch = +refs/heads/*:refs/remotes/origin/*
[remote "gitee"]
@ -256,7 +256,7 @@ nnet/
### 4.3 go.mod配置
```go
module github.com/noahlann/nnet
module git.noahlan.cn/noahlan/nnet/v2
go 1.25
@ -337,7 +337,7 @@ push-all:
.PHONY: setup-remotes
setup-remotes:
@echo "Setting up remote repositories..."
@git remote add origin https://github.com/noahlann/nnet.git || true
@git remote add origin https://git.noahlan.cn/noahlan/nnet.git || true
@git remote add gitee https://gitee.com/noahlann/nnet.git || true
@git remote add private https://your-private-git.com/noahlann/nnet.git || true
@echo "Remotes configured!"
@ -414,7 +414,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git remote add github https://x-access-token:${GITHUB_TOKEN}@github.com/noahlann/nnet.git || true
git remote add github https://x-access-token:${GITHUB_TOKEN}@git.noahlan.cn/noahlan/nnet.git || true
git push github main --force || true
```
@ -613,7 +613,7 @@ chmod +x scripts/push-all.sh
### 10.1 推荐方案
1. **使用提供的脚本**`./scripts/setup-remotes.sh` 和 `./scripts/push-all.sh`
2. **使用GitHub作为主路径**go.mod使用 `github.com/noahlann/nnet`(当前配置)
2. **使用GitHub作为主路径**go.mod使用 `git.noahlan.cn/noahlan/nnet/v2`(当前配置)
3. **配置CI/CD自动同步**:减少手动操作
4. **使用SSH密钥**:更安全便捷
@ -625,7 +625,7 @@ chmod +x scripts/setup-remotes.sh
./scripts/setup-remotes.sh
# 方式2手动配置
git remote add origin https://github.com/noahlann/nnet.git
git remote add origin https://git.noahlan.cn/noahlan/nnet.git
git remote add gitee https://gitee.com/noahlann/nnet.git
git remote add private https://your-private-git.com/noahlann/nnet.git

@ -178,8 +178,8 @@ protocol.RegisterFieldExtractor(extractor)
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"github.com/noahlann/nnet/pkg/protocol"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
)
// 定义协议帧头结构
@ -241,8 +241,8 @@ func main() {
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"github.com/noahlann/nnet/pkg/protocol"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
)
// 定义字段映射
@ -296,8 +296,8 @@ func main() {
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"github.com/noahlann/nnet/pkg/protocol"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
)
// 自定义字段提取器

@ -78,8 +78,8 @@ router.GET("/user/login", handler)
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"github.com/noahlann/nnet/pkg/router"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
func main() {
@ -126,8 +126,8 @@ func loginHandler(ctx router.Context) error {
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"github.com/noahlann/nnet/pkg/router"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
// 定义协议帧头结构
@ -247,8 +247,8 @@ server.Router().Register(comboMatcher, handler)
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"github.com/noahlann/nnet/pkg/router"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
func main() {
@ -354,8 +354,8 @@ server.Router().RegisterFrameData(
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"github.com/noahlann/nnet/pkg/router"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
func main() {
@ -406,8 +406,8 @@ func contains(data, pattern []byte) bool {
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"github.com/noahlann/nnet/pkg/router"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
func main() {
@ -443,8 +443,8 @@ func main() {
package main
import (
"github.com/noahlann/nnet/pkg/nnet"
"github.com/noahlann/nnet/pkg/router"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
func main() {

@ -8,7 +8,7 @@ import (
"sync"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {

@ -7,7 +7,7 @@ import (
"log"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {

@ -7,7 +7,7 @@ import (
"os"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
// This example demonstrates the client Request/Response API with timeout.

@ -9,7 +9,7 @@ import (
"os"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
// This example demonstrates client testing interceptor validation.
@ -67,4 +67,3 @@ func main() {
fmt.Printf("response: %s\n", string(resp))
}

@ -8,11 +8,11 @@ import (
"os/signal"
"syscall"
internalinterceptor "github.com/noahlann/nnet/internal/interceptor"
"github.com/noahlann/nnet/internal/interceptor/builtin"
"github.com/noahlann/nnet/pkg/interceptor"
"github.com/noahlann/nnet/pkg/nnet"
routerpkg "github.com/noahlann/nnet/pkg/router"
internalinterceptor "git.noahlan.cn/noahlan/nnet/v2/internal/interceptor"
"git.noahlan.cn/noahlan/nnet/v2/internal/interceptor/builtin"
"git.noahlan.cn/noahlan/nnet/v2/pkg/interceptor"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
// This example demonstrates interceptor chain usage.

@ -7,7 +7,7 @@ import (
"syscall"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
// This example demonstrates enabling metrics and health checks.
@ -46,5 +46,3 @@ func main() {
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
}

@ -9,7 +9,7 @@ import (
"os"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {
@ -41,4 +41,3 @@ func main() {
}
fmt.Printf("response: %s\n", string(resp))
}

@ -6,7 +6,7 @@ import (
"log"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {
@ -43,4 +43,3 @@ func main() {
log.Fatal(err)
}
}

@ -7,7 +7,7 @@ import (
"os/signal"
"syscall"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {

@ -9,7 +9,7 @@ import (
"os"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
// This example demonstrates client connecting to a protocol version server.
@ -56,4 +56,3 @@ func main() {
fmt.Printf("response: %s\n", string(resp))
}

@ -8,8 +8,8 @@ import (
"os/signal"
"syscall"
internalprotocol "github.com/noahlann/nnet/internal/protocol/nnet"
"github.com/noahlann/nnet/pkg/nnet"
internalprotocol "git.noahlan.cn/noahlan/nnet/v2/internal/protocol/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
// This example demonstrates protocol version management.
@ -92,4 +92,3 @@ func main() {
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
}

@ -6,7 +6,7 @@ import (
"os/signal"
"syscall"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
// This example demonstrates using a frame-data matcher to route JSON payloads.

@ -9,7 +9,7 @@ import (
"os"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
// This example demonstrates client interacting with a session file server.
@ -47,4 +47,3 @@ func main() {
fmt.Printf("response: %s\n", string(resp))
}

@ -9,7 +9,7 @@ import (
"syscall"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
// This example demonstrates file-based session storage.
@ -18,9 +18,9 @@ func main() {
cfg := &nnet.Config{
Addr: "tcp://:8083",
Session: &nnet.SessionConfig{
Storage: "file", // 使用文件存储
Path: "./sessions_example", // Session文件存储路径
Expiration: 1 * time.Hour, // Session过期时间
Storage: "file", // 使用文件存储
Path: "./sessions_example", // Session文件存储路径
Expiration: 1 * time.Hour, // Session过期时间
},
Codec: &nnet.CodecConfig{
DefaultCodec: "json",
@ -40,11 +40,11 @@ func main() {
// 实际使用中Session应该通过Connection或Context访问
connID := ctx.Connection().ID()
return ctx.Response().Write(map[string]any{
"action": "set",
"conn_id": connID,
"message": "session storage configured (file)",
"path": cfg.Session.Path,
"note": "Session API integration pending",
"action": "set",
"conn_id": connID,
"message": "session storage configured (file)",
"path": cfg.Session.Path,
"note": "Session API integration pending",
})
})
@ -52,10 +52,10 @@ func main() {
srv.Router().RegisterString("get", func(ctx nnet.Context) error {
connID := ctx.Connection().ID()
return ctx.Response().Write(map[string]any{
"action": "get",
"conn_id": connID,
"storage": "file",
"path": cfg.Session.Path,
"action": "get",
"conn_id": connID,
"storage": "file",
"path": cfg.Session.Path,
"expiration": cfg.Session.Expiration.String(),
})
})
@ -85,4 +85,3 @@ func main() {
log.Println("Shutting down... Sessions are persisted to disk.")
}

@ -9,7 +9,7 @@ import (
"os"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {
@ -42,4 +42,3 @@ func main() {
}
fmt.Printf("echo: %s\n", string(resp))
}

@ -5,7 +5,7 @@ package main
import (
"log"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {
@ -26,4 +26,3 @@ func main() {
log.Fatal(err)
}
}

@ -6,7 +6,7 @@ import (
"os/signal"
"syscall"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
// User 用户结构

@ -9,7 +9,7 @@ import (
"os"
"time"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {
@ -42,4 +42,3 @@ func main() {
}
fmt.Printf("echo: %s\n", string(resp))
}

@ -5,7 +5,7 @@ package main
import (
"log"
"github.com/noahlann/nnet/pkg/nnet"
"git.noahlan.cn/noahlan/nnet/v2/pkg/nnet"
)
func main() {
@ -30,4 +30,3 @@ func main() {
log.Fatal(err)
}
}

@ -1,10 +1,11 @@
module github.com/noahlann/nnet
module git.noahlan.cn/noahlan/nnet/v2
go 1.25
require (
github.com/gorilla/websocket v1.5.3
github.com/panjf2000/gnet/v2 v2.9.5
github.com/rs/xid v1.6.0
github.com/stretchr/testify v1.11.1
go.bug.st/serial v1.6.4
)
@ -14,7 +15,6 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/panjf2000/ants/v2 v2.11.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect

@ -0,0 +1,56 @@
package client
import (
"strings"
protocolnnet "git.noahlan.cn/noahlan/nnet/v2/internal/protocol/nnet"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
unpackerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/unpacker"
)
type unpackingProtocol interface {
Unpacker() unpackerpkg.Unpacker
}
func newApplicationProtocol(name string) protocolpkg.Protocol {
switch strings.ToLower(strings.TrimSpace(name)) {
case "", "none", "raw":
return nil
case "nnet":
return protocolnnet.NewNNetProtocol("1.0")
default:
return nil
}
}
func newApplicationUnpacker(protocol protocolpkg.Protocol) unpackerpkg.Unpacker {
if protocol == nil {
return nil
}
if provider, ok := protocol.(unpackingProtocol); ok {
return provider.Unpacker()
}
return nil
}
func encodeApplicationMessage(protocol protocolpkg.Protocol, data []byte) ([]byte, error) {
if protocol == nil {
return data, nil
}
return protocol.Encode(data, nil)
}
func decodeApplicationMessage(protocol protocolpkg.Protocol, frame []byte) ([]byte, error) {
if protocol == nil {
msg := make([]byte, len(frame))
copy(msg, frame)
return msg, nil
}
_, body, err := protocol.Decode(frame)
if err != nil {
return nil, err
}
msg := make([]byte, len(body))
copy(msg, body)
return msg, nil
}

@ -6,7 +6,7 @@ import (
"sync/atomic"
"time"
clientpkg "github.com/noahlann/nnet/pkg/client"
clientpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/client"
)
// Pool 连接池

@ -5,7 +5,7 @@ import (
"testing"
"time"
clientpkg "github.com/noahlann/nnet/pkg/client"
clientpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/client"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

@ -6,7 +6,7 @@ import (
"sync"
"time"
"github.com/noahlann/nnet/pkg/client"
"git.noahlan.cn/noahlan/nnet/v2/pkg/client"
"go.bug.st/serial"
)
@ -175,4 +175,3 @@ func (c *serialClient) Close() error {
c.cancel()
return c.Disconnect()
}

@ -2,11 +2,14 @@ package client
import (
"context"
"io"
"net"
"sync"
"time"
"github.com/noahlann/nnet/pkg/client"
"git.noahlan.cn/noahlan/nnet/v2/pkg/client"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
unpackerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/unpacker"
)
// tcpClient TCP客户端实现
@ -18,6 +21,13 @@ type tcpClient struct {
ctx context.Context
cancel context.CancelFunc
readBuffer []byte
requestMu sync.Mutex
readMu sync.Mutex
writeMu sync.Mutex
closeOnce sync.Once
protocol protocolpkg.Protocol
unpacker unpackerpkg.Unpacker
pending [][]byte
// 自动重连相关
reconnectAttempts int
@ -41,16 +51,19 @@ func NewTCPClient(config *client.Config) client.Client {
}
ctx, cancel := context.WithCancel(context.Background())
protocol := newApplicationProtocol(config.ApplicationProtocol)
c := &tcpClient{
config: config,
ctx: ctx,
cancel: cancel,
readBuffer: make([]byte, 4096),
reconnectCh: make(chan struct{}, 1),
config: config,
ctx: ctx,
cancel: cancel,
readBuffer: make([]byte, 4096),
protocol: protocol,
unpacker: newApplicationUnpacker(protocol),
reconnectCh: make(chan struct{}, 1),
reconnectStopCh: make(chan struct{}),
messageCh: make(chan []byte, 100),
messageErrCh: make(chan error, 10),
messageCh: make(chan []byte, 100),
messageErrCh: make(chan error, 10),
}
// 如果启用自动重连启动重连goroutine
@ -85,13 +98,36 @@ func (c *tcpClient) connect() error {
}
// 创建连接
dialer := &net.Dialer{
Timeout: c.config.ConnectTimeout,
connectTimeout := c.config.ConnectTimeout
if connectTimeout <= 0 {
connectTimeout = 3 * time.Second
}
conn, err := dialer.DialContext(c.ctx, "tcp", addr)
deadline := time.Now().Add(connectTimeout)
var conn net.Conn
var err error
for {
timeout := time.Until(deadline)
if timeout <= 0 {
break
}
if timeout > 200*time.Millisecond {
timeout = 200 * time.Millisecond
}
dialer := &net.Dialer{Timeout: timeout}
conn, err = dialer.DialContext(c.ctx, "tcp", addr)
if err == nil {
break
}
select {
case <-c.ctx.Done():
return c.ctx.Err()
case <-time.After(20 * time.Millisecond):
}
}
if err != nil {
// 如果启用自动重连,触发重连
if c.config.AutoReconnect {
select {
case c.reconnectCh <- struct{}{}:
@ -104,6 +140,8 @@ func (c *tcpClient) connect() error {
c.conn = conn
c.connected = true
c.reconnectAttempts = 0 // 重置重连次数
c.unpacker = newApplicationUnpacker(c.protocol)
c.pending = nil
return nil
}
@ -123,6 +161,7 @@ func (c *tcpClient) Disconnect() error {
}
c.connected = false
c.pending = nil
// 如果启用自动重连,触发重连
if c.config.AutoReconnect {
@ -135,62 +174,168 @@ func (c *tcpClient) Disconnect() error {
return nil
}
func (c *tcpClient) markDisconnected() {
c.mu.Lock()
defer c.mu.Unlock()
if c.conn != nil {
_ = c.conn.Close()
c.conn = nil
}
c.connected = false
c.pending = nil
if c.config.AutoReconnect {
select {
case c.reconnectCh <- struct{}{}:
default:
}
}
}
func shouldMarkDisconnected(err error) bool {
if err == nil {
return false
}
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
return false
}
return true
}
// Send 发送数据
func (c *tcpClient) Send(data []byte) error {
c.mu.RLock()
defer c.mu.RUnlock()
frame, err := encodeApplicationMessage(c.protocol, data)
if err != nil {
return err
}
c.mu.RLock()
if !c.connected || c.conn == nil {
c.mu.RUnlock()
return client.NewError("not connected")
}
conn := c.conn
writeTimeout := c.config.WriteTimeout
c.mu.RUnlock()
c.writeMu.Lock()
defer c.writeMu.Unlock()
if c.config.WriteTimeout > 0 {
c.conn.SetWriteDeadline(time.Now().Add(c.config.WriteTimeout))
if writeTimeout > 0 {
conn.SetWriteDeadline(time.Now().Add(writeTimeout))
}
_, err := c.conn.Write(data)
return err
for len(frame) > 0 {
n, err := conn.Write(frame)
if shouldMarkDisconnected(err) {
c.markDisconnected()
}
if err != nil {
return err
}
if n == 0 {
c.markDisconnected()
return io.ErrShortWrite
}
frame = frame[n:]
}
return nil
}
// Receive 接收数据
func (c *tcpClient) Receive() ([]byte, error) {
c.mu.RLock()
defer c.mu.RUnlock()
return c.receiveWithTimeout(0)
}
func (c *tcpClient) receiveWithTimeout(timeout time.Duration) ([]byte, error) {
c.readMu.Lock()
defer c.readMu.Unlock()
if len(c.pending) > 0 {
msg := c.pending[0]
c.pending[0] = nil
c.pending = c.pending[1:]
return msg, nil
}
c.mu.RLock()
if !c.connected || c.conn == nil {
c.mu.RUnlock()
return nil, client.NewError("not connected")
}
if c.config.ReadTimeout > 0 {
c.conn.SetReadDeadline(time.Now().Add(c.config.ReadTimeout))
conn := c.conn
readTimeout := c.config.ReadTimeout
if timeout > 0 {
readTimeout = timeout
}
n, err := c.conn.Read(c.readBuffer)
if err != nil {
return nil, err
bufferSize := len(c.readBuffer)
if bufferSize <= 0 {
bufferSize = 4096
}
protocol := c.protocol
c.mu.RUnlock()
for {
buffer := make([]byte, bufferSize)
if readTimeout > 0 {
conn.SetReadDeadline(time.Now().Add(readTimeout))
}
result := make([]byte, n)
copy(result, c.readBuffer[:n])
return result, nil
n, err := conn.Read(buffer)
if err != nil {
if shouldMarkDisconnected(err) {
c.markDisconnected()
}
return nil, err
}
if protocol == nil {
result := make([]byte, n)
copy(result, buffer[:n])
return result, nil
}
if c.unpacker == nil {
return decodeApplicationMessage(protocol, buffer[:n])
}
frames, _, _, err := c.unpacker.Unpack(buffer[:n])
if err != nil {
if shouldMarkDisconnected(err) {
c.markDisconnected()
}
return nil, err
}
if len(frames) == 0 {
continue
}
decoded := make([][]byte, 0, len(frames))
for _, frame := range frames {
msg, err := decodeApplicationMessage(protocol, frame)
if err != nil {
return nil, err
}
decoded = append(decoded, msg)
}
c.pending = append(c.pending, decoded[1:]...)
return decoded[0], nil
}
}
// Request 请求-响应(带超时)
func (c *tcpClient) Request(data []byte, timeout time.Duration) ([]byte, error) {
c.requestMu.Lock()
defer c.requestMu.Unlock()
// 发送请求
if err := c.Send(data); err != nil {
return nil, err
}
// 设置读取超时
oldTimeout := c.config.ReadTimeout
c.config.ReadTimeout = timeout
defer func() {
c.config.ReadTimeout = oldTimeout
}()
// 接收响应
return c.Receive()
return c.receiveWithTimeout(timeout)
}
// IsConnected 检查是否已连接
@ -202,8 +347,10 @@ func (c *tcpClient) IsConnected() bool {
// Close 关闭客户端
func (c *tcpClient) Close() error {
c.cancel()
close(c.reconnectStopCh)
c.closeOnce.Do(func() {
c.cancel()
close(c.reconnectStopCh)
})
c.mu.Lock()
defer c.mu.Unlock()
c.config.AutoReconnect = false // 禁用自动重连
@ -212,6 +359,7 @@ func (c *tcpClient) Close() error {
c.conn = nil
}
c.connected = false
c.pending = nil
return nil
}
@ -294,8 +442,7 @@ func (c *tcpClient) messageReceiver() {
conn.SetReadDeadline(time.Now().Add(c.config.ReadTimeout))
}
buffer := make([]byte, 4096)
n, err := conn.Read(buffer)
msg, err := c.receiveWithTimeout(c.config.ReadTimeout)
if err != nil {
// 连接错误,触发重连
if c.config.AutoReconnect {
@ -318,17 +465,15 @@ func (c *tcpClient) messageReceiver() {
}
// 发送消息到channel
message := make([]byte, n)
copy(message, buffer[:n])
select {
case c.messageCh <- message:
case c.messageCh <- msg:
default:
// channel已满丢弃消息
}
// 调用回调
if c.onMessage != nil {
c.onMessage(message)
c.onMessage(msg)
}
}
}
@ -357,4 +502,3 @@ func (c *tcpClient) SetOnError(fn func(error)) {
func (c *tcpClient) MessageChannel() <-chan []byte {
return c.messageCh
}

@ -4,7 +4,7 @@ import (
"testing"
"time"
"github.com/noahlann/nnet/pkg/client"
"git.noahlan.cn/noahlan/nnet/v2/pkg/client"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -53,5 +53,3 @@ func TestTCPClientConnectInvalidAddrRespectsTimeout(t *testing.T) {
elapsed := time.Since(start)
assert.LessOrEqual(t, elapsed, 500*time.Millisecond, "connect should fail quickly honoring timeout")
}

@ -4,7 +4,7 @@ import (
"testing"
"time"
"github.com/noahlann/nnet/pkg/client"
"git.noahlan.cn/noahlan/nnet/v2/pkg/client"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

@ -5,7 +5,7 @@ import (
"sync"
"time"
"github.com/noahlann/nnet/pkg/client"
"git.noahlan.cn/noahlan/nnet/v2/pkg/client"
)
// udpClient UDP客户端实现

@ -5,7 +5,7 @@ import (
"sync"
"time"
"github.com/noahlann/nnet/pkg/client"
"git.noahlan.cn/noahlan/nnet/v2/pkg/client"
)
// unixClient Unix Domain Socket客户端实现
@ -147,4 +147,3 @@ func (c *unixClient) IsConnected() bool {
func (c *unixClient) Close() error {
return c.Disconnect()
}

@ -2,11 +2,14 @@ package client
import (
"net/url"
"strings"
"sync"
"time"
"git.noahlan.cn/noahlan/nnet/v2/pkg/client"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
unpackerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/unpacker"
"github.com/gorilla/websocket"
"github.com/noahlann/nnet/pkg/client"
)
// websocketClient WebSocket客户端实现
@ -14,7 +17,13 @@ type websocketClient struct {
config *client.Config
conn *websocket.Conn
mu sync.RWMutex
requestMu sync.Mutex
readMu sync.Mutex
writeMu sync.Mutex
connected bool
protocol protocolpkg.Protocol
unpacker unpackerpkg.Unpacker
pending [][]byte
}
// NewWebSocketClient 创建WebSocket客户端
@ -22,10 +31,13 @@ func NewWebSocketClient(config *client.Config) client.Client {
if config == nil {
config = client.DefaultConfig()
}
protocol := newApplicationProtocol(config.ApplicationProtocol)
return &websocketClient{
config: config,
connected: false,
protocol: protocol,
unpacker: newApplicationUnpacker(protocol),
}
}
@ -41,11 +53,11 @@ func (c *websocketClient) Connect() error {
// 解析地址
addr := c.config.Addr
scheme := "ws"
if len(addr) > 6 && addr[:6] == "ws://" {
addr = addr[6:]
if strings.HasPrefix(addr, "ws://") {
addr = strings.TrimPrefix(addr, "ws://")
scheme = "ws"
} else if len(addr) > 7 && addr[:7] == "wss://" {
addr = addr[7:]
} else if strings.HasPrefix(addr, "wss://") {
addr = strings.TrimPrefix(addr, "wss://")
scheme = "wss"
} else if c.config.TLSEnabled {
scheme = "wss"
@ -66,6 +78,8 @@ func (c *websocketClient) Connect() error {
c.conn = conn
c.connected = true
c.unpacker = newApplicationUnpacker(c.protocol)
c.pending = nil
return nil
}
@ -85,59 +99,125 @@ func (c *websocketClient) Disconnect() error {
}
c.connected = false
c.pending = nil
return nil
}
// Send 发送数据
func (c *websocketClient) Send(data []byte) error {
c.mu.RLock()
defer c.mu.RUnlock()
frame, err := encodeApplicationMessage(c.protocol, data)
if err != nil {
return err
}
c.mu.RLock()
if !c.connected || c.conn == nil {
c.mu.RUnlock()
return client.NewError("not connected")
}
conn := c.conn
writeTimeout := c.config.WriteTimeout
c.mu.RUnlock()
return c.conn.WriteMessage(websocket.TextMessage, data)
c.writeMu.Lock()
defer c.writeMu.Unlock()
if writeTimeout > 0 {
conn.SetWriteDeadline(time.Now().Add(writeTimeout))
}
if err := conn.WriteMessage(websocket.BinaryMessage, frame); err != nil {
c.markDisconnected()
return err
}
return nil
}
// Receive 接收数据
func (c *websocketClient) Receive() ([]byte, error) {
c.mu.RLock()
defer c.mu.RUnlock()
return c.receiveWithTimeout(0)
}
func (c *websocketClient) receiveWithTimeout(timeout time.Duration) ([]byte, error) {
c.readMu.Lock()
defer c.readMu.Unlock()
if len(c.pending) > 0 {
msg := c.pending[0]
c.pending[0] = nil
c.pending = c.pending[1:]
return msg, nil
}
c.mu.RLock()
if !c.connected || c.conn == nil {
c.mu.RUnlock()
return nil, client.NewError("not connected")
}
// 设置读取超时
if c.config.ReadTimeout > 0 {
c.conn.SetReadDeadline(time.Now().Add(c.config.ReadTimeout))
conn := c.conn
readTimeout := c.config.ReadTimeout
if timeout > 0 {
readTimeout = timeout
}
protocol := c.protocol
c.mu.RUnlock()
_, data, err := c.conn.ReadMessage()
if err != nil {
return nil, err
// 设置读取超时
for {
if readTimeout > 0 {
conn.SetReadDeadline(time.Now().Add(readTimeout))
}
_, data, err := conn.ReadMessage()
if err != nil {
c.markDisconnected()
return nil, err
}
if protocol == nil {
msg := make([]byte, len(data))
copy(msg, data)
return msg, nil
}
if c.unpacker == nil {
return decodeApplicationMessage(protocol, data)
}
frames, _, _, err := c.unpacker.Unpack(data)
if err != nil {
c.markDisconnected()
return nil, err
}
if len(frames) == 0 {
continue
}
decoded := make([][]byte, 0, len(frames))
for _, frame := range frames {
msg, err := decodeApplicationMessage(protocol, frame)
if err != nil {
return nil, err
}
decoded = append(decoded, msg)
}
c.pending = append(c.pending, decoded[1:]...)
return decoded[0], nil
}
return data, nil
}
// Request 请求-响应(带超时)
func (c *websocketClient) Request(data []byte, timeout time.Duration) ([]byte, error) {
c.requestMu.Lock()
defer c.requestMu.Unlock()
// 发送请求
if err := c.Send(data); err != nil {
return nil, err
}
// 设置读取超时
oldTimeout := c.config.ReadTimeout
c.config.ReadTimeout = timeout
defer func() {
c.config.ReadTimeout = oldTimeout
}()
// 接收响应
return c.Receive()
return c.receiveWithTimeout(timeout)
}
// IsConnected 检查是否已连接
@ -152,3 +232,14 @@ func (c *websocketClient) Close() error {
return c.Disconnect()
}
func (c *websocketClient) markDisconnected() {
c.mu.Lock()
defer c.mu.Unlock()
if c.conn != nil {
_ = c.conn.Close()
c.conn = nil
}
c.connected = false
c.pending = nil
}

@ -5,7 +5,7 @@ import (
"encoding/binary"
"reflect"
"github.com/noahlann/nnet/pkg/codec"
"git.noahlan.cn/noahlan/nnet/v2/pkg/codec"
)
// BinaryCodec 二进制编解码器
@ -104,4 +104,3 @@ func (c *BinaryCodec) Decode(data []byte, v interface{}) error {
func (c *BinaryCodec) Name() string {
return "binary"
}

@ -91,4 +91,3 @@ func TestBinaryCodecInvalidType(t *testing.T) {
_, err := codec.Encode("invalid")
assert.Error(t, err, "Expected error for invalid type")
}

@ -3,7 +3,7 @@ package codec
import (
"encoding/json"
"github.com/noahlann/nnet/pkg/codec"
"git.noahlan.cn/noahlan/nnet/v2/pkg/codec"
)
// JSONCodec JSON编解码器
@ -28,4 +28,3 @@ func (c *JSONCodec) Decode(data []byte, v interface{}) error {
func (c *JSONCodec) Name() string {
return "json"
}

@ -126,4 +126,3 @@ func TestJSONCodecComplexStruct(t *testing.T) {
assert.Equal(t, data.Tags, decoded.Tags)
assert.Equal(t, data.Metadata, decoded.Metadata)
}

@ -3,7 +3,7 @@ package codec
import (
"encoding/json"
codecpkg "github.com/noahlann/nnet/pkg/codec"
codecpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/codec"
)
// MessagePackCodec MessagePack编解码器
@ -62,4 +62,3 @@ func (d *defaultMessagePackDecoder) Decode(data []byte, v interface{}) error {
// 如果没有安装msgpack库使用JSON作为fallback
return json.Unmarshal(data, v)
}

@ -59,4 +59,3 @@ func TestMessagePackCodecInvalidData(t *testing.T) {
// 由于使用JSON fallback可能会成功或失败这里只测试不会panic
_ = err
}

@ -3,7 +3,7 @@ package codec
import (
"fmt"
codecpkg "github.com/noahlann/nnet/pkg/codec"
codecpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/codec"
)
// PlainCodec 直接透传的编解码器

@ -3,7 +3,7 @@ package codec
import (
"fmt"
codecpkg "github.com/noahlann/nnet/pkg/codec"
codecpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/codec"
)
// ProtobufCodec Protobuf编解码器

@ -64,4 +64,3 @@ func (m *testProtoMessage) Unmarshal(data []byte) error {
m.data = data
return nil
}

@ -4,7 +4,7 @@ import (
"fmt"
"sync"
codecpkg "github.com/noahlann/nnet/pkg/codec"
codecpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/codec"
)
// registry 编解码器注册表实现

@ -4,7 +4,7 @@ import (
"testing"
"time"
"github.com/noahlann/nnet/pkg/errors"
"git.noahlan.cn/noahlan/nnet/v2/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

@ -93,4 +93,3 @@ func (s *ConditionGroupStrategy) GetGroupID(conn ConnectionInterface) string {
func (s *ConditionGroupStrategy) Match(conn ConnectionInterface, groupID string) bool {
return s.GetGroupID(conn) == groupID
}

@ -104,4 +104,3 @@ func (c *SerialConnection) UpdateActive() {
defer c.mu.Unlock()
c.lastActive = time.Now()
}

@ -6,7 +6,7 @@ import (
"sync/atomic"
"time"
"github.com/noahlann/nnet/pkg/errors"
"git.noahlan.cn/noahlan/nnet/v2/pkg/errors"
)
// ShardedManager 分段连接管理器(减少锁竞争)
@ -264,7 +264,7 @@ func (m *ShardedManager) BroadcastToGroup(groupID string, data []byte) error {
defer wg.Done()
var localErrs []error
for _, conn := range connections {
if err := conn.Write(data); err != nil {
if err := conn.Write(data); err != nil {
localErrs = append(localErrs, err)
}
}
@ -272,7 +272,7 @@ func (m *ShardedManager) BroadcastToGroup(groupID string, data []byte) error {
mu.Lock()
errs = append(errs, localErrs...)
mu.Unlock()
}
}
}(conns)
}

@ -8,7 +8,7 @@ import (
"testing"
"time"
"github.com/noahlann/nnet/pkg/errors"
"git.noahlan.cn/noahlan/nnet/v2/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

@ -131,4 +131,3 @@ func (c *UDPConnection) UpdateActive() {
defer c.mu.Unlock()
c.lastActive = time.Now()
}

@ -108,4 +108,3 @@ func (c *UnixConnection) UpdateActive() {
defer c.mu.Unlock()
c.lastActive = time.Now()
}

@ -13,6 +13,7 @@ type WebSocketConnection struct {
id string
conn *websocket.Conn
mu sync.RWMutex
writeMu sync.Mutex
createdAt time.Time
lastActive time.Time
attributes map[string]interface{}
@ -61,6 +62,8 @@ func (c *WebSocketConnection) Write(data []byte) error {
c.mu.Unlock()
if c.conn != nil {
c.writeMu.Lock()
defer c.writeMu.Unlock()
return c.conn.WriteMessage(websocket.TextMessage, data)
}
return nil
@ -107,4 +110,3 @@ func (c *WebSocketConnection) UpdateActive() {
defer c.mu.Unlock()
c.lastActive = time.Now()
}

@ -1,8 +1,8 @@
package builtin
import (
ctxpkg "github.com/noahlann/nnet/pkg/context"
interceptorpkg "github.com/noahlann/nnet/pkg/interceptor"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
interceptorpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/interceptor"
)
// ValidationInterceptor 验证拦截器
@ -39,4 +39,3 @@ func MaxLengthInterceptor(maxLength int) interceptorpkg.Interceptor {
return nil
})
}

@ -3,12 +3,12 @@ package builtin
import (
"testing"
"github.com/noahlann/nnet/internal/codec"
interceptorimpl "github.com/noahlann/nnet/internal/interceptor"
"github.com/noahlann/nnet/internal/request"
"github.com/noahlann/nnet/internal/response"
ctxpkg "github.com/noahlann/nnet/pkg/context"
interceptorpkg "github.com/noahlann/nnet/pkg/interceptor"
"git.noahlan.cn/noahlan/nnet/v2/internal/codec"
interceptorimpl "git.noahlan.cn/noahlan/nnet/v2/internal/interceptor"
"git.noahlan.cn/noahlan/nnet/v2/internal/request"
"git.noahlan.cn/noahlan/nnet/v2/internal/response"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
interceptorpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/interceptor"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

@ -1,8 +1,8 @@
package interceptor
import (
ctxpkg "github.com/noahlann/nnet/pkg/context"
interceptorpkg "github.com/noahlann/nnet/pkg/interceptor"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
interceptorpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/interceptor"
)
// chain 拦截器链实现
@ -43,4 +43,3 @@ func Execute(data []byte, ctx ctxpkg.Context, interceptors ...interceptorpkg.Int
chain := NewChain(interceptors...)
return chain.Next(data, ctx)
}

@ -4,11 +4,11 @@ import (
"errors"
"testing"
"github.com/noahlann/nnet/internal/codec"
"github.com/noahlann/nnet/internal/request"
"github.com/noahlann/nnet/internal/response"
ctxpkg "github.com/noahlann/nnet/pkg/context"
interceptorpkg "github.com/noahlann/nnet/pkg/interceptor"
"git.noahlan.cn/noahlan/nnet/v2/internal/codec"
"git.noahlan.cn/noahlan/nnet/v2/internal/request"
"git.noahlan.cn/noahlan/nnet/v2/internal/response"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
interceptorpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/interceptor"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

@ -1,8 +1,8 @@
package builtin
import (
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
// AuthMiddleware 认证中间件工厂
@ -36,4 +36,3 @@ func HeaderAuthMiddleware(headerKey string, expectedValue string) routerpkg.Hand
return value == expectedValue
})
}

@ -4,8 +4,8 @@ import (
"fmt"
"time"
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
// LoggingMiddleware 日志中间件

@ -4,8 +4,8 @@ import (
"sync"
"time"
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
// RateLimiter 限流器
@ -68,4 +68,3 @@ func RateLimitMiddleware(limiter *RateLimiter) routerpkg.Handler {
return nil
}
}

@ -4,8 +4,8 @@ import (
"fmt"
"runtime/debug"
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
// RecoveryMiddleware 恢复中间件捕获panic
@ -39,4 +39,3 @@ func RecoveryMiddlewareWithHandler(handler func(ctx ctxpkg.Context, panic interf
return nil
}
}

@ -1,8 +1,8 @@
package middleware
import (
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
// Chain 中间件链
@ -53,4 +53,3 @@ func (c *Chain) Append(middleware ...routerpkg.Handler) {
func (c *Chain) Prepend(middleware ...routerpkg.Handler) {
c.middlewares = append(middleware, c.middlewares...)
}

@ -4,10 +4,10 @@ import (
"errors"
"testing"
"github.com/noahlann/nnet/internal/codec"
"github.com/noahlann/nnet/internal/request"
"github.com/noahlann/nnet/internal/response"
ctxpkg "github.com/noahlann/nnet/pkg/context"
"git.noahlan.cn/noahlan/nnet/v2/internal/codec"
"git.noahlan.cn/noahlan/nnet/v2/internal/request"
"git.noahlan.cn/noahlan/nnet/v2/internal/response"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

@ -5,8 +5,8 @@ import (
"fmt"
"sync"
"github.com/noahlann/nnet/pkg/config"
pluginpkg "github.com/noahlann/nnet/pkg/plugin"
"git.noahlan.cn/noahlan/nnet/v2/pkg/config"
pluginpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/plugin"
)
// manager 插件管理器实现
@ -131,4 +131,3 @@ func (m *manager) StopAll(ctx context.Context) error {
return nil
}

@ -4,7 +4,7 @@ import (
"encoding/json"
"sync"
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
)
// frameHeader 协议帧头实现
@ -99,4 +99,3 @@ func (h *frameHeader) Clone() protocolpkg.FrameHeader {
return cloned
}

@ -5,7 +5,7 @@ import (
"fmt"
"sync"
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
)
// manager 协议管理器实现
@ -213,4 +213,3 @@ func (m *manager) IdentifyVersion(name string, data []byte, ctx context.Context)
return version, nil
}

@ -6,8 +6,8 @@ import (
"testing"
"time"
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
unpackerpkg "github.com/noahlann/nnet/pkg/unpacker"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
unpackerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/unpacker"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

@ -3,7 +3,7 @@ package nnet
import (
"testing"
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

@ -4,19 +4,16 @@ import (
"context"
"encoding/binary"
"fmt"
"sync"
internalprotocol "github.com/noahlann/nnet/internal/protocol"
internalunpacker "github.com/noahlann/nnet/internal/unpacker"
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
unpackerpkg "github.com/noahlann/nnet/pkg/unpacker"
internalprotocol "git.noahlan.cn/noahlan/nnet/v2/internal/protocol"
internalunpacker "git.noahlan.cn/noahlan/nnet/v2/internal/unpacker"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
unpackerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/unpacker"
)
// NNetProtocol nnet协议实现
type NNetProtocol struct {
version string
unpacker unpackerpkg.Unpacker
once sync.Once
version string
}
// NewNNetProtocol 创建nnet协议
@ -175,20 +172,15 @@ func (p *NNetProtocol) Handle(ctx context.Context, data []byte) ([]byte, error)
// Unpacker 获取协议的拆包器
// nnet协议使用LengthFieldUnpacker来处理粘包拆包
func (p *NNetProtocol) Unpacker() unpackerpkg.Unpacker {
p.once.Do(func() {
// nnet协议格式[Magic(4)][Version(1)][Length(4)][Data(N)][Checksum(2)]
// 长度字段在偏移5的位置Magic 4字节 + Version 1字节
// 长度字段是4字节表示Data部分的长度
// 总长度 = 5Magic+Version + 4Length字段 + Length数据长度 + 2Checksum
config := unpackerpkg.LengthFieldUnpacker{
LengthFieldOffset: 5, // Magic(4) + Version(1) = 5
LengthFieldLength: 4, // Length字段是4字节
LengthAdjustment: 2, // 需要加上Checksum(2字节)
InitialBytesToStrip: 0, // 不跳过任何字节,保留完整包
}
p.unpacker = internalunpacker.NewLengthFieldUnpacker(config)
})
return p.unpacker
// The unpacker owns mutable buffering state, so each connection must get
// its own instance. Protocol objects are shared by the protocol manager.
config := unpackerpkg.LengthFieldUnpacker{
LengthFieldOffset: 5, // Magic(4) + Version(1) = 5
LengthFieldLength: 4, // Length字段是4字节
LengthAdjustment: 2, // 需要加上Checksum(2字节)
InitialBytesToStrip: 0, // 不跳过任何字节,保留完整包
}
return internalunpacker.NewLengthFieldUnpacker(config)
}
// DecodeHeader 解码帧头(增量解析,即使数据不完整)

@ -4,8 +4,8 @@ import (
"encoding/binary"
"testing"
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
unpackerpkg "github.com/noahlann/nnet/pkg/unpacker"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
unpackerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/unpacker"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -95,9 +95,9 @@ func TestNNetProtocol_Unpacker_Config(t *testing.T) {
u := withUnpacker.Unpacker()
require.NotNil(t, u)
// Should return same singleton
// Unpackers own mutable buffering state, so callers must receive distinct instances.
u2 := withUnpacker.Unpacker()
assert.Equal(t, u, u2)
assert.NotSame(t, u, u2)
}
// Ensure it implements protocol interface

@ -4,7 +4,7 @@ import (
"context"
"fmt"
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
)
// NNetVersionIdentifier NNet协议版本识别器
@ -58,4 +58,3 @@ func (i *NNetVersionIdentifier) Identify(data []byte, ctx context.Context) (stri
return version, nil
}

@ -20,10 +20,10 @@ func TestNNetVersionIdentifier_Identify(t *testing.T) {
t.Run("Identify version 1.0", func(t *testing.T) {
// 创建版本1的数据包Magic + Version(1) + Length(4) + Data + Checksum
data := []byte("NNET")
data = append(data, byte(1)) // version
data = append(data, byte(1)) // version
data = append(data, []byte{0, 0, 0, 5}...) // length
data = append(data, []byte("hello")...) // data
data = append(data, []byte{0, 0}...) // checksum (简化)
data = append(data, []byte("hello")...) // data
data = append(data, []byte{0, 0}...) // checksum (简化)
version, err := identifier.Identify(data, context.Background())
require.NoError(t, err)
@ -33,10 +33,10 @@ func TestNNetVersionIdentifier_Identify(t *testing.T) {
// 测试版本2识别
t.Run("Identify version 2.0", func(t *testing.T) {
data := []byte("NNET")
data = append(data, byte(2)) // version
data = append(data, byte(2)) // version
data = append(data, []byte{0, 0, 0, 5}...) // length
data = append(data, []byte("hello")...) // data
data = append(data, []byte{0, 0}...) // checksum (简化)
data = append(data, []byte("hello")...) // data
data = append(data, []byte{0, 0}...) // checksum (简化)
version, err := identifier.Identify(data, context.Background())
require.NoError(t, err)
@ -65,7 +65,7 @@ func TestNNetVersionIdentifier_Identify(t *testing.T) {
// 测试未知版本
t.Run("Unknown version", func(t *testing.T) {
data := []byte("NNET")
data = append(data, byte(99)) // unknown version
data = append(data, byte(99)) // unknown version
data = append(data, []byte{0, 0, 0, 5}...) // length
version, err := identifier.Identify(data, context.Background())
@ -79,13 +79,12 @@ func TestNNetVersionIdentifier_DefaultMapping(t *testing.T) {
identifier := NewNNetVersionIdentifier(nil)
data := []byte("NNET")
data = append(data, byte(1)) // version
data = append(data, byte(1)) // version
data = append(data, []byte{0, 0, 0, 5}...) // length
data = append(data, []byte("hello")...) // data
data = append(data, []byte{0, 0}...) // checksum (简化)
data = append(data, []byte("hello")...) // data
data = append(data, []byte{0, 0}...) // checksum (简化)
version, err := identifier.Identify(data, context.Background())
require.NoError(t, err)
assert.Equal(t, "1.0", version)
}

@ -3,7 +3,7 @@ package version
import (
"context"
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
)
// HeaderIdentifier 基于帧头的版本识别器
@ -88,4 +88,3 @@ func (i *CustomIdentifier) Identify(data []byte, ctx context.Context) (string, e
}
return i.fn(data, ctx)
}

@ -1,8 +1,8 @@
package request
import (
internalprotocol "github.com/noahlann/nnet/internal/protocol"
requestpkg "github.com/noahlann/nnet/pkg/request"
internalprotocol "git.noahlan.cn/noahlan/nnet/v2/internal/protocol"
requestpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/request"
)
// newFrameHeader 创建新的协议帧头(内部使用)
@ -10,4 +10,3 @@ import (
func newFrameHeader() requestpkg.FrameHeader {
return internalprotocol.NewFrameHeader()
}

@ -39,4 +39,3 @@ func TestFrameHeaderConcurrent(t *testing.T) {
<-done
}
}

@ -1,7 +1,7 @@
package request
import (
requestpkg "github.com/noahlann/nnet/pkg/request"
requestpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/request"
)
// RequestSetter 内部使用的Request设置接口
@ -25,4 +25,3 @@ func AsRequestSetter(req requestpkg.Request) RequestSetter {
func NewFrameHeader() requestpkg.FrameHeader {
return newFrameHeader()
}

@ -4,8 +4,8 @@ import (
"encoding/json"
"fmt"
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
requestpkg "github.com/noahlann/nnet/pkg/request"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
requestpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/request"
)
// requestImpl 请求实现

@ -4,8 +4,8 @@ import (
"context"
"testing"
"github.com/noahlann/nnet/pkg/protocol"
unpackerpkg "github.com/noahlann/nnet/pkg/unpacker"
"git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
unpackerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/unpacker"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -180,4 +180,3 @@ func (m *mockProtocol) Handle(ctx context.Context, data []byte) ([]byte, error)
func (m *mockProtocol) Unpacker() unpackerpkg.Unpacker {
return nil
}

@ -1,8 +1,8 @@
package response
import (
internalprotocol "github.com/noahlann/nnet/internal/protocol"
responsepkg "github.com/noahlann/nnet/pkg/response"
internalprotocol "git.noahlan.cn/noahlan/nnet/v2/internal/protocol"
responsepkg "git.noahlan.cn/noahlan/nnet/v2/pkg/response"
)
// NewFrameHeader 创建新的协议帧头
@ -10,4 +10,3 @@ import (
func NewFrameHeader() responsepkg.FrameHeader {
return internalprotocol.NewFrameHeader()
}

@ -73,4 +73,3 @@ func TestFrameHeaderEncodeDecode(t *testing.T) {
err = emptyHeader2.Decode([]byte("{}"))
assert.NoError(t, err, "Decode empty JSON should not return error")
}

@ -1,8 +1,8 @@
package response
import (
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
responsepkg "github.com/noahlann/nnet/pkg/response"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
responsepkg "git.noahlan.cn/noahlan/nnet/v2/pkg/response"
)
// convertResponseHeaderToProtocolHeader 将响应帧头转换为协议帧头
@ -37,4 +37,3 @@ func convertResponseHeaderToProtocolHeaderWithClone(responseHeader responsepkg.F
// 如果类型不匹配理论上不应该发生返回nil
return nil
}

@ -3,10 +3,10 @@ package response
import (
"fmt"
"github.com/noahlann/nnet/pkg/codec"
ctxpkg "github.com/noahlann/nnet/pkg/context"
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
responsepkg "github.com/noahlann/nnet/pkg/response"
"git.noahlan.cn/noahlan/nnet/v2/pkg/codec"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
responsepkg "git.noahlan.cn/noahlan/nnet/v2/pkg/response"
)
// connectionWriter 连接写入接口(避免循环依赖)

@ -5,9 +5,9 @@ import (
"errors"
"testing"
codecimpl "github.com/noahlann/nnet/internal/codec"
protocolpkg "github.com/noahlann/nnet/pkg/protocol"
unpackerpkg "github.com/noahlann/nnet/pkg/unpacker"
codecimpl "git.noahlan.cn/noahlan/nnet/v2/internal/codec"
protocolpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/protocol"
unpackerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/unpacker"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -138,7 +138,7 @@ func TestResponseWriteWithProtocol(t *testing.T) {
// mockConnectionWriter 模拟连接写入器
type mockConnectionWriter struct {
written [][]byte
written [][]byte
writeError error
}
@ -180,4 +180,3 @@ func (m *mockProtocol) Handle(ctx context.Context, data []byte) ([]byte, error)
func (m *mockProtocol) Unpacker() unpackerpkg.Unpacker {
return nil
}

@ -1,8 +1,8 @@
package router
import (
ctxpkg "github.com/noahlann/nnet/pkg/context"
"github.com/noahlann/nnet/pkg/router"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
"git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
// routerGroup 路由分组实现

@ -3,7 +3,7 @@ package router
import (
"testing"
ctxpkg "github.com/noahlann/nnet/pkg/context"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
"github.com/stretchr/testify/assert"
)
@ -51,4 +51,3 @@ func TestRouterGroupWithMiddleware(t *testing.T) {
routeHandler := route.Handler()
assert.NotNil(t, routeHandler, "Expected handler to be non-nil")
}

@ -3,8 +3,8 @@ package matcher
import (
"testing"
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
"github.com/stretchr/testify/assert"
)

@ -5,8 +5,8 @@ import (
"reflect"
"strings"
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
// FrameDataMatcher 帧数据匹配器

@ -4,11 +4,11 @@ import (
"encoding/json"
"testing"
"github.com/noahlann/nnet/internal/codec"
"github.com/noahlann/nnet/internal/request"
"github.com/noahlann/nnet/internal/response"
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
"git.noahlan.cn/noahlan/nnet/v2/internal/codec"
"git.noahlan.cn/noahlan/nnet/v2/internal/request"
"git.noahlan.cn/noahlan/nnet/v2/internal/response"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
"github.com/stretchr/testify/assert"
)

@ -4,11 +4,11 @@ import (
"encoding/json"
"testing"
"github.com/noahlann/nnet/internal/codec"
"github.com/noahlann/nnet/internal/request"
"github.com/noahlann/nnet/internal/response"
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
"git.noahlan.cn/noahlan/nnet/v2/internal/codec"
"git.noahlan.cn/noahlan/nnet/v2/internal/request"
"git.noahlan.cn/noahlan/nnet/v2/internal/response"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
"github.com/stretchr/testify/assert"
)

@ -3,8 +3,8 @@ package matcher
import (
"reflect"
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
)
// FrameHeaderMatcher 帧头匹配器

@ -3,11 +3,11 @@ package matcher
import (
"testing"
"github.com/noahlann/nnet/internal/codec"
"github.com/noahlann/nnet/internal/request"
"github.com/noahlann/nnet/internal/response"
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
"git.noahlan.cn/noahlan/nnet/v2/internal/codec"
"git.noahlan.cn/noahlan/nnet/v2/internal/request"
"git.noahlan.cn/noahlan/nnet/v2/internal/response"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
"github.com/stretchr/testify/assert"
)

@ -3,11 +3,11 @@ package matcher
import (
"testing"
"github.com/noahlann/nnet/internal/codec"
"github.com/noahlann/nnet/internal/request"
"github.com/noahlann/nnet/internal/response"
ctxpkg "github.com/noahlann/nnet/pkg/context"
routerpkg "github.com/noahlann/nnet/pkg/router"
"git.noahlan.cn/noahlan/nnet/v2/internal/codec"
"git.noahlan.cn/noahlan/nnet/v2/internal/request"
"git.noahlan.cn/noahlan/nnet/v2/internal/response"
ctxpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/context"
routerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/router"
"github.com/stretchr/testify/assert"
)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save