|
|
//go:build server || (!server && !client)
|
|
|
|
|
|
package main
|
|
|
|
|
|
import (
|
|
|
"log"
|
|
|
"os"
|
|
|
"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"
|
|
|
)
|
|
|
|
|
|
// This example demonstrates interceptor chain usage.
|
|
|
// Interceptors can validate, transform, or filter data before it reaches handlers.
|
|
|
func main() {
|
|
|
cfg := &nnet.Config{
|
|
|
Addr: "tcp://:8084",
|
|
|
Codec: &nnet.CodecConfig{
|
|
|
DefaultCodec: "json",
|
|
|
EnableProtocolEncode: false,
|
|
|
},
|
|
|
}
|
|
|
|
|
|
srv, err := nnet.NewServer(cfg)
|
|
|
if err != nil {
|
|
|
log.Fatal("create server:", err)
|
|
|
}
|
|
|
|
|
|
// 创建拦截器链
|
|
|
// 拦截器1:最小长度验证(至少5字节)
|
|
|
minLenInterceptor := builtin.MinLengthInterceptor(5)
|
|
|
|
|
|
// 拦截器2:最大长度验证(最多100字节)
|
|
|
maxLenInterceptor := builtin.MaxLengthInterceptor(100)
|
|
|
|
|
|
// 拦截器3:自定义验证拦截器(验证数据不为空且不为"forbidden")
|
|
|
customInterceptor := interceptor.HandlerFunc(func(data []byte, ctx nnet.Context, next interceptor.Chain) ([]byte, bool, error) {
|
|
|
if len(data) == 0 {
|
|
|
return nil, false, interceptor.New("data cannot be empty")
|
|
|
}
|
|
|
|
|
|
if string(data) == "forbidden" {
|
|
|
return nil, false, interceptor.New("forbidden data")
|
|
|
}
|
|
|
|
|
|
// 记录到上下文
|
|
|
ctx.Set("intercepted", true)
|
|
|
ctx.Set("data_length", len(data))
|
|
|
|
|
|
return next.Next(data, ctx)
|
|
|
})
|
|
|
|
|
|
// 使用自定义匹配器,匹配所有请求并在handler中应用拦截器
|
|
|
// 路由1:验证端点(使用拦截器链)
|
|
|
srv.Router().RegisterCustom(
|
|
|
func(input routerpkg.MatchInput, ctx nnet.Context) bool {
|
|
|
data := input.Raw
|
|
|
// 匹配以"validate"开头的数据
|
|
|
return len(data) >= 8 && string(data[:8]) == "validate"
|
|
|
},
|
|
|
func(ctx nnet.Context) error {
|
|
|
rawData := ctx.Request().Raw()
|
|
|
// 提取实际数据(跳过"validate"命令)
|
|
|
var actualData []byte
|
|
|
if len(rawData) > 8 {
|
|
|
actualData = rawData[8:]
|
|
|
// 跳过空格或换行
|
|
|
for len(actualData) > 0 && (actualData[0] == ' ' || actualData[0] == '\n') {
|
|
|
actualData = actualData[1:]
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 如果没有数据,使用默认测试数据
|
|
|
if len(actualData) == 0 {
|
|
|
actualData = []byte("test data for validation")
|
|
|
}
|
|
|
|
|
|
// 执行拦截器链
|
|
|
interceptors := []interceptor.Interceptor{
|
|
|
minLenInterceptor,
|
|
|
maxLenInterceptor,
|
|
|
customInterceptor,
|
|
|
}
|
|
|
|
|
|
data, continueProcessing, err := internalinterceptor.Execute(actualData, ctx, interceptors...)
|
|
|
if err != nil {
|
|
|
return ctx.Response().Write(map[string]any{
|
|
|
"error": err.Error(),
|
|
|
"valid": false,
|
|
|
"message": "validation failed",
|
|
|
})
|
|
|
}
|
|
|
|
|
|
if !continueProcessing {
|
|
|
return ctx.Response().Write(map[string]any{
|
|
|
"error": "processing stopped",
|
|
|
"valid": false,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 获取拦截器设置的值
|
|
|
intercepted := ctx.GetBool("intercepted")
|
|
|
dataLength := ctx.GetInt("data_length")
|
|
|
|
|
|
return ctx.Response().Write(map[string]any{
|
|
|
"valid": true,
|
|
|
"data": string(data),
|
|
|
"intercepted": intercepted,
|
|
|
"data_length": dataLength,
|
|
|
"message": "validation passed",
|
|
|
})
|
|
|
},
|
|
|
)
|
|
|
|
|
|
// 路由2:简单的echo
|
|
|
srv.Router().RegisterString("echo", func(ctx nnet.Context) error {
|
|
|
data := ctx.Request().Raw()
|
|
|
return ctx.Response().Write(map[string]any{
|
|
|
"echo": string(data),
|
|
|
})
|
|
|
})
|
|
|
|
|
|
// 路由3:测试端点(使用最小长度拦截器)
|
|
|
srv.Router().RegisterString("test", func(ctx nnet.Context) error {
|
|
|
rawData := ctx.Request().Raw()
|
|
|
|
|
|
// 只使用最小长度拦截器
|
|
|
data, continueProcessing, err := internalinterceptor.Execute(rawData, ctx, minLenInterceptor)
|
|
|
if err != nil {
|
|
|
return ctx.Response().Write(map[string]any{
|
|
|
"error": err.Error(),
|
|
|
"valid": false,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
if !continueProcessing {
|
|
|
return ctx.Response().Write(map[string]any{
|
|
|
"error": "processing stopped",
|
|
|
"valid": false,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
return ctx.Response().Write(map[string]any{
|
|
|
"valid": true,
|
|
|
"data": string(data),
|
|
|
})
|
|
|
})
|
|
|
|
|
|
log.Println("interceptor_server listening on :8084")
|
|
|
log.Println("Interceptors:")
|
|
|
log.Println(" - MinLengthInterceptor (min: 5 bytes)")
|
|
|
log.Println(" - MaxLengthInterceptor (max: 100 bytes)")
|
|
|
log.Println(" - CustomInterceptor (rejects 'forbidden')")
|
|
|
if err := srv.Start(); err != nil {
|
|
|
log.Fatal("start server:", err)
|
|
|
}
|
|
|
defer srv.Stop()
|
|
|
|
|
|
quit := make(chan os.Signal, 1)
|
|
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
|
<-quit
|
|
|
}
|