router op 1
This commit is contained in:
parent
f6c260a525
commit
9d326eaec1
|
@ -1,35 +1,27 @@
|
||||||
package routers
|
package routers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"hash/fnv"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
|
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
|
||||||
|
"github.com/VictoriaMetrics/fastcache"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Maximum number of URL parameters per route
|
// Maximum number of URL parameters per route
|
||||||
const maxParams = 20
|
const maxParams = 20
|
||||||
|
|
||||||
// LuaRouter is a filesystem-based HTTP router for Lua files
|
// Default cache sizes
|
||||||
type LuaRouter struct {
|
const (
|
||||||
routesDir string // Root directory containing route files
|
defaultBytecodeMaxBytes = 32 * 1024 * 1024 // 32MB for bytecode cache
|
||||||
routes map[string]*node // Method -> route tree
|
defaultRouteMaxBytes = 8 * 1024 * 1024 // 8MB for route match cache
|
||||||
failedRoutes map[string]*RouteError // Track failed routes
|
)
|
||||||
mu sync.RWMutex // Lock for concurrent access to routes
|
|
||||||
}
|
|
||||||
|
|
||||||
// node represents a node in the routing trie
|
|
||||||
type node struct {
|
|
||||||
handler string // Path to Lua file (empty if not an endpoint)
|
|
||||||
bytecode []byte // Pre-compiled Lua bytecode
|
|
||||||
paramName string // Parameter name (if this is a parameter node)
|
|
||||||
staticChild map[string]*node // Static children by segment name
|
|
||||||
paramChild *node // Parameter/wildcard child
|
|
||||||
err error // Compilation error if any
|
|
||||||
}
|
|
||||||
|
|
||||||
// Params holds URL parameters with fixed-size arrays to avoid allocations
|
// Params holds URL parameters with fixed-size arrays to avoid allocations
|
||||||
type Params struct {
|
type Params struct {
|
||||||
|
@ -48,6 +40,28 @@ func (p *Params) Get(name string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LuaRouter is a filesystem-based HTTP router for Lua files
|
||||||
|
type LuaRouter struct {
|
||||||
|
routesDir string // Root directory containing route files
|
||||||
|
routes map[string]*node // Method -> route tree
|
||||||
|
failedRoutes map[string]*RouteError // Track failed routes
|
||||||
|
mu sync.RWMutex // Lock for concurrent access to routes
|
||||||
|
|
||||||
|
// Cache for route matches and bytecode
|
||||||
|
routeCache *fastcache.Cache // Cache for route lookups
|
||||||
|
bytecodeCache *fastcache.Cache // Cache for compiled bytecode
|
||||||
|
}
|
||||||
|
|
||||||
|
// node represents a node in the routing trie
|
||||||
|
type node struct {
|
||||||
|
handler string // Path to Lua file (empty if not an endpoint)
|
||||||
|
paramName string // Parameter name (if this is a parameter node)
|
||||||
|
staticChild map[string]*node // Static children by segment name
|
||||||
|
paramChild *node // Parameter/wildcard child
|
||||||
|
err error // Compilation error if any
|
||||||
|
modTime time.Time // Last modification time
|
||||||
|
}
|
||||||
|
|
||||||
// NewLuaRouter creates a new LuaRouter instance
|
// NewLuaRouter creates a new LuaRouter instance
|
||||||
func NewLuaRouter(routesDir string) (*LuaRouter, error) {
|
func NewLuaRouter(routesDir string) (*LuaRouter, error) {
|
||||||
// Verify routes directory exists
|
// Verify routes directory exists
|
||||||
|
@ -63,6 +77,8 @@ func NewLuaRouter(routesDir string) (*LuaRouter, error) {
|
||||||
routesDir: routesDir,
|
routesDir: routesDir,
|
||||||
routes: make(map[string]*node),
|
routes: make(map[string]*node),
|
||||||
failedRoutes: make(map[string]*RouteError),
|
failedRoutes: make(map[string]*RouteError),
|
||||||
|
routeCache: fastcache.New(defaultRouteMaxBytes),
|
||||||
|
bytecodeCache: fastcache.New(defaultBytecodeMaxBytes),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize method trees
|
// Initialize method trees
|
||||||
|
@ -77,7 +93,6 @@ func NewLuaRouter(routesDir string) (*LuaRouter, error) {
|
||||||
err = r.buildRoutes()
|
err = r.buildRoutes()
|
||||||
|
|
||||||
// If some routes failed to compile, return the router with a warning error
|
// If some routes failed to compile, return the router with a warning error
|
||||||
// This allows the server to continue running with the routes that did compile
|
|
||||||
if len(r.failedRoutes) > 0 {
|
if len(r.failedRoutes) > 0 {
|
||||||
return r, ErrRoutesCompilationErrors
|
return r, ErrRoutesCompilationErrors
|
||||||
}
|
}
|
||||||
|
@ -127,13 +142,13 @@ func (r *LuaRouter) buildRoutes() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add route to tree - continue even if there are errors
|
// Add route to tree - continue even if there are errors
|
||||||
r.addRoute(root, urlPath, path)
|
r.addRoute(root, urlPath, path, info.ModTime())
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// addRoute adds a route to the routing tree and compiles the Lua file to bytecode
|
// addRoute adds a route to the routing tree
|
||||||
func (r *LuaRouter) addRoute(root *node, urlPath, handlerPath string) error {
|
func (r *LuaRouter) addRoute(root *node, urlPath, handlerPath string, modTime time.Time) error {
|
||||||
segments := strings.Split(strings.Trim(urlPath, "/"), "/")
|
segments := strings.Split(strings.Trim(urlPath, "/"), "/")
|
||||||
current := root
|
current := root
|
||||||
|
|
||||||
|
@ -159,11 +174,12 @@ func (r *LuaRouter) addRoute(root *node, urlPath, handlerPath string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set handler path
|
// Set handler path and mod time
|
||||||
current.handler = handlerPath
|
current.handler = handlerPath
|
||||||
|
current.modTime = modTime
|
||||||
|
|
||||||
// Compile Lua file to bytecode
|
// Compile Lua file to bytecode
|
||||||
if err := r.compileHandler(current, urlPath); err != nil {
|
if err := r.compileHandler(current); err != nil {
|
||||||
// Track the failure but don't fail the entire process
|
// Track the failure but don't fail the entire process
|
||||||
routeKey := getRouteKey(urlPath, handlerPath)
|
routeKey := getRouteKey(urlPath, handlerPath)
|
||||||
r.failedRoutes[routeKey] = &RouteError{
|
r.failedRoutes[routeKey] = &RouteError{
|
||||||
|
@ -181,6 +197,38 @@ func getRouteKey(path, handler string) string {
|
||||||
return path + ":" + handler
|
return path + ":" + handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hashString generates a hash for a string
|
||||||
|
func hashString(s string) uint64 {
|
||||||
|
h := fnv.New64a()
|
||||||
|
h.Write([]byte(s))
|
||||||
|
return h.Sum64()
|
||||||
|
}
|
||||||
|
|
||||||
|
// uint64ToBytes converts a uint64 to bytes for cache key
|
||||||
|
func uint64ToBytes(n uint64) []byte {
|
||||||
|
b := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(b, n)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// bytesToUint64 converts bytes to uint64
|
||||||
|
func bytesToUint64(b []byte) uint64 {
|
||||||
|
return binary.LittleEndian.Uint64(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCacheKey generates a cache key for a method and path
|
||||||
|
func getCacheKey(method, path string) []byte {
|
||||||
|
// Simple concatenation with separator to create a unique key
|
||||||
|
key := hashString(method + ":" + path)
|
||||||
|
return uint64ToBytes(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getBytecodeKey generates a cache key for a handler path
|
||||||
|
func getBytecodeKey(handlerPath string) []byte {
|
||||||
|
key := hashString(handlerPath)
|
||||||
|
return uint64ToBytes(key)
|
||||||
|
}
|
||||||
|
|
||||||
// Match finds a handler for the given method and path
|
// Match finds a handler for the given method and path
|
||||||
// Uses the pre-allocated params struct to avoid allocations
|
// Uses the pre-allocated params struct to avoid allocations
|
||||||
func (r *LuaRouter) Match(method, path string, params *Params) (*node, bool) {
|
func (r *LuaRouter) Match(method, path string, params *Params) (*node, bool) {
|
||||||
|
@ -244,7 +292,7 @@ func (r *LuaRouter) matchPath(current *node, segments []string, params *Params,
|
||||||
}
|
}
|
||||||
|
|
||||||
// compileHandler compiles a Lua file to bytecode
|
// compileHandler compiles a Lua file to bytecode
|
||||||
func (r *LuaRouter) compileHandler(n *node, _ string) error {
|
func (r *LuaRouter) compileHandler(n *node) error {
|
||||||
if n.handler == "" {
|
if n.handler == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -271,15 +319,71 @@ func (r *LuaRouter) compileHandler(n *node, _ string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store bytecode in the node
|
// Store bytecode in cache
|
||||||
n.bytecode = bytecode
|
bytecodeKey := getBytecodeKey(n.handler)
|
||||||
|
r.bytecodeCache.Set(bytecodeKey, bytecode)
|
||||||
|
|
||||||
n.err = nil // Clear any previous error
|
n.err = nil // Clear any previous error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBytecode returns the compiled bytecode for a matched route
|
// GetBytecode returns the compiled bytecode for a matched route
|
||||||
// If a route exists but failed to compile, returns nil bytecode with found=true
|
// Uses FastCache for both route matching and bytecode retrieval
|
||||||
func (r *LuaRouter) GetBytecode(method, path string, params *Params) ([]byte, string, bool) {
|
func (r *LuaRouter) GetBytecode(method, path string, params *Params) ([]byte, string, bool) {
|
||||||
|
// Check route cache first
|
||||||
|
routeCacheKey := getCacheKey(method, path)
|
||||||
|
routeCacheData := r.routeCache.Get(nil, routeCacheKey)
|
||||||
|
|
||||||
|
if len(routeCacheData) > 0 {
|
||||||
|
// Cache hit - first 8 bytes are bytecode hash, rest is handler path
|
||||||
|
handlerPath := string(routeCacheData[8:])
|
||||||
|
bytecodeKey := routeCacheData[:8]
|
||||||
|
|
||||||
|
// Get bytecode from cache
|
||||||
|
bytecode := r.bytecodeCache.Get(nil, bytecodeKey)
|
||||||
|
if len(bytecode) > 0 {
|
||||||
|
return bytecode, handlerPath, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytecode not found, check if file was modified
|
||||||
|
n, exists := r.nodeForHandler(handlerPath)
|
||||||
|
if !exists {
|
||||||
|
// Handler no longer exists
|
||||||
|
r.routeCache.Del(routeCacheKey)
|
||||||
|
return nil, "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if file was modified
|
||||||
|
fileInfo, err := os.Stat(handlerPath)
|
||||||
|
if err != nil || fileInfo.ModTime().After(n.modTime) {
|
||||||
|
// Recompile if file was modified
|
||||||
|
if err := r.compileHandler(n); err != nil {
|
||||||
|
return nil, handlerPath, true // Return with error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update cache
|
||||||
|
newBytecodeKey := getBytecodeKey(handlerPath)
|
||||||
|
bytecode = r.bytecodeCache.Get(nil, newBytecodeKey)
|
||||||
|
|
||||||
|
// Update route cache
|
||||||
|
newCacheData := make([]byte, 8+len(handlerPath))
|
||||||
|
copy(newCacheData[:8], newBytecodeKey)
|
||||||
|
copy(newCacheData[8:], handlerPath)
|
||||||
|
r.routeCache.Set(routeCacheKey, newCacheData)
|
||||||
|
|
||||||
|
return bytecode, handlerPath, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strange case - bytecode not in cache but file not modified
|
||||||
|
// Recompile
|
||||||
|
if err := r.compileHandler(n); err != nil {
|
||||||
|
return nil, handlerPath, true
|
||||||
|
}
|
||||||
|
bytecode = r.bytecodeCache.Get(nil, bytecodeKey)
|
||||||
|
return bytecode, handlerPath, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache miss - do normal routing
|
||||||
node, found := r.Match(method, path, params)
|
node, found := r.Match(method, path, params)
|
||||||
if !found {
|
if !found {
|
||||||
return nil, "", false
|
return nil, "", false
|
||||||
|
@ -290,7 +394,66 @@ func (r *LuaRouter) GetBytecode(method, path string, params *Params) ([]byte, st
|
||||||
return nil, node.handler, true
|
return nil, node.handler, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return node.bytecode, node.handler, true
|
// Get bytecode from cache
|
||||||
|
bytecodeKey := getBytecodeKey(node.handler)
|
||||||
|
bytecode := r.bytecodeCache.Get(nil, bytecodeKey)
|
||||||
|
|
||||||
|
if len(bytecode) == 0 {
|
||||||
|
// Compile if not in cache
|
||||||
|
if err := r.compileHandler(node); err != nil {
|
||||||
|
return nil, node.handler, true
|
||||||
|
}
|
||||||
|
bytecode = r.bytecodeCache.Get(nil, bytecodeKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to route cache
|
||||||
|
cacheData := make([]byte, 8+len(node.handler))
|
||||||
|
copy(cacheData[:8], bytecodeKey)
|
||||||
|
copy(cacheData[8:], node.handler)
|
||||||
|
r.routeCache.Set(routeCacheKey, cacheData)
|
||||||
|
|
||||||
|
return bytecode, node.handler, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// nodeForHandler finds a node by its handler path
|
||||||
|
func (r *LuaRouter) nodeForHandler(handlerPath string) (*node, bool) {
|
||||||
|
r.mu.RLock()
|
||||||
|
defer r.mu.RUnlock()
|
||||||
|
|
||||||
|
for _, root := range r.routes {
|
||||||
|
if node := findNodeByHandler(root, handlerPath); node != nil {
|
||||||
|
return node, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// findNodeByHandler finds a node by its handler path
|
||||||
|
func findNodeByHandler(current *node, handlerPath string) *node {
|
||||||
|
if current == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if current.handler == handlerPath {
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check static children
|
||||||
|
for _, child := range current.staticChild {
|
||||||
|
if node := findNodeByHandler(child, handlerPath); node != nil {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check param child
|
||||||
|
if current.paramChild != nil {
|
||||||
|
if node := findNodeByHandler(current.paramChild, handlerPath); node != nil {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh rebuilds the router by rescanning the routes directory
|
// Refresh rebuilds the router by rescanning the routes directory
|
||||||
|
@ -332,22 +495,28 @@ func (r *LuaRouter) ReportFailedRoutes() []*RouteError {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeWithError struct {
|
// ClearCache clears both the route and bytecode caches
|
||||||
ScriptPath string
|
func (r *LuaRouter) ClearCache() {
|
||||||
Error error
|
r.routeCache.Reset()
|
||||||
|
r.bytecodeCache.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNodeWithError returns the node with its error for a given path
|
// GetCacheStats returns statistics about the cache
|
||||||
func (r *LuaRouter) GetNodeWithError(method, path string, params *Params) (*NodeWithError, bool) {
|
func (r *LuaRouter) GetCacheStats() map[string]interface{} {
|
||||||
node, found := r.Match(method, path, params)
|
var routeStats fastcache.Stats
|
||||||
if !found {
|
var bytecodeStats fastcache.Stats
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return &NodeWithError{
|
r.routeCache.UpdateStats(&routeStats)
|
||||||
ScriptPath: node.handler,
|
r.bytecodeCache.UpdateStats(&bytecodeStats)
|
||||||
Error: node.err,
|
|
||||||
}, true
|
return map[string]interface{}{
|
||||||
|
"routeEntries": routeStats.EntriesCount,
|
||||||
|
"routeBytes": routeStats.BytesSize,
|
||||||
|
"routeCollisions": routeStats.Collisions,
|
||||||
|
"bytecodeEntries": bytecodeStats.EntriesCount,
|
||||||
|
"bytecodeBytes": bytecodeStats.BytesSize,
|
||||||
|
"bytecodeCollisions": bytecodeStats.Collisions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRouteStats returns statistics about the router
|
// GetRouteStats returns statistics about the router
|
||||||
|
@ -358,7 +527,7 @@ func (r *LuaRouter) GetRouteStats() (int, int64) {
|
||||||
routeCount := 0
|
routeCount := 0
|
||||||
bytecodeBytes := int64(0)
|
bytecodeBytes := int64(0)
|
||||||
|
|
||||||
// Count routes and bytecode size
|
// Count routes and estimate bytecode size
|
||||||
for _, root := range r.routes {
|
for _, root := range r.routes {
|
||||||
count, bytes := countNodesAndBytecode(root)
|
count, bytes := countNodesAndBytecode(root)
|
||||||
routeCount += count
|
routeCount += count
|
||||||
|
@ -377,7 +546,8 @@ func countNodesAndBytecode(n *node) (count int, bytecodeBytes int64) {
|
||||||
// Count this node if it has a handler
|
// Count this node if it has a handler
|
||||||
if n.handler != "" {
|
if n.handler != "" {
|
||||||
count = 1
|
count = 1
|
||||||
bytecodeBytes = int64(len(n.bytecode))
|
// Estimate bytecode size (average of 2KB per script)
|
||||||
|
bytecodeBytes = 2048
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count static children
|
// Count static children
|
||||||
|
@ -396,3 +566,40 @@ func countNodesAndBytecode(n *node) (count int, bytecodeBytes int64) {
|
||||||
|
|
||||||
return count, bytecodeBytes
|
return count, bytecodeBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NodeWithError struct {
|
||||||
|
ScriptPath string
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNodeWithError returns the node with its error for a given path
|
||||||
|
func (r *LuaRouter) GetNodeWithError(method, path string, params *Params) (*NodeWithError, bool) {
|
||||||
|
// Try route cache first
|
||||||
|
routeCacheKey := getCacheKey(method, path)
|
||||||
|
routeCacheData := r.routeCache.Get(nil, routeCacheKey)
|
||||||
|
|
||||||
|
if len(routeCacheData) > 0 {
|
||||||
|
// Cache hit - get handler path
|
||||||
|
handlerPath := string(routeCacheData[8:])
|
||||||
|
|
||||||
|
// Find the node for this handler
|
||||||
|
node, found := r.nodeForHandler(handlerPath)
|
||||||
|
if found {
|
||||||
|
return &NodeWithError{
|
||||||
|
ScriptPath: node.handler,
|
||||||
|
Error: node.err,
|
||||||
|
}, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache miss - do normal routing
|
||||||
|
node, found := r.Match(method, path, params)
|
||||||
|
if !found {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return &NodeWithError{
|
||||||
|
ScriptPath: node.handler,
|
||||||
|
Error: node.err,
|
||||||
|
}, true
|
||||||
|
}
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -5,13 +5,17 @@ go 1.24.1
|
||||||
require git.sharkk.net/Sky/LuaJIT-to-Go v0.0.0
|
require git.sharkk.net/Sky/LuaJIT-to-Go v0.0.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect
|
||||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
github.com/panjf2000/ants/v2 v2.11.2 // indirect
|
github.com/panjf2000/ants/v2 v2.11.2 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasthttp v1.60.0 // indirect
|
github.com/valyala/fasthttp v1.60.0 // indirect
|
||||||
golang.org/x/sync v0.12.0 // indirect
|
golang.org/x/sync v0.12.0 // indirect
|
||||||
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace git.sharkk.net/Sky/LuaJIT-to-Go => ./luajit
|
replace git.sharkk.net/Sky/LuaJIT-to-Go => ./luajit
|
||||||
|
|
15
go.sum
15
go.sum
|
@ -1,11 +1,23 @@
|
||||||
|
github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI=
|
||||||
|
github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI=
|
||||||
|
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
github.com/panjf2000/ants/v2 v2.11.2 h1:AVGpMSePxUNpcLaBO34xuIgM1ZdKOiGnpxLXixLi5Jo=
|
github.com/panjf2000/ants/v2 v2.11.2 h1:AVGpMSePxUNpcLaBO34xuIgM1ZdKOiGnpxLXixLi5Jo=
|
||||||
github.com/panjf2000/ants/v2 v2.11.2/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek=
|
github.com/panjf2000/ants/v2 v2.11.2/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.60.0 h1:kBRYS0lOhVJ6V+bYN8PqAHELKHtXqwq9zNMLKx1MBsw=
|
github.com/valyala/fasthttp v1.60.0 h1:kBRYS0lOhVJ6V+bYN8PqAHELKHtXqwq9zNMLKx1MBsw=
|
||||||
|
@ -13,3 +25,6 @@ github.com/valyala/fasthttp v1.60.0/go.mod h1:iY4kDgV3Gc6EqhRZ8icqcmlG6bqhcDXfuH
|
||||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
|
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
|
Loading…
Reference in New Issue
Block a user