From a4920a6a8e97b86dbf29132bdc1607b71f3c43aa Mon Sep 17 00:00:00 2001 From: 4566704 <4566704@qq.com> Date: Sun, 20 Sep 2026 12:29:36 +0800 Subject: [PATCH] =?UTF-8?q?feat(arp):=20=E8=87=AA=20go-hua=20=E8=BF=81?= =?UTF-8?q?=E5=85=A5=20ARP=20=E8=A1=A8=E6=9F=A5=E8=AF=A2=E4=B8=8E=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E5=88=B7=E6=96=B0=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - IP→MAC 查询(AutoRefresh 后台刷新/Search/Table), 新增依赖 mostlygeek/arp - 附测试、examples/arp 例程与包 README --- arp/README.md | 37 +++++++++++++++++ arp/arp.go | 57 +++++++++++++++++++++++++++ arp/arp_linux.go | 43 ++++++++++++++++++++ arp/arp_test.go | 94 ++++++++++++++++++++++++++++++++++++++++++++ arp/arp_unix.go | 40 +++++++++++++++++++ arp/arp_windows.go | 57 +++++++++++++++++++++++++++ arp/cache.go | 42 ++++++++++++++++++++ examples/arp/main.go | 27 +++++++++++++ go.mod | 8 ++++ go.sum | 33 ++++++++++++++++ 10 files changed, 438 insertions(+) create mode 100644 arp/README.md create mode 100644 arp/arp.go create mode 100644 arp/arp_linux.go create mode 100644 arp/arp_test.go create mode 100644 arp/arp_unix.go create mode 100644 arp/arp_windows.go create mode 100644 arp/cache.go create mode 100644 examples/arp/main.go diff --git a/arp/README.md b/arp/README.md new file mode 100644 index 0000000..4aa8b85 --- /dev/null +++ b/arp/README.md @@ -0,0 +1,37 @@ +# arp + +系统 ARP 表读取与 IP→MAC 查询,内置定时自动刷新缓存。 + +> 迁移自 go-hua/arp,代码保持原样。基于 `mostlygeek/arp` 读取系统 ARP 表, +> Windows/Unix/Linux 各有平台实现。 + +## 用法 + +```go +import ( + "fmt" + "time" + + "git.zeroonesoft.cn/golib/zogo/arp" +) + +// 方式一:手动刷新 + 查询 +arp.CacheUpdate() +mac := arp.Search("192.168.1.1") // 未命中会自动再刷一次 + +// 方式二:后台定时刷新(每 30s),进程退出前 Stop +arp.AutoRefresh(30 * time.Second) +defer arp.StopAutoRefresh() + +// 全表 +table := arp.Table() // map[ip]mac +fmt.Println("上次刷新:", arp.CacheLastUpdate(), "累计次数:", arp.CacheUpdateCount()) +``` + +完整可运行例程:[examples/arp/main.go](../examples/arp/main.go) + +## 注意 + +- 目标 IP 必须与本机同网段且有过通信,ARP 表才会有记录;查跨网段网关之外的 + 地址大概率 miss。 +- `Search`/`Table` 读的是缓存;要实时数据先 `CacheUpdate` 或开启 `AutoRefresh`。 diff --git a/arp/arp.go b/arp/arp.go new file mode 100644 index 0000000..4f0a5d3 --- /dev/null +++ b/arp/arp.go @@ -0,0 +1,57 @@ +// Package arp 提供系统 ARP 表读取与 IP→MAC 查询,内置定时刷新缓存。 +package arp + +import ( + "time" +) + +// ArpTable ARP 表:IP → MAC 地址映射 +type ArpTable map[string]string + +var ( + stop = make(chan struct{}) + arpCache = &cache{ + table: make(ArpTable), + } +) + +// AutoRefresh 开启定时自动刷新 ARP 缓存 +// t 为刷新间隔 +func AutoRefresh(t time.Duration) { + go func() { + for { + select { + case <-time.After(t): + arpCache.Refresh() + case <-stop: + return + } + } + }() +} + +// StopAutoRefresh 停止定时自动刷新 +func StopAutoRefresh() { + stop <- struct{}{} +} + +// CacheUpdate 手动刷新一次 ARP 缓存 +func CacheUpdate() { + arpCache.Refresh() +} + +// CacheLastUpdate 返回缓存最近一次刷新时间 +func CacheLastUpdate() time.Time { + return arpCache.Updated +} + +// CacheUpdateCount 返回缓存累计刷新次数 +func CacheUpdateCount() int { + return arpCache.UpdatedCount +} + +// Search looks up the MAC address for an IP address +// in the arp table +func Search(ip string) string { + return arpCache.Search(ip) +} diff --git a/arp/arp_linux.go b/arp/arp_linux.go new file mode 100644 index 0000000..a988db7 --- /dev/null +++ b/arp/arp_linux.go @@ -0,0 +1,43 @@ +//go:build linux +// +build linux + +package arp + +import ( + "bufio" + "os" + "strings" +) + +const ( + f_IPAddr int = iota + f_HWType + f_Flags + f_HWAddr + f_Mask + f_Device +) + +// Table 读取 Linux 内核 ARP 表(/proc/net/arp) +func Table() ArpTable { + f, err := os.Open("/proc/net/arp") + + if err != nil { + return nil + } + + defer f.Close() + + s := bufio.NewScanner(f) + s.Scan() // skip the field descriptions + + var table = make(ArpTable) + + for s.Scan() { + line := s.Text() + fields := strings.Fields(line) + table[fields[f_IPAddr]] = fields[f_HWAddr] + } + + return table +} diff --git a/arp/arp_test.go b/arp/arp_test.go new file mode 100644 index 0000000..3ee9547 --- /dev/null +++ b/arp/arp_test.go @@ -0,0 +1,94 @@ +package arp + +import ( + "fmt" + "testing" + "time" +) + +var ( + _ = fmt.Println +) + +func TestTable(t *testing.T) { + + table := Table() + if table == nil { + t.Errorf("Empty table") + } +} + +func TestCacheInfo(t *testing.T) { + prevUpdated := CacheLastUpdate().UnixNano() + prevCount := CacheUpdateCount() + + CacheUpdate() + + if prevUpdated == CacheLastUpdate().UnixNano() { + t.Error() + } + + if prevCount == CacheUpdateCount() { + t.Error() + } +} + +func TestAutoRefresh(t *testing.T) { + if testing.Short() { + t.Skip("Skipping autorefresh test") + } + prevUpdated := CacheLastUpdate().UnixNano() + prevCount := CacheUpdateCount() + + AutoRefresh(100 * time.Millisecond) + time.Sleep(200 * time.Millisecond) + StopAutoRefresh() + + if prevUpdated == CacheLastUpdate().UnixNano() { + t.Error() + } + + if prevCount == CacheUpdateCount() { + t.Error() + } + + // test to make sure stop worked + prevUpdated = CacheLastUpdate().UnixNano() + prevCount = CacheUpdateCount() + time.Sleep(200 * time.Millisecond) + if prevUpdated != CacheLastUpdate().UnixNano() { + t.Error() + } + + if prevCount != CacheUpdateCount() { + t.Error() + } +} + +func TestSearch(t *testing.T) { + table := Table() + + for ip, test := range table { + + result := Search(ip) + if test != result { + t.Errorf("expected %s got %s", test, result) + } + } +} + +func BenchmarkSearch(b *testing.B) { + table := Table() + if len(table) == 0 { + return + } + + for ip, _ := range Table() { + for i := 0; i < b.N; i++ { + Search(ip) + } + + // using the first key is enough + break + } +} diff --git a/arp/arp_unix.go b/arp/arp_unix.go new file mode 100644 index 0000000..020319d --- /dev/null +++ b/arp/arp_unix.go @@ -0,0 +1,40 @@ +//go:build !linux && !windows +// +build !linux,!windows + +// only tested on OSX +// decided to go with exec.Command after I couldn't figure +// out how to extract the arp cache out of the kernel with +// golang's syscall or Sysctl() +// +// ... Help appreciated :) + +package arp + +import ( + "os/exec" + "strings" +) + +// Table 通过 arp -an 命令读取 ARP 表(类 Unix 平台,仅在 OSX 测试过) +func Table() ArpTable { + data, err := exec.Command("arp", "-an").Output() + if err != nil { + return nil + } + + var table = make(ArpTable) + for _, line := range strings.Split(string(data), "\n") { + fields := strings.Fields(line) + if len(fields) < 3 { + continue + } + + // strip brackets around IP + ip := strings.Replace(fields[1], "(", "", -1) + ip = strings.Replace(ip, ")", "", -1) + + table[ip] = fields[3] + } + + return table +} diff --git a/arp/arp_windows.go b/arp/arp_windows.go new file mode 100644 index 0000000..b040335 --- /dev/null +++ b/arp/arp_windows.go @@ -0,0 +1,57 @@ +//go:build windows +// +build windows + +package arp + +// Windows arp table reader added by Claudio Matsuoka. +// Tested only in Windows 8.1, hopefully the arp command output format +// is the same in other Windows versions. + +import ( + "os/exec" + "strings" + "syscall" +) + +// Table 读取 Windows 系统 ARP 表(执行 arp -a 命令解析) +// MAC 地址统一转换为冒号分隔格式 +func Table() ArpTable { + cmd := exec.Command("arp", "-a") + // 隐藏窗口 + cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} + data, err := cmd.Output() + // data, err := exec.Command("arp", "-a").Output() + if err != nil { + return nil + } + + var table = make(ArpTable) + skipNext := false + for _, line := range strings.Split(string(data), "\n") { + // skip empty lines + if len(line) <= 0 { + continue + } + // skip Interface: lines + if line[0] != ' ' { + skipNext = true + continue + } + // skip column headers + if skipNext { + skipNext = false + continue + } + + fields := strings.Fields(line) + if len(fields) < 2 { + continue + } + + ip := fields[0] + // Normalize MAC address to colon-separated format + table[ip] = strings.Replace(fields[1], "-", ":", -1) + } + + return table +} diff --git a/arp/cache.go b/arp/cache.go new file mode 100644 index 0000000..cb8504a --- /dev/null +++ b/arp/cache.go @@ -0,0 +1,42 @@ +package arp + +import ( + "sync" + "time" +) + +// cache ARP 表缓存,读写加锁保证并发安全 +type cache struct { + sync.RWMutex + table ArpTable + + Updated time.Time + UpdatedCount int +} + +// Refresh 重新读取系统 ARP 表,并记录刷新时间与累计次数 +func (c *cache) Refresh() { + c.Lock() + defer c.Unlock() + + c.table = Table() + c.Updated = time.Now() + c.UpdatedCount += 1 +} + +// Search 按 IP 查询 MAC 地址,缓存未命中时自动刷新一次后重查 +func (c *cache) Search(ip string) string { + c.RLock() + defer c.RUnlock() + + mac, ok := c.table[ip] + + if !ok { + c.RUnlock() + c.Refresh() + c.RLock() + mac = c.table[ip] + } + + return mac +} diff --git a/examples/arp/main.go b/examples/arp/main.go new file mode 100644 index 0000000..7f3a812 --- /dev/null +++ b/examples/arp/main.go @@ -0,0 +1,27 @@ +// arp 包示例:读取系统 ARP 表并按 IP 查询 MAC 地址,支持定时自动刷新缓存 +package main + +import ( + "fmt" + "time" + + "git.zeroonesoft.cn/golib/zogo/arp" +) + +func main() { + // 手动刷新一次 ARP 缓存 + arp.CacheUpdate() + fmt.Println("缓存更新时间:", arp.CacheLastUpdate().Format("15:04:05")) + fmt.Println("累计刷新次数:", arp.CacheUpdateCount()) + + // 按 IP 查询 MAC(缓存未命中时会自动刷新一次再查) + gateway := "192.168.1.1" + fmt.Printf("%s 的 MAC: %q\n", gateway, arp.Search(gateway)) + + // 开启自动刷新(每 30 秒),适合长时间运行的服务 + arp.AutoRefresh(30 * time.Second) + fmt.Println("已开启自动刷新(每30秒)") + + time.Sleep(100 * time.Millisecond) + fmt.Printf("再次查询 %s: %q\n", gateway, arp.Search(gateway)) +} diff --git a/go.mod b/go.mod index a705f05..47b61c4 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/cloudwego/base64x v0.1.6 // indirect github.com/gabriel-vasile/mimetype v1.4.15 // indirect github.com/gin-contrib/sse v1.1.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/goccy/go-json v0.10.5 // indirect @@ -34,19 +35,26 @@ require ( github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/leodido/go-urn v1.5.0 // indirect github.com/lestrrat-go/strftime v1.2.0 // indirect + github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20250508043914-ed57fa5c5274 // indirect + github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mostlygeek/arp v0.0.0-20170424181311-541a2129847a // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/quic-go v0.59.0 // indirect + github.com/shirou/gopsutil/v3 v3.24.3 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect golang.org/x/arch v0.22.0 // indirect golang.org/x/crypto v0.55.0 // indirect golang.org/x/net v0.57.0 // indirect golang.org/x/sys v0.47.0 // indirect + golang.org/x/time v0.5.0 // indirect google.golang.org/protobuf v1.36.10 // indirect ) diff --git a/go.sum b/go.sum index 63729f2..a748f4a 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,8 @@ github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8= github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -29,6 +31,9 @@ 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-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -54,15 +59,24 @@ github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkL github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= github.com/lestrrat-go/strftime v1.2.0 h1:8fAUYOeaJKCuLzNvUWBAo8t6I6hkFfodDTndEzJIun0= github.com/lestrrat-go/strftime v1.2.0/go.mod h1:GtsIA/7ddIGJjEdfadUafEb1sbutvlvpMdPCMglykYo= +github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20250508043914-ed57fa5c5274 h1:Vslec/nYvO2TdLdhwex8/1x64OZoQNsUzG79WABQaWg= +github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20250508043914-ed57fa5c5274/go.mod h1:C5LA5UO2ZXJrLaPLYtE1wUJMiyd/nwWaCO5cw/2pSHs= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mostlygeek/arp v0.0.0-20170424181311-541a2129847a h1:AfneHvfmYgUIcgdUrrDFklLdEzQAvG9AKRTe1x1mx/0= +github.com/mostlygeek/arp v0.0.0-20170424181311-541a2129847a/go.mod h1:jZxafo9CAqaKFQE4zitrg5QNlA6CXUsjwXPlIppF3tk= github.com/mozillazg/go-pinyin v0.21.0 h1:Wo8/NT45z7P3er/9YSLHA3/kjZzbLz5hR7i+jGeIGao= github.com/mozillazg/go-pinyin v0.21.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= @@ -70,10 +84,15 @@ github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw= github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= +github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE= +github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/sirupsen/logrus v1.10.2 h1:G2SED73/qrAu6YwbdxOD6peLkCBI3z7L+ykJFTXJBBo= github.com/sirupsen/logrus v1.10.2/go.mod h1:SLEg8TqYulVKKfIGHldVp2K2aYz2DKSVBq4g/H5bR7Q= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -84,13 +103,18 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE= go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= @@ -103,11 +127,20 @@ golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=