mirror of
https://github.com/luxfi/zap.git
synced 2026-07-26 22:53:31 +00:00
fix: gofmt -s across repo (CI format check)
This commit is contained in:
+4
-4
@@ -77,10 +77,10 @@ func (b *Builder) FinishWithFlags(flags uint16) []byte {
|
||||
|
||||
// ObjectBuilder builds a ZAP object (struct).
|
||||
type ObjectBuilder struct {
|
||||
b *Builder
|
||||
startPos int
|
||||
dataSize int
|
||||
offsets []offsetEntry
|
||||
b *Builder
|
||||
startPos int
|
||||
dataSize int
|
||||
offsets []offsetEntry
|
||||
}
|
||||
|
||||
type offsetEntry struct {
|
||||
|
||||
@@ -138,7 +138,12 @@ func TestAsPQConnRejectsLegacy(t *testing.T) {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
defer ln.Close()
|
||||
go func() { c, _ := ln.Accept(); if c != nil { c.Close() } }()
|
||||
go func() {
|
||||
c, _ := ln.Accept()
|
||||
if c != nil {
|
||||
c.Close()
|
||||
}
|
||||
}()
|
||||
plain, err := net.Dial("tcp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatalf("dial: %v", err)
|
||||
|
||||
@@ -108,13 +108,13 @@ func TestCoverage_ObjectBuilderEVMSetters(t *testing.T) {
|
||||
}
|
||||
|
||||
// Out-of-bounds returns zero values / nil slices.
|
||||
if root.Address(1 << 20) != ZeroAddress {
|
||||
if root.Address(1<<20) != ZeroAddress {
|
||||
t.Fatal("OOB Address should return zero")
|
||||
}
|
||||
if root.Hash(1 << 20) != ZeroHash {
|
||||
if root.Hash(1<<20) != ZeroHash {
|
||||
t.Fatal("OOB Hash should return zero")
|
||||
}
|
||||
if root.Signature(1 << 20) != (Signature{}) {
|
||||
if root.Signature(1<<20) != (Signature{}) {
|
||||
t.Fatal("OOB Signature should return zero")
|
||||
}
|
||||
if root.AddressSlice(1<<20) != nil {
|
||||
|
||||
@@ -75,13 +75,13 @@ func TestCoverage_ObjectOOBReads(t *testing.T) {
|
||||
msg, _ := Parse(out)
|
||||
root := msg.Root()
|
||||
// OOB byte offset returns 0.
|
||||
if root.Uint8(1 << 20) != 0 {
|
||||
if root.Uint8(1<<20) != 0 {
|
||||
t.Fatal("OOB Uint8 should be 0")
|
||||
}
|
||||
if root.Uint16(1 << 20) != 0 {
|
||||
if root.Uint16(1<<20) != 0 {
|
||||
t.Fatal("OOB Uint16 should be 0")
|
||||
}
|
||||
if root.Uint32(1 << 20) != 0 {
|
||||
if root.Uint32(1<<20) != 0 {
|
||||
t.Fatal("OOB Uint32 should be 0")
|
||||
}
|
||||
if root.Bool(1 << 20) {
|
||||
@@ -114,8 +114,8 @@ func TestCoverage_BuilderGrowExpansion(t *testing.T) {
|
||||
func TestCoverage_SetObjectAndSetListNull(t *testing.T) {
|
||||
b := NewBuilder(128)
|
||||
ob := b.StartObject(12)
|
||||
ob.SetObject(0, 0) // null object
|
||||
ob.SetList(4, 0, 0) // null list (offset==0)
|
||||
ob.SetObject(0, 0) // null object
|
||||
ob.SetList(4, 0, 0) // null list (offset==0)
|
||||
ob.SetList(4, 100, 0) // null list (length==0)
|
||||
ob.FinishAsRoot()
|
||||
out := b.Finish()
|
||||
@@ -130,4 +130,3 @@ func TestCoverage_SetObjectAndSetListNull(t *testing.T) {
|
||||
t.Fatal("null list should be null")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -241,7 +241,7 @@ var TransactionSchema = NewStructBuilder("Transaction").
|
||||
Uint64("nonce").
|
||||
Address("from").
|
||||
Address("to").
|
||||
Bytes("value"). // uint256 as bytes
|
||||
Bytes("value"). // uint256 as bytes
|
||||
Bytes("data").
|
||||
Uint64("gas").
|
||||
Bytes("gasPrice"). // uint256 as bytes
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
// - Gemini as final summarizer/arbiter
|
||||
//
|
||||
// Usage:
|
||||
// go run main.go
|
||||
//
|
||||
// go run main.go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -77,9 +77,9 @@ type AgentNode struct {
|
||||
connsMu sync.RWMutex
|
||||
|
||||
// Consensus state
|
||||
responses map[uint64]map[int]string // queryID -> agentID -> response
|
||||
votes map[uint64]map[int][]int // queryID -> agentID -> list of voters
|
||||
summaries map[uint64]string // queryID -> final summary
|
||||
responses map[uint64]map[int]string // queryID -> agentID -> response
|
||||
votes map[uint64]map[int][]int // queryID -> agentID -> list of voters
|
||||
summaries map[uint64]string // queryID -> final summary
|
||||
mu sync.Mutex
|
||||
|
||||
// Stats
|
||||
|
||||
@@ -19,10 +19,10 @@ import (
|
||||
// failingRW returns a configurable error on Read or Write at a
|
||||
// specific byte offset.
|
||||
type failingRW struct {
|
||||
mu sync.Mutex
|
||||
written int
|
||||
failAt int
|
||||
failErr error
|
||||
mu sync.Mutex
|
||||
written int
|
||||
failAt int
|
||||
failErr error
|
||||
underlying io.ReadWriter
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ func TestCoverage_SessionRecvMalformedRekey(t *testing.T) {
|
||||
// emptyRW returns io.EOF on every Read; Write succeeds (discards).
|
||||
type emptyRW struct{}
|
||||
|
||||
func (emptyRW) Read([]byte) (int, error) { return 0, io.EOF }
|
||||
func (emptyRW) Read([]byte) (int, error) { return 0, io.EOF }
|
||||
func (emptyRW) Write(p []byte) (int, error) { return len(p), nil }
|
||||
|
||||
// bufRW combines an io.Reader and io.Writer.
|
||||
|
||||
@@ -243,7 +243,6 @@ func TestCoverage_InitiatorAuthRDecodeFails(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------- responder full handshake replay rejection --------
|
||||
|
||||
// TestCoverage_ResponderTimestampOutOfWindow: HELLO with timestamp
|
||||
|
||||
@@ -261,7 +261,7 @@ func TestCoverage_FrameBufBucketOverflow(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// Force the overflow branch.
|
||||
if frameBufBucket(1 << 30) >= 0 {
|
||||
if frameBufBucket(1<<30) >= 0 {
|
||||
t.Fatal("frameBufBucket should return -1 for huge sizes")
|
||||
}
|
||||
bufP := getFrameBuf(1 << 30)
|
||||
|
||||
+12
-12
@@ -14,18 +14,18 @@ import (
|
||||
type AlertCode uint8
|
||||
|
||||
const (
|
||||
AlertNone AlertCode = 0x00 // reserved
|
||||
AlertDecodeError AlertCode = 0x01
|
||||
AlertUnsupportedSuite AlertCode = 0x02
|
||||
AlertAuthFailed AlertCode = 0x03
|
||||
AlertReplayDetected AlertCode = 0x04
|
||||
AlertDowngradeRefused AlertCode = 0x05
|
||||
AlertHandshakeTimeout AlertCode = 0x06
|
||||
AlertNonceViolation AlertCode = 0x07
|
||||
AlertPSKUnknown AlertCode = 0x08
|
||||
AlertVMIdentityMismatch AlertCode = 0x09
|
||||
AlertAuthoritySigFailed AlertCode = 0x0A
|
||||
AlertPolicyRefused AlertCode = 0x0B
|
||||
AlertNone AlertCode = 0x00 // reserved
|
||||
AlertDecodeError AlertCode = 0x01
|
||||
AlertUnsupportedSuite AlertCode = 0x02
|
||||
AlertAuthFailed AlertCode = 0x03
|
||||
AlertReplayDetected AlertCode = 0x04
|
||||
AlertDowngradeRefused AlertCode = 0x05
|
||||
AlertHandshakeTimeout AlertCode = 0x06
|
||||
AlertNonceViolation AlertCode = 0x07
|
||||
AlertPSKUnknown AlertCode = 0x08
|
||||
AlertVMIdentityMismatch AlertCode = 0x09
|
||||
AlertAuthoritySigFailed AlertCode = 0x0A
|
||||
AlertPolicyRefused AlertCode = 0x0B
|
||||
)
|
||||
|
||||
// String returns the canonical §14 name. Audit pipelines match on
|
||||
|
||||
+7
-7
@@ -17,13 +17,13 @@ import (
|
||||
// ---------- HELLO (§6.1) ----------
|
||||
|
||||
type HelloFrame struct {
|
||||
Suite SuiteID
|
||||
PQMode PQMode
|
||||
ClientRandom [ClientRandLen]byte
|
||||
TimestampNS uint64
|
||||
ClientID [IDLen]byte
|
||||
OfferedSchemes []SuiteID
|
||||
StaticPKInitiator []byte // MLDSA65PubLen
|
||||
Suite SuiteID
|
||||
PQMode PQMode
|
||||
ClientRandom [ClientRandLen]byte
|
||||
TimestampNS uint64
|
||||
ClientID [IDLen]byte
|
||||
OfferedSchemes []SuiteID
|
||||
StaticPKInitiator []byte // MLDSA65PubLen
|
||||
}
|
||||
|
||||
// Encode returns the wire-encoded HELLO body (no outer type/length).
|
||||
|
||||
@@ -30,11 +30,11 @@ func TestFullHandshakeAndEcho(t *testing.T) {
|
||||
}
|
||||
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
clientSess *Session
|
||||
clientErr error
|
||||
serverSess *Session
|
||||
serverErr error
|
||||
wg sync.WaitGroup
|
||||
clientSess *Session
|
||||
clientErr error
|
||||
serverSess *Session
|
||||
serverErr error
|
||||
)
|
||||
wg.Add(2)
|
||||
|
||||
@@ -230,7 +230,11 @@ func TestHandshakeStrictPQRefusesClassicalOffer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func errIsVMIdentity(err error) bool { return bytes.Contains([]byte(err.Error()), []byte("vm_identity_mismatch")) }
|
||||
func errIsDowngrade(err error) bool { return bytes.Contains([]byte(err.Error()), []byte("downgrade_refused")) }
|
||||
func errIsVMIdentity(err error) bool {
|
||||
return bytes.Contains([]byte(err.Error()), []byte("vm_identity_mismatch"))
|
||||
}
|
||||
func errIsDowngrade(err error) bool {
|
||||
return bytes.Contains([]byte(err.Error()), []byte("downgrade_refused"))
|
||||
}
|
||||
|
||||
func errfmt(format string, args ...any) error { return fmt.Errorf(format, args...) }
|
||||
|
||||
@@ -93,8 +93,8 @@ func runStaticTranscriptKAT(t *testing.T, path string) {
|
||||
// katBytes resolves a JSON input field to a []byte. Two shapes are
|
||||
// supported:
|
||||
//
|
||||
// "field": "0xabcd..." -> hex string
|
||||
// "field": {"pattern_base": "0xAA", "length": N} -> generated pattern
|
||||
// "field": "0xabcd..." -> hex string
|
||||
// "field": {"pattern_base": "0xAA", "length": N} -> generated pattern
|
||||
func katBytes(t *testing.T, in map[string]interface{}, name string) []byte {
|
||||
t.Helper()
|
||||
raw, ok := in[name]
|
||||
|
||||
@@ -446,4 +446,3 @@ func (p Profile) label() string {
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
|
||||
@@ -454,4 +454,3 @@ func zeroBytes(b []byte) {
|
||||
b[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,10 +39,10 @@ type Transcript struct {
|
||||
type transcriptStage uint8
|
||||
|
||||
const (
|
||||
stageNew transcriptStage = iota // before AbsorbHello
|
||||
stageH0 // after AbsorbHello
|
||||
stageH1 // after AbsorbKEM
|
||||
stageH2 // after FinishFull / FinishPSK
|
||||
stageNew transcriptStage = iota // before AbsorbHello
|
||||
stageH0 // after AbsorbHello
|
||||
stageH1 // after AbsorbKEM
|
||||
stageH2 // after FinishFull / FinishPSK
|
||||
)
|
||||
|
||||
// NewTranscript creates a transcript pinned to the supplied suite. The
|
||||
|
||||
+5
-5
@@ -120,12 +120,12 @@ const (
|
||||
MsgTypeToolResult uint16 = 11
|
||||
|
||||
// Field offsets for tool messages
|
||||
FieldToolID = 0 // uint32 - tool identifier
|
||||
FieldToolID = 0 // uint32 - tool identifier
|
||||
FieldToolNameLen = 4 // uint32 - tool name length
|
||||
FieldToolName = 8 // bytes - tool name (up to 32 bytes)
|
||||
FieldArgCount = 40 // uint32 - number of arguments
|
||||
FieldResultLen = 44 // uint32 - result length
|
||||
FieldResult = 48 // bytes - result data
|
||||
FieldToolName = 8 // bytes - tool name (up to 32 bytes)
|
||||
FieldArgCount = 40 // uint32 - number of arguments
|
||||
FieldResultLen = 44 // uint32 - result length
|
||||
FieldResult = 48 // bytes - result data
|
||||
)
|
||||
|
||||
// simulateZAPToolCall simulates ZAP tool calling with zero-copy
|
||||
|
||||
+5
-5
@@ -124,12 +124,12 @@ func Publish(opts PublishOptions) (*Publisher, error) {
|
||||
}
|
||||
|
||||
info, err := mdns.NewMDNSService(
|
||||
opts.ServerID, // instance name
|
||||
ServiceType+".local.", // service type
|
||||
"", // domain (default)
|
||||
host+".local.", // host
|
||||
opts.ServerID, // instance name
|
||||
ServiceType+".local.", // service type
|
||||
"", // domain (default)
|
||||
host+".local.", // host
|
||||
opts.Port,
|
||||
nil, // ips (auto-detect)
|
||||
nil, // ips (auto-detect)
|
||||
txt,
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -53,10 +53,10 @@ type Conn struct {
|
||||
mu sync.Mutex
|
||||
|
||||
// Request/response correlation
|
||||
reqID uint32
|
||||
reqIDMu sync.Mutex
|
||||
pending map[uint32]chan *Message
|
||||
pendMu sync.Mutex
|
||||
reqID uint32
|
||||
reqIDMu sync.Mutex
|
||||
pending map[uint32]chan *Message
|
||||
pendMu sync.Mutex
|
||||
}
|
||||
|
||||
// Handler handles incoming ZAP messages.
|
||||
|
||||
@@ -49,9 +49,9 @@ type Struct struct {
|
||||
|
||||
// Enum describes a ZAP enum.
|
||||
type Enum struct {
|
||||
Name string
|
||||
Type Type // Underlying type (Uint8, Uint16, etc.)
|
||||
Values map[string]uint64
|
||||
Name string
|
||||
Type Type // Underlying type (Uint8, Uint16, etc.)
|
||||
Values map[string]uint64
|
||||
}
|
||||
|
||||
// Schema describes a complete ZAP schema.
|
||||
|
||||
@@ -13,12 +13,12 @@ import (
|
||||
|
||||
// SimpleConsensus is a simplified consensus test using direct channels
|
||||
type SimpleConsensus struct {
|
||||
id int
|
||||
inbox chan *Message
|
||||
peers []*SimpleConsensus
|
||||
votes map[uint64]int
|
||||
commits atomic.Int32
|
||||
mu sync.Mutex
|
||||
id int
|
||||
inbox chan *Message
|
||||
peers []*SimpleConsensus
|
||||
votes map[uint64]int
|
||||
commits atomic.Int32
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func newSimpleConsensus(id int) *SimpleConsensus {
|
||||
|
||||
+4
-4
@@ -9,10 +9,10 @@ import "errors"
|
||||
// hugepage path is wired. See dpdk_linux.go for the build-tagged factory.
|
||||
//
|
||||
// Hardware/software required for the real impl:
|
||||
// * Linux kernel with hugepage support (2MB or 1GB pages)
|
||||
// * DPDK 23.11+ build with cuda_gha or cuda_kernel mempool driver
|
||||
// * Any DPDK-supported NIC (broader than GPUDirect's Mellanox-only)
|
||||
// * NVIDIA GPU with CUDA Toolkit 12+
|
||||
// - Linux kernel with hugepage support (2MB or 1GB pages)
|
||||
// - DPDK 23.11+ build with cuda_gha or cuda_kernel mempool driver
|
||||
// - Any DPDK-supported NIC (broader than GPUDirect's Mellanox-only)
|
||||
// - NVIDIA GPU with CUDA Toolkit 12+
|
||||
//
|
||||
// The real path: DPDK takes the NIC via kernel-bypass, ingests packets
|
||||
// into hugepages, cudaHostRegister maps the hugepages into CUDA-visible
|
||||
|
||||
@@ -9,10 +9,10 @@ import "errors"
|
||||
// path is wired. See gpudirect_linux.go for the build-tagged factory.
|
||||
//
|
||||
// Hardware required for the real impl:
|
||||
// * NVIDIA GPU with GPUDirect RDMA support (Hopper / Ada / Ampere)
|
||||
// * Mellanox / NVIDIA ConnectX-6+ NIC
|
||||
// * Linux kernel with nv_peer_mem / nvidia-peermem loaded
|
||||
// * libfabric or libibverbs build-time deps
|
||||
// - NVIDIA GPU with GPUDirect RDMA support (Hopper / Ada / Ampere)
|
||||
// - Mellanox / NVIDIA ConnectX-6+ NIC
|
||||
// - Linux kernel with nv_peer_mem / nvidia-peermem loaded
|
||||
// - libfabric or libibverbs build-time deps
|
||||
//
|
||||
// Reference architecture: NVIDIA DOCA GPUNetIO + Holoscan transport
|
||||
// layer. Packets DMA from NIC into VRAM, GPU kernel parses ZAP header
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
//
|
||||
// Three transports are implemented:
|
||||
//
|
||||
// default — standard Go net (CPU parsing). Always available.
|
||||
// uma — Apple Silicon / NVIDIA Grace unified-memory. cgo + darwin.
|
||||
// Network packets land in shared RAM; GPU kernels read them
|
||||
// at GPU memory speed without a copy.
|
||||
// gpudirect — NVIDIA + Mellanox CX-6/7 (GPUDirect RDMA). cgo + linux.
|
||||
// NIC DMA into VRAM, ZAP parsed by GPU kernel, no CPU touch.
|
||||
// dpdk — Linux DPDK + GPU-mapped hugepages. cgo + linux.
|
||||
// Kernel-bypass packet ingestion, GPU reads from mapped huge-
|
||||
// pages. Best for non-Mellanox NICs.
|
||||
// default — standard Go net (CPU parsing). Always available.
|
||||
// uma — Apple Silicon / NVIDIA Grace unified-memory. cgo + darwin.
|
||||
// Network packets land in shared RAM; GPU kernels read them
|
||||
// at GPU memory speed without a copy.
|
||||
// gpudirect — NVIDIA + Mellanox CX-6/7 (GPUDirect RDMA). cgo + linux.
|
||||
// NIC DMA into VRAM, ZAP parsed by GPU kernel, no CPU touch.
|
||||
// dpdk — Linux DPDK + GPU-mapped hugepages. cgo + linux.
|
||||
// Kernel-bypass packet ingestion, GPU reads from mapped huge-
|
||||
// pages. Best for non-Mellanox NICs.
|
||||
//
|
||||
// All four implement the same Transport interface. Pick() chooses the
|
||||
// best available implementation at runtime, honoring a caller-supplied
|
||||
|
||||
+10
-10
@@ -111,15 +111,15 @@ func WithPicker(p Picker) ClientOption {
|
||||
// Client is a native ZAP RPC client. Created by Connect; closed by
|
||||
// Close (or returned stop function from MustConnect).
|
||||
type Client struct {
|
||||
node *zap.Node
|
||||
disc Discovery
|
||||
picker Picker
|
||||
timeout time.Duration
|
||||
logger *slog.Logger
|
||||
node *zap.Node
|
||||
disc Discovery
|
||||
picker Picker
|
||||
timeout time.Duration
|
||||
logger *slog.Logger
|
||||
|
||||
mu sync.Mutex
|
||||
closed bool
|
||||
stopDisc func()
|
||||
mu sync.Mutex
|
||||
closed bool
|
||||
stopDisc func()
|
||||
}
|
||||
|
||||
// Connect resolves a service via Discovery and returns a Client.
|
||||
@@ -336,10 +336,10 @@ func (nd nodeDiscovery) Peers() []Peer {
|
||||
return out
|
||||
}
|
||||
|
||||
func (nd nodeDiscovery) PeerCount() int { return len(nd.n.Peers()) }
|
||||
func (nd nodeDiscovery) PeerCount() int { return len(nd.n.Peers()) }
|
||||
func (nd nodeDiscovery) ServiceType() string { return nd.serviceType }
|
||||
func (nd nodeDiscovery) Start() error { return nil } // Node already started it
|
||||
func (nd nodeDiscovery) Stop() {} // Node.Stop handles it
|
||||
func (nd nodeDiscovery) Stop() {} // Node.Stop handles it
|
||||
|
||||
// compile-time: RoundRobinPicker satisfies Picker; the *Client uses it.
|
||||
var _ Picker = (*RoundRobinPicker)(nil)
|
||||
|
||||
@@ -31,9 +31,9 @@ func newMDNSDiscovery(serviceType, clientID string, browseInterval time.Duration
|
||||
return &mdnsDiscovery{disc: d}
|
||||
}
|
||||
|
||||
func (m *mdnsDiscovery) Start() error { return m.disc.Start() }
|
||||
func (m *mdnsDiscovery) Stop() { m.disc.Stop() }
|
||||
func (m *mdnsDiscovery) PeerCount() int { return m.disc.PeerCount() }
|
||||
func (m *mdnsDiscovery) Start() error { return m.disc.Start() }
|
||||
func (m *mdnsDiscovery) Stop() { m.disc.Stop() }
|
||||
func (m *mdnsDiscovery) PeerCount() int { return m.disc.PeerCount() }
|
||||
func (m *mdnsDiscovery) ServiceType() string {
|
||||
return m.disc.ServiceType()
|
||||
}
|
||||
|
||||
@@ -110,8 +110,8 @@ func TestAllowListVerifier(t *testing.T) {
|
||||
}{
|
||||
{"bd-1", "ListSecurity", true},
|
||||
{"bd-2", "ListSecurity", true},
|
||||
{"bd-3", "ListSecurity", false}, // not in allow list
|
||||
{"bd-1", "DelistSecurity", false}, // procedure not exposed
|
||||
{"bd-3", "ListSecurity", false}, // not in allow list
|
||||
{"bd-1", "DelistSecurity", false}, // procedure not exposed
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := v.Verify(context.Background(), PeerInfo{NodeID: tc.peer}, tc.proc)
|
||||
@@ -198,11 +198,11 @@ func TestClient_Discover_Timeout(t *testing.T) {
|
||||
|
||||
type emptyDiscovery struct{}
|
||||
|
||||
func (emptyDiscovery) Peers() []Peer { return nil }
|
||||
func (emptyDiscovery) PeerCount() int { return 0 }
|
||||
func (emptyDiscovery) ServiceType() string { return "no-such-service" }
|
||||
func (emptyDiscovery) Start() error { return nil }
|
||||
func (emptyDiscovery) Stop() {}
|
||||
func (emptyDiscovery) Peers() []Peer { return nil }
|
||||
func (emptyDiscovery) PeerCount() int { return 0 }
|
||||
func (emptyDiscovery) ServiceType() string { return "no-such-service" }
|
||||
func (emptyDiscovery) Start() error { return nil }
|
||||
func (emptyDiscovery) Stop() {}
|
||||
|
||||
func contains(haystack, needle string) bool {
|
||||
for i := 0; i+len(needle) <= len(haystack); i++ {
|
||||
|
||||
Reference in New Issue
Block a user