Compare commits
No commits in common. "e9a6d5b42a359362da971157826b0dbfba720c58" and "4a80a26371912418f386ffaca89e033925a21e1e" have entirely different histories.
e9a6d5b42a
...
4a80a26371
19
CHANGELOG.md
19
CHANGELOG.md
@ -1,24 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## v1.5.3 (2026-06-21)
|
|
||||||
- **测试修复**:
|
|
||||||
- 在测试中通过 `SERVICE_IP=127.0.0.1` 环境变量绕过 VPN 虚拟网卡导致的连接超时。
|
|
||||||
- 修正测试中的代理匹配路径断言,确保兼容查询参数传递。
|
|
||||||
- **依赖对齐**:
|
|
||||||
- 升级依赖 `jsmod` 至 `v1.5.3`, `timer` (`v1.5.0`), `cast` 至 `v1.5.3`, `rand` 至 `v1.5.3`, `encoding` 至 `v1.5.4`, `shell` 至 `v1.5.3`, `safe` 至 `v1.5.2`, `id` 至 `v1.5.4`, `crypto` 至 `v1.5.3`, `file` 至 `v1.5.5`, `config` 至 `v1.5.3`, `watch` 至 `v1.5.2`, `log` 至 `v1.5.8`, `http` 至 `v1.5.3`, `redis` 至 `v1.5.6`, `starter` 至 `v1.5.5`, `discover` 至 `v1.5.3`, `service` 至 `v1.5.15`。
|
|
||||||
|
|
||||||
## v1.5.2 (2026-06-12)
|
|
||||||
- **依赖对齐**:
|
|
||||||
- 对齐全局服务和基础设施到最新版本。
|
|
||||||
|
|
||||||
## v1.5.1 (2026-06-08)
|
|
||||||
- **优化**:
|
|
||||||
- 对齐 starter v1.5.3 与 service v1.5.12。
|
|
||||||
|
|
||||||
## v1.5.0 (2026-06-03)
|
|
||||||
- **依赖对齐**:
|
|
||||||
- 对齐 Tag v1.5.0。
|
|
||||||
|
|
||||||
## [v2.0.0] - 2026-05-12
|
## [v2.0.0] - 2026-05-12
|
||||||
|
|
||||||
### ✨ 全新重构架构 (Architecture Rewrite)
|
### ✨ 全新重构架构 (Architecture Rewrite)
|
||||||
|
|||||||
15
app.go
15
app.go
@ -22,6 +22,7 @@ var GatewayConf = Config{
|
|||||||
|
|
||||||
// GatewayApp 定义网关应用,融合了 WebServer 的原生能力
|
// GatewayApp 定义网关应用,融合了 WebServer 的原生能力
|
||||||
type GatewayApp struct {
|
type GatewayApp struct {
|
||||||
|
*service.WebServer
|
||||||
rd *redis.Redis
|
rd *redis.Redis
|
||||||
pubsubChannel string
|
pubsubChannel string
|
||||||
cancelPubSub context.CancelFunc
|
cancelPubSub context.CancelFunc
|
||||||
@ -29,7 +30,9 @@ type GatewayApp struct {
|
|||||||
|
|
||||||
// NewGatewayApp 创建 Gateway
|
// NewGatewayApp 创建 Gateway
|
||||||
func NewGatewayApp() *GatewayApp {
|
func NewGatewayApp() *GatewayApp {
|
||||||
return &GatewayApp{}
|
return &GatewayApp{
|
||||||
|
WebServer: service.NewWebServer(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start 启动网关服务 (实现 starter.Service)
|
// Start 启动网关服务 (实现 starter.Service)
|
||||||
@ -59,8 +62,7 @@ func (g *GatewayApp) Start(ctx context.Context, logger *log.Logger) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 启动底层的 WebServer,处理所有实际的 HTTP 连接和发现注册
|
// 启动底层的 WebServer,处理所有实际的 HTTP 连接和发现注册
|
||||||
service.Start()
|
return g.WebServer.Start(ctx, logger)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop 停止网关服务 (实现 starter.Service)
|
// Stop 停止网关服务 (实现 starter.Service)
|
||||||
@ -72,14 +74,13 @@ func (g *GatewayApp) Stop(ctx context.Context) error {
|
|||||||
g.rd.Unsubscribe(g.pubsubChannel)
|
g.rd.Unsubscribe(g.pubsubChannel)
|
||||||
}
|
}
|
||||||
// 停止底层的 WebServer
|
// 停止底层的 WebServer
|
||||||
// 注意:全局 service.Stop 目前在框架中可能由 starter 统一管理,或者手动调用 service.DefaultServer.Stop(ctx)
|
return g.WebServer.Stop(ctx)
|
||||||
return service.DefaultServer.Stop(ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload 重载网关配置 (实现 starter.Reloader)
|
// Reload 重载网关配置 (实现 starter.Reloader)
|
||||||
func (g *GatewayApp) Reload() error {
|
func (g *GatewayApp) Reload() error {
|
||||||
// 1. 触发底层 WebServer 的重载 (会重新加载本地 yaml 配置文件中的固定路由策略,并触发 OnReload 钩子)
|
// 1. 触发底层 WebServer 的重载 (会重新加载本地 yaml 配置文件中的固定路由策略,并触发 OnReload 钩子)
|
||||||
err := service.DefaultServer.Reload()
|
err := g.WebServer.Reload()
|
||||||
|
|
||||||
// 2. 重新全量拉取 Redis 中的动态配置
|
// 2. 重新全量拉取 Redis 中的动态配置
|
||||||
logger := log.DefaultLogger
|
logger := log.DefaultLogger
|
||||||
@ -91,7 +92,7 @@ func (g *GatewayApp) Reload() error {
|
|||||||
|
|
||||||
// Status 返回网关运行状态
|
// Status 返回网关运行状态
|
||||||
func (g *GatewayApp) Status() (string, error) {
|
func (g *GatewayApp) Status() (string, error) {
|
||||||
addr, err := service.DefaultServer.Status()
|
addr, err := g.WebServer.Status()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|||||||
67
app_test.go
67
app_test.go
@ -1,21 +1,21 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"apigo.cc/go/log"
|
"apigo.cc/go/log"
|
||||||
"apigo.cc/go/redis"
|
"apigo.cc/go/redis"
|
||||||
"apigo.cc/go/service"
|
"apigo.cc/go/service"
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
gohttp "net/http"
|
gohttp "net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGateway(t *testing.T) {
|
func TestGateway(t *testing.T) {
|
||||||
t.Setenv("SERVICE_IP", "127.0.0.1")
|
|
||||||
// 1. 设置服务发现和 Redis 依赖
|
// 1. 设置服务发现和 Redis 依赖
|
||||||
registry := "127.0.0.1:6379"
|
registry := "127.0.0.1:6379"
|
||||||
rd := redis.GetRedis(registry, log.DefaultLogger)
|
rd := redis.GetRedis(registry, log.DefaultLogger)
|
||||||
@ -27,27 +27,23 @@ func TestGateway(t *testing.T) {
|
|||||||
// 清理测试数据
|
// 清理测试数据
|
||||||
rd.Do("DEL", "gateway:host:gw.test", "gateway:hosts")
|
rd.Do("DEL", "gateway:host:gw.test", "gateway:hosts")
|
||||||
|
|
||||||
// 2. 启动一个独立的后端测试服务 test-backend (不使用全局 DefaultServer)
|
// 2. 启动一个后端测试服务 test-backend
|
||||||
backend := service.NewWebServer()
|
service.Config.App = "test-backend"
|
||||||
backend.Config.App = "test-backend"
|
service.Config.Listen = ":0"
|
||||||
backend.Config.Listen = ":0"
|
service.Config.Register = registry
|
||||||
backend.Config.Register = registry
|
|
||||||
|
|
||||||
backend.Host("*").GET("/hello", func(req *service.Request) string {
|
service.Host("*").GET("/hello", func(req *service.Request) string {
|
||||||
return "hello from backend, path: " + req.RequestURI
|
return "hello from backend, path: " + req.RequestURI
|
||||||
})
|
})
|
||||||
backend.Host("*").GET("/hello/world", func(req *service.Request) string {
|
service.Host("*").GET("/hello/world", func(req *service.Request) string {
|
||||||
return "hello from backend, path: " + req.RequestURI
|
return "hello from backend, path: " + req.RequestURI
|
||||||
})
|
})
|
||||||
|
|
||||||
backendCtx, backendCancel := context.WithCancel(context.Background())
|
asBackend := service.AsyncStart()
|
||||||
defer backendCancel()
|
defer asBackend.Stop()
|
||||||
go backend.Start(backendCtx, log.DefaultLogger)
|
time.Sleep(200 * time.Millisecond) // 等待后端启动和注册
|
||||||
defer backend.Stop(backendCtx)
|
|
||||||
|
|
||||||
time.Sleep(500 * time.Millisecond) // 等待后端启动和注册
|
// 3. 配置 Gateway
|
||||||
|
|
||||||
// 3. 配置 Gateway (使用全局 service)
|
|
||||||
GatewayConf.Redis = registry
|
GatewayConf.Redis = registry
|
||||||
GatewayConf.Prefix = "gateway"
|
GatewayConf.Prefix = "gateway"
|
||||||
|
|
||||||
@ -81,31 +77,29 @@ func TestGateway(t *testing.T) {
|
|||||||
// 4. 启动 Gateway 应用
|
// 4. 启动 Gateway 应用
|
||||||
app := NewGatewayApp()
|
app := NewGatewayApp()
|
||||||
|
|
||||||
// 设置独立的端口给 Gateway 的 WebServer
|
// 设置独立的端口给 Gateway 的 WebServer 避免与 backend 冲突
|
||||||
service.Config.App = "gateway"
|
service.Config.App = "gateway"
|
||||||
service.Config.Listen = ":0"
|
service.Config.Listen = ":0"
|
||||||
|
// 重置发现,确保网关独立
|
||||||
|
service.SetDiscovererForTest(nil)
|
||||||
|
// 配置网关可以通过 discover 找到 test-backend (网关也需要开启 discover)
|
||||||
service.Config.Register = registry
|
service.Config.Register = registry
|
||||||
service.Config.Calls = map[string]service.CallConfig{
|
service.Config.Calls = map[string]service.CallConfig{
|
||||||
"test-backend": {Timeout: 1000},
|
"test-backend": {Timeout: 1000},
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx := context.Background()
|
||||||
defer cancel()
|
err := app.Start(ctx, log.DefaultLogger)
|
||||||
|
if err != nil {
|
||||||
// 这里假设 GatewayApp.Start 内部会调用 service.Start(),
|
t.Fatalf("Failed to start gateway: %v", err)
|
||||||
// 而 service.Start() 在新版本中如果是阻塞的,我们需要在 goroutine 中运行
|
}
|
||||||
go app.Start(ctx, log.DefaultLogger)
|
|
||||||
defer app.Stop(ctx)
|
defer app.Stop(ctx)
|
||||||
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
|
||||||
gwAddr := service.DefaultServer.Addr
|
_, gwPort, _ := net.SplitHostPort(app.Addr)
|
||||||
if gwAddr == "" {
|
|
||||||
t.Fatalf("Gateway address is empty")
|
|
||||||
}
|
|
||||||
_, gwPort, _ := net.SplitHostPort(gwAddr)
|
|
||||||
|
|
||||||
client := &gohttp.Client{Timeout: 5 * time.Second}
|
client := &gohttp.Client{Timeout: 2 * time.Second}
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// 测试 1: 直接代理匹配 (Discover)
|
// 测试 1: 直接代理匹配 (Discover)
|
||||||
@ -135,8 +129,8 @@ func TestGateway(t *testing.T) {
|
|||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
body = string(b)
|
body = string(b)
|
||||||
}
|
}
|
||||||
if err != nil || body != "hello from backend, path: /hello?a=1" {
|
if err != nil || !strings.Contains(body, "hello from backend, path: /hello?a=1") {
|
||||||
t.Fatalf("Proxy /api/ failed, got: %s", body)
|
t.Fatalf("Proxy regexp failed, got: %s", body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
@ -151,8 +145,8 @@ func TestGateway(t *testing.T) {
|
|||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
body = string(b)
|
body = string(b)
|
||||||
}
|
}
|
||||||
if err != nil || body != "hello from backend, path: /hello/world?x=2" {
|
if err != nil || !strings.Contains(body, "hello from backend, path: /hello/world?x=2") {
|
||||||
t.Fatalf("Proxy /v2/* failed, got: %s", body)
|
t.Fatalf("Proxy wildcard failed, got: %s", body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
@ -225,6 +219,7 @@ func TestGateway(t *testing.T) {
|
|||||||
t.Fatalf("Request failed: %v", err)
|
t.Fatalf("Request failed: %v", err)
|
||||||
}
|
}
|
||||||
if res.StatusCode != 404 {
|
if res.StatusCode != 404 {
|
||||||
t.Fatalf("Atomic update failed, old route still exists")
|
t.Fatalf("Old proxy rule should be deleted (404), got status: %v", res.StatusCode)
|
||||||
}
|
}
|
||||||
|
res.Body.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
34
go.mod
34
go.mod
@ -3,28 +3,28 @@ module apigo.cc/go/gateway
|
|||||||
go 1.25.0
|
go 1.25.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
apigo.cc/go/cast v1.5.3
|
apigo.cc/go/cast v1.5.0
|
||||||
apigo.cc/go/config v1.5.3
|
apigo.cc/go/config v1.5.1
|
||||||
apigo.cc/go/log v1.5.8
|
apigo.cc/go/log v1.5.5
|
||||||
apigo.cc/go/redis v1.5.6
|
apigo.cc/go/redis v1.5.0
|
||||||
apigo.cc/go/service v1.5.15
|
apigo.cc/go/service v1.5.12
|
||||||
apigo.cc/go/starter v1.5.5
|
apigo.cc/go/starter v1.5.3
|
||||||
)
|
)
|
||||||
|
|
||||||
require apigo.cc/go/jsmod v1.5.3 // indirect
|
require apigo.cc/go/jsmod v1.5.0 // indirect
|
||||||
|
|
||||||
require (
|
require (
|
||||||
apigo.cc/go/crypto v1.5.3 // indirect
|
apigo.cc/go/crypto v1.5.0 // indirect
|
||||||
apigo.cc/go/discover v1.5.3 // indirect
|
apigo.cc/go/discover v1.5.0 // indirect
|
||||||
apigo.cc/go/encoding v1.5.4 // indirect
|
apigo.cc/go/encoding v1.5.0 // indirect
|
||||||
apigo.cc/go/file v1.5.5 // indirect
|
apigo.cc/go/file v1.5.0 // indirect
|
||||||
apigo.cc/go/http v1.5.3 // indirect
|
apigo.cc/go/http v1.5.0 // indirect
|
||||||
apigo.cc/go/id v1.5.4 // indirect
|
apigo.cc/go/id v1.5.0 // indirect
|
||||||
apigo.cc/go/rand v1.5.3 // indirect
|
apigo.cc/go/rand v1.5.0 // indirect
|
||||||
apigo.cc/go/safe v1.5.2 // indirect
|
apigo.cc/go/safe v1.5.0 // indirect
|
||||||
apigo.cc/go/shell v1.5.3 // indirect
|
apigo.cc/go/shell v1.5.0 // indirect
|
||||||
apigo.cc/go/timer v1.5.0 // indirect
|
apigo.cc/go/timer v1.5.0 // indirect
|
||||||
apigo.cc/go/watch v1.5.2 // indirect
|
apigo.cc/go/watch v1.5.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.10.1 // indirect
|
github.com/fsnotify/fsnotify v1.10.1 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
||||||
|
|||||||
68
go.sum
68
go.sum
@ -1,39 +1,39 @@
|
|||||||
apigo.cc/go/cast v1.5.3 h1:jk6VX0rGFhjKtfPhsaV6IKYpiGmORRk9qPTtuNS53tw=
|
apigo.cc/go/cast v1.5.0 h1:UBGJtFQ8eJPMQXs37cUgqd7YQo1zI9opuSDBDmn2/pE=
|
||||||
apigo.cc/go/cast v1.5.3/go.mod h1:GMjjrYn93tWat1U409G7h1jR3ejfLLI7r0efBo9Sbd4=
|
apigo.cc/go/cast v1.5.0/go.mod h1:z2GW5p5WCZGEqVVIJUdhl232vRbLf2Qu4EDlEakX/D8=
|
||||||
apigo.cc/go/config v1.5.3 h1:peq1FM2xO+vzPHJf8Dwg3DXm8PtFQMfTFKQj6fpoG7A=
|
apigo.cc/go/config v1.5.1 h1:rpj7oCzlsDV3f2/YK3Pb+CHbfr2DL5Vyyv6VNkobJP4=
|
||||||
apigo.cc/go/config v1.5.3/go.mod h1:ZiOAjWa1mQIzszaJZN+kO6YU4GXreng+NxkcK/TAkqQ=
|
apigo.cc/go/config v1.5.1/go.mod h1:jdMiDLPa9gzB8/FFZvm9jOopUqdxb7XSX+0OeWcZZUM=
|
||||||
apigo.cc/go/crypto v1.5.3 h1:2JUHC2cgR2zrnn36EzwkUAdxmmTXAA/8yTNo+2X1mPE=
|
apigo.cc/go/crypto v1.5.0 h1:Nxz7a6VKCdvaF258IU0NkjQyureOLxfR308Sy2iftUI=
|
||||||
apigo.cc/go/crypto v1.5.3/go.mod h1:PheYKHEXmoEFI1AK5PpY1borQWcRlkkSaWncT3cWbhE=
|
apigo.cc/go/crypto v1.5.0/go.mod h1:F9M6nXv+5328r1ZwbTvI6fcr8VdgqHVzALOcsdv6ntE=
|
||||||
apigo.cc/go/discover v1.5.3 h1:WW1A7qReYytebETDb5MhVRPmT10KReGM4QbPTfqS/iw=
|
apigo.cc/go/discover v1.5.0 h1:RGHulidyAHCZdGfpFytFUl3ur4aNVMXKlfJbAMCvgpo=
|
||||||
apigo.cc/go/discover v1.5.3/go.mod h1:rylFiGvfNro090rGtlc9K31KATn6WZbnn1Fk2AbQZEU=
|
apigo.cc/go/discover v1.5.0/go.mod h1:nA5DQlmhzjGBZVqpEbZRNDIKNU+Sr9trxbKAgDxjZ+I=
|
||||||
apigo.cc/go/encoding v1.5.4 h1:Fk8TrveZATyy8SHukC4ZiqdTSp+QIfsRHtt55xmMK7w=
|
apigo.cc/go/encoding v1.5.0 h1:EJNdRVDOMoI2DAvZwQNQTbYuqB/6zsEzvg7lS5pQI+I=
|
||||||
apigo.cc/go/encoding v1.5.4/go.mod h1:dShEsZ3gKqBINz7TSOYf4e7/fBCqCY9VzlenoGUQUFM=
|
apigo.cc/go/encoding v1.5.0/go.mod h1:8++NfZj3hWig0qh2g7GQRw/4LpSvCYMWUZ+8J+x58cA=
|
||||||
apigo.cc/go/file v1.5.5 h1:/+HmDumLu6Qk2KuQL63M9lpgzHTDL+QJ8dStOl7e9gs=
|
apigo.cc/go/file v1.5.0 h1:Fh1NSDBqaxjuXYJ71yPHPXVJ8BFEv/AGS3l+jkLi5uw=
|
||||||
apigo.cc/go/file v1.5.5/go.mod h1:xRVNhctvqOKeBemmcRW/BQfgkc3B+vT/UZVdSc7duUo=
|
apigo.cc/go/file v1.5.0/go.mod h1:4YhOGgBINTpmmmgws3H8LAyXQQBGzBp44hYUoCS+kr0=
|
||||||
apigo.cc/go/http v1.5.3 h1:nvJh9bqPPcPRv6p8WEw7bJAd0UC+r2zvQA8/QioVLTQ=
|
apigo.cc/go/http v1.5.0 h1:GGIu0dhMjTiYygxH9NWOzz6AY+WZjfyTL1qZ8G9vI1U=
|
||||||
apigo.cc/go/http v1.5.3/go.mod h1:cFrPK61y9f1PrsNSJscZT/QVOgkT15o9OP7O8cuMb8Q=
|
apigo.cc/go/http v1.5.0/go.mod h1:CIIH7HS6wdicLpSgkEVozdDcHlM9W9ygmmzJvzhAKWg=
|
||||||
apigo.cc/go/id v1.5.4 h1:D1Zx9gEZhOgdTgZ4SdmPImhpc9xGiOA33Y+j2MkstzQ=
|
apigo.cc/go/id v1.5.0 h1:MjNWPhBhDsoXaLeJDv/0wfJmVMU9EvOs8pWYfsTQ6e8=
|
||||||
apigo.cc/go/id v1.5.4/go.mod h1:hCTQq+KC1ALWe1FpPERf+W4B6FSulg9FAgOUJDDySiY=
|
apigo.cc/go/id v1.5.0/go.mod h1:qhu4a1/KLc/XcBpcsRu+mXZt7U7Wvd9zMcPs4VspuPA=
|
||||||
apigo.cc/go/jsmod v1.5.3 h1:S3W317bH0QV2NMeRO1E0v6ySIBOfMWYv/NuQJbvqKWU=
|
apigo.cc/go/jsmod v1.5.0 h1:JgQtJNiJWy1NOP9AzE8NX5VXJkpO/x3GqLsCCSny5Ec=
|
||||||
apigo.cc/go/jsmod v1.5.3/go.mod h1:bmyeZtOAP/j5am+YRnaiM89smysK24K7ebk0koFtsSw=
|
apigo.cc/go/jsmod v1.5.0/go.mod h1:bmyeZtOAP/j5am+YRnaiM89smysK24K7ebk0koFtsSw=
|
||||||
apigo.cc/go/log v1.5.8 h1:/IYtGPWhRjT3OayylDIphkWZIQbpLjqVeSnFEiD3Dy0=
|
apigo.cc/go/log v1.5.5 h1:AFU7d7AQxkpgDHl7SnlEwd6yzGSFAlnrrjbrNDQnQHI=
|
||||||
apigo.cc/go/log v1.5.8/go.mod h1:HfFPANMYxJx197SSTXB21Pgxcz/gGqPP8nlSErgd5WE=
|
apigo.cc/go/log v1.5.5/go.mod h1:Djy+I5aLhGB/EjwRz4KHqkVEz584IAD55FAFiIfInuo=
|
||||||
apigo.cc/go/rand v1.5.3 h1:O4bPIwyaOWEBCr0nL9A4G4qG48AqiGTCzfPeckm3Ius=
|
apigo.cc/go/rand v1.5.0 h1:1o8hh8fhdBuk1/h02IvugvamuT3dkWbVJrqEJVQKB2E=
|
||||||
apigo.cc/go/rand v1.5.3/go.mod h1:q1BTFkY/cXE229dDD5Q22lF7T0DoKPV6xAu+6bCrDH4=
|
apigo.cc/go/rand v1.5.0/go.mod h1:Lh98S2dm9UY0X+M+kNQQEKyXHG5pcCKSFPyXN0QCGdk=
|
||||||
apigo.cc/go/redis v1.5.6 h1:Lzo8M2binfqdQdVVp31Z/Max4qT8D82QdZjLlLQsrIY=
|
apigo.cc/go/redis v1.5.0 h1:VXNDqzKj87BchF7ubDEH+T6lp8NrjeK0izU4ooo7u1A=
|
||||||
apigo.cc/go/redis v1.5.6/go.mod h1:HmqSh2Ll7/b2zFXDi2Ap13YOuMCVniuZNbwtxkbIYII=
|
apigo.cc/go/redis v1.5.0/go.mod h1:/olsrHndkUNezUX1KbBBt8b4Got7SX7E8EJzcb1PknM=
|
||||||
apigo.cc/go/safe v1.5.2 h1:EnuEOW/SGwf/5A0nw9LnqfKJE071+TIc6ez8HI9R9Lg=
|
apigo.cc/go/safe v1.5.0 h1:W1NblmcU8cex1f9Y5z8mNLUJOzZTE1s6fszb3FbhGnk=
|
||||||
apigo.cc/go/safe v1.5.2/go.mod h1:2GqCCLLGex4OAhdET3iBWm1R+LIYtmTrvHP8W0iESSw=
|
apigo.cc/go/safe v1.5.0/go.mod h1:OfQ5d6COePSGEuPvMeOk6KagX2sezw7nvKh7exj9SeM=
|
||||||
apigo.cc/go/service v1.5.15 h1:MmmLKJSOjXtZHlEWoCNsuIguPLpe36/cWugqvHPRiSw=
|
apigo.cc/go/service v1.5.11 h1:KU0Jj5Uo3hwdH1b6Wn9Vru61XvEqZaxPHzzZgYkThAc=
|
||||||
apigo.cc/go/service v1.5.15/go.mod h1:HUyz+w77n5kBNB8uJVJo10nxCFewLDmgRuVIy/benHc=
|
apigo.cc/go/service v1.5.11/go.mod h1:MH3SjHtOLlKN/fTpA8NOjJXrB+BCdQRBnO9JNj9fir8=
|
||||||
apigo.cc/go/shell v1.5.3 h1:pI+u12sy6upoygq+1XXqUlvUboBfH4Q52jRpoJFv56A=
|
apigo.cc/go/shell v1.5.0 h1:WLDMMqUU0INeaBDmQsTPr0h/NfB2RknAtiJ5NL467+Q=
|
||||||
apigo.cc/go/shell v1.5.3/go.mod h1:FdZWUrcXHGJXo725oSyHqAeFoX0E9yY3PDhrz9hujgY=
|
apigo.cc/go/shell v1.5.0/go.mod h1:rYHA77d5hEsQHcJrbAWf1pHy0sxayeJ0gU55LA/JWQk=
|
||||||
apigo.cc/go/starter v1.5.5 h1:4ST02o4qP8IIekxtd9Jhx5RHTrSGXtVQUguSIXV0iWc=
|
apigo.cc/go/starter v1.5.2 h1:bSNByK9uU+4+Rw8a83TNhQnUUjCPfJj7DVUpEuCD2wg=
|
||||||
apigo.cc/go/starter v1.5.5/go.mod h1:WAGhdtmZdpP1Jn/z0pCqHwpTbqqaFhm5OqH7QVtcanY=
|
apigo.cc/go/starter v1.5.2/go.mod h1:iu3AnpqpriJBiTJC0MJyeFxGmmFto+SU+S2d96XhRco=
|
||||||
apigo.cc/go/timer v1.5.0 h1:iPo/IQn+iuhBRI1/MR1txwZnamef/RBBfOiIlBiqkgk=
|
apigo.cc/go/timer v1.5.0 h1:iPo/IQn+iuhBRI1/MR1txwZnamef/RBBfOiIlBiqkgk=
|
||||||
apigo.cc/go/timer v1.5.0/go.mod h1:kOnqTTX+zA4AH7SfC+LpUm4ZvS+DVyWWMqul/V5QWJs=
|
apigo.cc/go/timer v1.5.0/go.mod h1:kOnqTTX+zA4AH7SfC+LpUm4ZvS+DVyWWMqul/V5QWJs=
|
||||||
apigo.cc/go/watch v1.5.2 h1:zG56PD8Vml5gVJeo2yNuX9s6stOaIJRYqqKGqXK+xTU=
|
apigo.cc/go/watch v1.5.0 h1:hdnnr7DkiY/HyQGwOIl3A4wV2pfaS7h61fODq06XTu8=
|
||||||
apigo.cc/go/watch v1.5.2/go.mod h1:MW1XnI0MVyUZpRy590no1vrDT+U4y20L0UZW9/LgU+k=
|
apigo.cc/go/watch v1.5.0/go.mod h1:/Hbhoxiq295FnIqPzieUJ7EGtibWyLQrvV4Cj/vjNXE=
|
||||||
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||||
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user