Exemple #1
0
func (f *impl) Link(ctx *context.T, sc ifc.BridgeLinkServerCall, topics []ifc.Topic) error {
	ctx.Info("Link for topics ", topics)

	done := make(chan error, 2)

	cc, mu, err := mqttConnect()
	if err != nil {
		return err
	}

	// transmitter: do mqtt subscribe, then copy messages to output stream
	go func() {
		done <- transmitter(topics, sc.SendStream(), cc, mu)
	}()

	// receiver: read the input stream and copy to mqtt via cc.Publish
	go func() {
		done <- receiver(sc.RecvStream(), cc, mu)
	}()

	err = <-done

	// Stop sender by closing cc.Incoming
	cc.Disconnect()

	return err
}
Exemple #2
0
// AllFunc runs a server, advertises it, scans for other servers and makes an
// Echo RPC to every advertised remote server.
func AllFunc(ctx *context.T, output io.Writer) error {
	ls := rpc.ListenSpec{Proxy: "proxy"}
	addRegisteredProto(&ls, "tcp", ":0")
	addRegisteredProto(&ls, "bt", "/0")
	fmt.Fprintf(output, "Listening on: %+v (and proxy)\n", ls.Addrs)
	ctx, server, err := v23.WithNewServer(
		v23.WithListenSpec(ctx, ls),
		mountName(ctx, "all"),
		&echoServer{},
		security.AllowEveryone())
	if err != nil {
		return err
	}
	ad := &discovery.Advertisement{
		InterfaceName: interfaceName,
		Attributes: discovery.Attributes{
			"Hello": "There",
		},
	}
	d, err := v23.NewDiscovery(ctx)
	if err != nil {
		return err
	}
	stoppedAd, err := libdiscovery.AdvertiseServer(ctx, d, server, "", ad, nil)
	if err != nil {
		return err
	}
	updates, err := d.Scan(ctx, "v.InterfaceName=\""+interfaceName+"\"")
	if err != nil {
		return err
	}
	var (
		status      = server.Status()
		counter     = 0
		peerByAdId  = make(map[discovery.AdId]*peer)
		lastCall    = make(map[discovery.AdId]time.Time)
		callResults = make(chan string)
		activeCalls = 0
		quit        = false
		myaddrs     = serverAddrs(status)
		ticker      = time.NewTicker(time.Second)
		call        = func(p *peer) {
			counter++
			activeCalls++
			lastCall[p.adId] = time.Now()
			go func(msg string) {
				summary, err := p.call(ctx, msg)
				if err != nil {
					ctx.Infof("Failed to call [%v]: %v", p.description, err)
					callResults <- ""
					return
				}
				callResults <- summary
			}(fmt.Sprintf("Hello #%d", counter))
		}
		statRequest = make(chan chan<- string)
	)
	defer ticker.Stop()
	stats.NewStringFunc(vangoStat, func() string {
		r := make(chan string)
		statRequest <- r
		return <-r
	})
	defer stats.Delete(vangoStat)
	fmt.Fprintln(output, "My AdID:", ad.Id)
	fmt.Fprintln(output, "My addrs:", myaddrs)
	ctx.Infof("SERVER STATUS: %+v", status)
	for !quit {
		select {
		case <-ctx.Done():
			quit = true
		case <-status.Dirty:
			status = server.Status()
			newaddrs := serverAddrs(status)
			changed := len(newaddrs) != len(myaddrs)
			if !changed {
				for i := range newaddrs {
					if newaddrs[i] != myaddrs[i] {
						changed = true
						break
					}
				}
			}
			if changed {
				myaddrs = newaddrs
				fmt.Fprintln(output, "My addrs:", myaddrs)
			}
			ctx.Infof("SERVER STATUS: %+v", status)
		case u, scanning := <-updates:
			if !scanning {
				fmt.Fprintln(output, "SCANNING STOPPED")
				quit = true
				break
			}
			if u.IsLost() {
				if p, ok := peerByAdId[u.Id()]; ok {
					fmt.Fprintln(output, "LOST:", p.description)
				}
				delete(peerByAdId, u.Id())
				delete(lastCall, u.Id())
				break
			}
			p, err := newPeer(ctx, u)
			if err != nil {
				ctx.Info(err)
				break
			}
			peerByAdId[p.adId] = p
			fmt.Fprintln(output, "FOUND:", p.description)
			call(p)
		case r := <-callResults:
			activeCalls--
			if len(r) > 0 {
				fmt.Fprintln(output, r)
			}
		case <-stoppedAd:
			fmt.Fprintln(output, "STOPPED ADVERTISING")
			stoppedAd = nil
		case <-ticker.C:
			// Call all peers that haven't been called in a while
			now := time.Now()
			for id, t := range lastCall {
				if now.Sub(t) > rpcTimeout {
					call(peerByAdId[id])
				}
			}
		case s := <-statRequest:
			idx := 1
			ret := new(bytes.Buffer)
			fmt.Fprintln(ret, "ACTIVE CALLS:", activeCalls)
			fmt.Fprintln(ret, "PEERS")
			for id, p := range peerByAdId {
				fmt.Fprintf(ret, "%2d) %s -- %v\n", idx, p.description, lastCall[id])
			}
			s <- ret.String()
		}
	}
	fmt.Println(output, "EXITING: Cleaning up")
	for activeCalls > 0 {
		<-callResults
		activeCalls--
	}
	// Exhaust the scanned updates queue.
	// (The channel will be closed as a by-product of the context being Done).
	for range updates {
	}
	fmt.Fprintln(output, "EXITING: Done")
	return nil
}