musique/server/mdns.go
2023-01-02 05:55:48 +01:00

89 lines
1.9 KiB
Go

package main
import (
"context"
"fmt"
"log"
"musique/server/proto"
"net"
"sync"
"time"
"github.com/RobertBendun/zeroconf/v2"
)
func doHandshake(wg *sync.WaitGroup, service *zeroconf.ServiceEntry, remotes chan<- Remote, timeout time.Duration) {
for _, ip := range service.AddrIPv4 {
wg.Add(1)
go func(ip net.IP) {
defer wg.Done()
target := fmt.Sprintf("%s:%d", ip, service.Port)
if isThisMyAddress(target) {
return
}
var hs proto.HandshakeResponse
err := proto.CommandTimeout(target, proto.Handshake(), &hs, timeout)
if err == nil {
log.Println("Received handshake response", target, hs)
remotes <- Remote{
Address: target,
Nick: hs.Nick,
Version: hs.Version,
}
}
}(ip)
}
}
// Register all remotes that cane be found in `waitTime` seconds
func registerRemotes(waitTime int) error {
wg := sync.WaitGroup{}
done := make(chan error, 1)
incomingRemotes := make(chan Remote, 32)
entries := make(chan *zeroconf.ServiceEntry, 12)
timeout := time.Second*time.Duration(waitTime)
wg.Add(1)
go func(results <-chan *zeroconf.ServiceEntry) {
for entry := range results {
log.Println("Found service at", entry.HostName, "at addrs", entry.AddrIPv4)
doHandshake(&wg, entry, incomingRemotes, timeout)
}
wg.Done()
done <- nil
}(entries)
go func() {
wg.Wait()
close(incomingRemotes)
}()
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
go func() {
err := zeroconf.Browse(ctx, "_musique._tcp", "local", entries)
if err != nil {
done <- fmt.Errorf("failed to browse: %v", err)
}
<-ctx.Done()
}()
remotes = make(map[string]*Remote)
for remote := range incomingRemotes {
remote := remote
remotes[remote.Address] = &remote
}
return <-done
}
type dnsServer interface {
Shutdown()
}
func registerDNS() (dnsServer, error) {
return zeroconf.Register("Musique", "_musique._tcp", "local", port, []string{}, nil)
}