--- /dev/null
+package zeroconf
+
+import (
+ "fmt"
+ "net"
+ "sync"
+)
+
+// 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.)
+ 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, domain string) *ServiceRecord {
+ s := &ServiceRecord{
+ Instance: instance,
+ Service: service,
+ Domain: domain,
+ serviceName: fmt.Sprintf("%s.%s.", trimDot(service), trimDot(domain)),
+ }
+
+ // 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
+
+ stopProbing chan struct{}
+ once sync.Once
+}
+
+// NewLookupParams constructs a LookupParams.
+func NewLookupParams(instance, service, domain string, entries chan<- *ServiceEntry) *LookupParams {
+ return &LookupParams{
+ ServiceRecord: *NewServiceRecord(instance, service, domain),
+ Entries: entries,
+
+ stopProbing: make(chan struct{}),
+ }
+}
+
+// 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
+ TTL uint32 `json:"ttl"` // TTL of the service record
+ AddrIPv4 []net.IP `json:"-"` // Host machine IPv4 address
+ AddrIPv6 []net.IP `json:"-"` // Host machine IPv6 address
+}
+
+// NewServiceEntry constructs a ServiceEntry.
+func NewServiceEntry(instance, service, domain string) *ServiceEntry {
+ return &ServiceEntry{
+ ServiceRecord: *NewServiceRecord(instance, service, domain),
+ }
+}