func (ds *DiscoveryBrowser) Browse(service *NetworkWebSocket_Service, intervalSeconds, timeoutSeconds int) {

	// Don't run two browse processes at the same time
	if ds.inprogress {
		return
	}

	ds.inprogress = true

	entries := make(chan *mdns.ServiceEntry, 255)

	recordsCache := make(map[string]*NetworkWebSocket_DNSRecord)

	timeout := time.Duration(timeoutSeconds) * time.Second
	interval := time.Duration(intervalSeconds) * time.Second

	var targetIPv4 *net.UDPAddr
	var targetIPv6 *net.UDPAddr

	targetIPv4 = network_ipv4Addr
	targetIPv6 = network_ipv6Addr

	// Only look for Named Web Socket DNS-SD services
	params := &mdns.QueryParam{
		Service:  "_nws._tcp",
		Domain:   "local",
		Timeout:  timeout,
		Entries:  entries,
		IPv4mdns: targetIPv4,
		IPv6mdns: targetIPv6,
	}

	go func() {
		complete := false
		timeoutFinish := time.After(timeout)
		intervalFinish := time.After(interval)

		// Wait for responses until timeout
		for !complete {
			select {
			case discoveredService, ok := <-entries:

				if !ok {
					continue
				}

				serviceRecord, err := NewNetworkWebSocketRecordFromDNSRecord(discoveredService)
				if err != nil {
					log.Printf("err: %v", err)
					continue
				}

				// Ignore our own NetworkWebSocket services
				if service.isOwnProxyService(serviceRecord) {
					continue
				}

				// Ignore previously discovered NetworkWebSocket proxy services
				if service.isActiveProxyService(serviceRecord) {
					continue
				}

				// Resolve discovered service hash provided against available services
				var sock *NetworkWebSocket
				for _, knownService := range service.Channels {
					if bcrypt.Match(knownService.serviceName, serviceRecord.Hash_BCrypt) {
						sock = knownService
						break
					}
				}

				if sock != nil {
					// Create new web socket connection toward discovered proxy
					if _, dErr := sock.dialFromDNSRecord(serviceRecord); dErr != nil {
						log.Printf("err: %v", dErr)
						continue
					}
				} else {
					// Store as an unresolved DNS-SD record
					recordsCache[serviceRecord.Hash_Base64] = serviceRecord
					continue
				}

			case <-timeoutFinish:
				// Replace unresolved DNS records cache
				ds.cachedDNSRecords = recordsCache

				ds.inprogress = false
			case <-intervalFinish:
				complete = true
			}
		}
	}()

	// Run the mDNS/DNS-SD query
	err := mdns.Query(params)

	time.Sleep(interval) // sleep until next loop is scheduled

	if err != nil {
		log.Printf("Could not perform mDNS/DNS-SD query. %v", err)
		return
	}
}
func (ds *DiscoveryServer) Browse() {

	entries := make(chan *mdns.ServiceEntry, 255)

	timeout := 2 * time.Second

	params := &mdns.QueryParam{
		Service: "_ws._tcp",
		Domain:  "local",
		Timeout: timeout,
		Entries: entries,
	}

	go func() {
		complete := false
		finish := time.After(timeout)

		// Wait for responses until timeout
		for !complete {
			select {
			case e, ok := <-entries:

				if !ok {
					continue
				}

				nameComponents := strings.Split(e.Name, ".")
				shortName := ""

				for i := len(nameComponents) - 1; i >= 0; i-- {
					if nameComponents[i] == "_ws" {
						shortName = strings.Join(nameComponents[:i], ".")
						break
					}
				}

				// DEBUG
				//log.Printf("Found proxy web socket [%s] @ [%s:%d] TXT[%s]", shortName, e.Host, e.Port, e.Info)

				// Is this a BroadcastWebSocket service?
				if isValid := NetworkServiceMatcher.MatchString(shortName); !isValid {
					continue
				}

				// Ignore our own BroadcastWebSocket services
				if isOwned := advertisedServiceNames[shortName]; isOwned {
					continue
				}

				// Ignore previously discovered BroadcastWebSocket services
				if isRegistered := registeredServiceNames[shortName]; isRegistered {
					continue
				}

				// Build websocket data from returned information
				servicePath := "/"
				serviceParts := strings.FieldsFunc(e.Info, func(r rune) bool {
					return r == '=' || r == ',' || r == ';' || r == ' '
				})
				if len(serviceParts) > 1 {
					for i := 0; i < len(serviceParts); i += 2 {
						if strings.ToLower(serviceParts[i]) == "path" {
							servicePath = serviceParts[i+1]
							break
						}
					}
				}

				// Generate unique id for connection
				rand.Seed(time.Now().UTC().UnixNano())
				newPeerId := rand.Int()

				// Build URL
				remoteWSUrl := &url.URL{
					Scheme: "ws",
					Host:   fmt.Sprintf("%s:%d", e.Host, e.Port),
					Path:   fmt.Sprintf("%s/%d", servicePath, newPeerId),
				}

				serviceName := path.Base(servicePath)

				// Resolve websocket connection
				sock := namedWebSockets[servicePath]
				if sock == nil {
					sock = NewNamedWebSocket(serviceName, true, ds.Port)
					namedWebSockets[servicePath] = sock
				}

				log.Printf("Establishing proxy broadcast websocket connection to ws://%s%s", remoteWSUrl.Host, remoteWSUrl.Path)

				ws, _, nErr := websocket.DefaultDialer.Dial(remoteWSUrl.String(), map[string][]string{
					"Origin":                     []string{ds.Host},
					"X-BroadcastWebSocket-Proxy": []string{"true"},
				})
				if nErr != nil {
					log.Printf("Proxy broadcast websocket connection failed: %s", nErr)
					return
				}

				proxyConn := NewProxyConnection(newPeerId, ws, false)

				proxyConn.addConnection(sock)

				registeredServiceNames[shortName] = true

			case <-finish:
				complete = true
			}
		}
	}()

	// Run the mDNS query
	err := mdns.Query(params)
	if err != nil {
		log.Fatalf("err: %v", err)
	}
}
func (ds *DiscoveryBrowser) Browse(service *Service, timeoutSeconds int) {

	entries := make(chan *mdns.ServiceEntry, 255)

	recordsCache := make(map[string]*DNSRecord, 255)

	timeout := time.Duration(timeoutSeconds) * time.Second

	var targetIPv4 *net.UDPAddr
	var targetIPv6 *net.UDPAddr

	targetIPv4 = network_ipv4Addr
	targetIPv6 = network_ipv6Addr

	// Only look for Network Web Socket DNS-SD services
	params := &mdns.QueryParam{
		Service:  "_nws._tcp",
		Domain:   "local",
		Timeout:  timeout,
		Entries:  entries,
		IPv4mdns: targetIPv4,
		IPv6mdns: targetIPv6,
	}

	go func() {
		complete := false
		timeoutFinish := time.After(timeout)

		// Wait for responses until timeout
		for !complete {
			select {
			case discoveredService, ok := <-entries:

				if !ok {
					continue
				}

				serviceRecord, err := NewServiceRecordFromDNSRecord(discoveredService)
				if err != nil {
					log.Printf("err: %v", err)
					continue
				}

				// Ignore our own Channel services
				if service.isOwnProxyService(serviceRecord) {
					continue
				}

				// Ignore previously discovered Channel proxy services
				if service.isActiveProxyService(serviceRecord) {
					continue
				}

				// Resolve discovered service hash provided against available services
				var channel *Channel
				for _, knownService := range service.Channels {
					if bcrypt.Match(knownService.serviceName, serviceRecord.Hash_BCrypt) {
						channel = knownService
						break
					}
				}

				if channel != nil {
					// Create new web socket connection toward discovered proxy
					if dErr := dialProxyFromDNSRecord(serviceRecord, channel); dErr != nil {
						log.Printf("err: %v", dErr)
						continue
					}
				} else {
					// Store as an unresolved DNS-SD record
					recordsCache[serviceRecord.Hash_Base64] = serviceRecord
					continue
				}

			case <-timeoutFinish:
				// Replace unresolved DNS records cache
				ds.cachedDNSRecords = recordsCache

				complete = true
			}
		}
	}()

	// Run the mDNS/DNS-SD query
	err := mdns.Query(params)

	if err != nil {
		log.Printf("Could not perform mDNS/DNS-SD query. %v", err)
		return
	}
}