//export swift_io_v_v23_discovery_new func swift_io_v_v23_discovery_new(ctxHandle C.GoContextHandle, errOut *C.SwiftVError) C.GoDiscoveryHandle { ctx := scontext.GoContext(uint64(ctxHandle)) d, err := v23.NewDiscovery(ctx) if err != nil { sutil.ThrowSwiftError(ctx, err, unsafe.Pointer(errOut)) return C.GoDiscoveryHandle(0) } return C.GoDiscoveryHandle(sutil.GoNewRef(&d)) }
func newDiscovery(ctx *context.T, connectionUrl string) (discovery.T, error) { u, err := url.ParseRequestURI(connectionUrl) if err != nil { return nil, err } q := u.Query() if _, ok := q[QueryGlobal]; ok { mountTTL, err := parseDuration(q.Get(QueryMountTTL)) if err != nil { return nil, err } scanInterval, err := parseDuration(q.Get(QueryScanInterval)) if err != nil { return nil, err } return global.NewWithTTL(ctx, q.Get(QueryGlobal), mountTTL, scanInterval) } return v23.NewDiscovery(ctx) }
func btAndDiscoveryFunc(ctx *context.T, w io.Writer) error { bothf := func(ctx *context.T, w io.Writer, format string, args ...interface{}) { fmt.Fprintf(w, format, args...) ctx.Infof(format, args...) } defer bothf(ctx, w, "finishing!") dis, err := v23.NewDiscovery(ctx) if err != nil { bothf(ctx, w, "Can't create discovery %v", err) return err } ctx = v23.WithListenSpec(ctx, rpc.ListenSpec{Addrs: rpc.ListenAddrs{{Protocol: "bt", Address: "/0"}}}) _, server, err := v23.WithNewServer(ctx, "", &echoServer{}, security.AllowEveryone()) if err != nil { bothf(ctx, w, "Can't create server %v", err) return err } ctx.Infof("Server listening on %v", server.Status().Endpoints) ctx.Infof("Server listen errors: %v", server.Status().ListenErrors) interfaces := []string{ "v.io/x/jni/impl/google/services/vango/Echo", "v.io/x/jni/impl/google/services/vango/Echo2", "v.io/x/jni/impl/google/services/vango/Echo3", "v.io/x/jni/impl/google/services/vango/Echo4", } type adstate struct { ad *discovery.Advertisement stop func() } ads := []adstate{} for _, name := range interfaces { ad := &discovery.Advertisement{ InterfaceName: name, Attributes: discovery.Attributes{ "one": "A value of some kind", "two": "Yet another value", "three": "More and more", "four": "This is insane", }, } nctx, ncancel := context.WithCancel(ctx) ch, err := libdiscovery.AdvertiseServer(nctx, dis, server, "", ad, nil) if err != nil { bothf(nctx, w, "Can't advertise server %v", err) return err } stop := func() { ncancel() <-ch } ads = append(ads, adstate{ad, stop}) } type updateState struct { ch <-chan discovery.Update stop func() } var updates []updateState for _, name := range interfaces { nctx, ncancel := context.WithCancel(ctx) u, err := dis.Scan(nctx, `v.InterfaceName="`+name+`"`) if err != nil { bothf(nctx, w, "Can't scan %v", err) return err } stop := func() { ncancel() } updates = append(updates, updateState{u, stop}) } for _, u := range updates[1:] { go func(up updateState) { for _ = range up.ch { } }(u) } makeopt := func(ad discovery.Advertisement) options.Preresolved { me := &naming.MountEntry{ IsLeaf: true, } for _, a := range ad.Addresses { addr, _ := naming.SplitAddressName(a) me.Servers = append(me.Servers, naming.MountedServer{ Server: addr, }) } return options.Preresolved{Resolution: me} } alive := map[discovery.AdId]options.Preresolved{} ticker := time.NewTicker(time.Second) for { select { case <-ticker.C: if len(alive) == 0 { bothf(ctx, w, "No live connections to dial.") } for _, opt := range alive { dialtime := options.ConnectionTimeout(5 * time.Second) channeltime := options.ChannelTimeout(2 * time.Second) data := make([]byte, 1024) summary, err := runTimedCall(ctx, "A timed call.", string(data), opt, dialtime, channeltime) if err != nil { bothf(ctx, w, "failed call %s, %v, %v", summary, err, opt.Resolution.Servers) } else { bothf(ctx, w, "succeeded call: %s, %v", summary, opt.Resolution.Servers) } } case u := <-updates[0].ch: if u.IsLost() { bothf(ctx, w, "lost %v", u.Addresses()) delete(alive, u.Id()) } else { bothf(ctx, w, "found %v", u.Addresses()) alive[u.Id()] = makeopt(u.Advertisement()) } } } }
// 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 }
func (nm *networkManager) run(ready chan<- interface{}, newLeftScreen, newRightScreen chan<- chan<- *spec.Triangle, newInvite chan<- Invitation) { defer close(nm.myScreen) defer close(newLeftScreen) defer close(newRightScreen) notifyReady := func(result interface{}) { ready <- result close(ready) ready = nil } ctx, shutdown := v23.Init() defer shutdown() ctx, server, err := v23.WithNewServer(ctx, "", spec.ScreenServer(nm), security.AllowEveryone()) if err != nil { notifyReady(err) return } disc, err := v23.NewDiscovery(ctx) if err != nil { notifyReady(err) return } // Select a color based on some unique identifier of the process, the PublicKey serves as one. notifyReady(selectColor(v23.GetPrincipal(ctx).PublicKey())) var ( left = remoteScreen{myScreen: nm.myScreen, notify: newLeftScreen} right = remoteScreen{myScreen: nm.myScreen, notify: newRightScreen} accepted = make(chan string) // Names of remote screens that accepted an invitation seek = make(chan bool) // Send false to stop seeking invitations from others, true otherwise pendingInviterName string pendingInviteUserResponse <-chan error pendingInviteRPCResponse chan<- error ) seekInvites(ctx, disc, server, seek) go sendInvites(ctx, disc, accepted) for { select { case invitation := <-nm.inviteRPCs: if left.Active() { invitation.Response <- fmt.Errorf("thanks for the invite but I'm already engaged with a previous invitation") break } // Defer the response to the user interface. ch := make(chan error) pendingInviterName = invitation.Name pendingInviteRPCResponse = invitation.Response pendingInviteUserResponse = ch invitation.Response = ch newInvite <- invitation case err := <-pendingInviteUserResponse: pendingInviteRPCResponse <- err if err == nil { ctx.Infof("Activating left screen %q", pendingInviterName) left.Activate(ctx, pendingInviterName) seek <- false } pendingInviterName = "" pendingInviteUserResponse = nil pendingInviteRPCResponse = nil case <-left.Lost(): ctx.Infof("Deactivating left screen") left.Deactivate() seek <- true case invitee := <-accepted: ctx.Infof("Activating right screen %q", invitee) right.Activate(ctx, invitee) case <-right.Lost(): ctx.Infof("Deactivating right screen") right.Deactivate() go sendInvites(ctx, disc, accepted) case <-ctx.Done(): return } } }