Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
121 lines
3.8 KiB
Go
121 lines
3.8 KiB
Go
package zeroconf
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// ServiceRecord contains the basic description of a service, which contains instance name, service type & domain
|
|
type ServiceRecord struct {
|
|
Instance string `json:"name"` // Instance name (e.g. "My web page")
|
|
Service string `json:"type"` // Service name (e.g. _http._tcp.)
|
|
Subtypes []string `json:"subtypes"` // Service subtypes
|
|
Domain string `json:"domain"` // If blank, assumes "local"
|
|
|
|
// private variable populated on ServiceRecord creation
|
|
serviceName string
|
|
serviceInstanceName string
|
|
serviceTypeName string
|
|
}
|
|
|
|
// ServiceName returns a complete service name (e.g. _foobar._tcp.local.), which is composed
|
|
// of a service name (also referred as service type) and a domain.
|
|
func (s *ServiceRecord) ServiceName() string {
|
|
return s.serviceName
|
|
}
|
|
|
|
// ServiceInstanceName returns a complete service instance name (e.g. MyDemo\ Service._foobar._tcp.local.),
|
|
// which is composed from service instance name, service name and a domain.
|
|
func (s *ServiceRecord) ServiceInstanceName() string {
|
|
return s.serviceInstanceName
|
|
}
|
|
|
|
// ServiceTypeName returns the complete identifier for a DNS-SD query.
|
|
func (s *ServiceRecord) ServiceTypeName() string {
|
|
return s.serviceTypeName
|
|
}
|
|
|
|
// newServiceRecord constructs a ServiceRecord.
|
|
func newServiceRecord(instance, service string, domain string) *ServiceRecord {
|
|
service, subtypes := parseSubtypes(service)
|
|
s := &ServiceRecord{
|
|
Instance: instance,
|
|
Service: service,
|
|
Domain: domain,
|
|
serviceName: fmt.Sprintf("%s.%s.", trimDot(service), trimDot(domain)),
|
|
}
|
|
|
|
for _, subtype := range subtypes {
|
|
s.Subtypes = append(s.Subtypes, fmt.Sprintf("%s._sub.%s", trimDot(subtype), s.serviceName))
|
|
}
|
|
|
|
// Cache service instance name
|
|
if instance != "" {
|
|
s.serviceInstanceName = fmt.Sprintf("%s.%s", trimDot(s.Instance), s.ServiceName())
|
|
}
|
|
|
|
// Cache service type name domain
|
|
typeNameDomain := "local"
|
|
if len(s.Domain) > 0 {
|
|
typeNameDomain = trimDot(s.Domain)
|
|
}
|
|
s.serviceTypeName = fmt.Sprintf("_services._dns-sd._udp.%s.", typeNameDomain)
|
|
|
|
return s
|
|
}
|
|
|
|
// lookupParams contains configurable properties to create a service discovery request
|
|
type lookupParams struct {
|
|
ServiceRecord
|
|
Entries chan<- *ServiceEntry // Entries Channel
|
|
|
|
isBrowsing bool
|
|
stopProbing chan struct{}
|
|
once sync.Once
|
|
}
|
|
|
|
// newLookupParams constructs a lookupParams.
|
|
func newLookupParams(instance, service, domain string, isBrowsing bool, entries chan<- *ServiceEntry) *lookupParams {
|
|
p := &lookupParams{
|
|
ServiceRecord: *newServiceRecord(instance, service, domain),
|
|
Entries: entries,
|
|
isBrowsing: isBrowsing,
|
|
}
|
|
if !isBrowsing {
|
|
p.stopProbing = make(chan struct{})
|
|
}
|
|
return p
|
|
}
|
|
|
|
// Notify subscriber that no more entries will arrive. Mostly caused
|
|
// by an expired context.
|
|
func (l *lookupParams) done() {
|
|
close(l.Entries)
|
|
}
|
|
|
|
func (l *lookupParams) disableProbing() {
|
|
l.once.Do(func() { close(l.stopProbing) })
|
|
}
|
|
|
|
// ServiceEntry represents a browse/lookup result for client API.
|
|
// It is also used to configure service registration (server API), which is
|
|
// used to answer multicast queries.
|
|
type ServiceEntry struct {
|
|
ServiceRecord
|
|
HostName string `json:"hostname"` // Host machine DNS name
|
|
Port int `json:"port"` // Service Port
|
|
Text []string `json:"text"` // Service info served as a TXT record
|
|
Expiry time.Time `json:"expiry"` // Expiry of the service entry, will be converted to a TTL value
|
|
AddrIPv4 []net.IP `json:"-"` // Host machine IPv4 address
|
|
AddrIPv6 []net.IP `json:"-"` // Host machine IPv6 address
|
|
}
|
|
|
|
// newServiceEntry constructs a ServiceEntry.
|
|
func newServiceEntry(instance, service string, domain string) *ServiceEntry {
|
|
return &ServiceEntry{
|
|
ServiceRecord: *newServiceRecord(instance, service, domain),
|
|
}
|
|
}
|