// sendOneInvite sends invitations to all the addresses in addrs and returns the one that accepted it. // All addrs are assumed to be equivalent and thus at most one Invite RPC will succeed. // // TODO: This is aiming to replicate what the RPC stack does for all the // addresses a single name resolved to. Should all these addresses discovered // somehow be encapsulated in a single object name? func sendOneInvite(ctx *context.T, addrs []string) string { // Give at most 1 second for these connections to be made, if they // can't be made then consider the peer bad and ignore it. // TODO: Should these RPCs also use the "connection timeout" that might be implemented // as per proposal: https://docs.google.com/a/google.com/document/d/1prtxGhSR5TaL0lc_iDRC0Q6H1Drbg2T0x7MWVb_ZCSM/edit?usp=sharing ctx, cancel := context.WithTimeout(ctx, maxInvitationWaitTime) defer cancel() ch := make(chan string) for _, addr := range addrs { go func(addr string) { err := spec.ScreenClient(addr).Invite(ctx, options.ServerAuthorizer{security.AllowEveryone()}) ctx.Infof("Invitation to %v sent, error: %v", addr, err) if err == nil { ch <- addr return } ch <- "" }(addr) } for i := range addrs { if ret := <-ch; len(ret) > 0 { // Drain the rest and return go func() { i++ for i < len(addrs) { <-ch } }() return ret } } return "" }
func channel2rpc(ctx *context.T, src <-chan *spec.Triangle, dst string, errch chan<- error, myScreen chan<- *spec.Triangle) { for t := range src { // This is an "interactive" game, if an RPC doesn't succeed in say ctxTimeout, cancel := context.WithTimeout(ctx, maxTriangleGiveTime) if err := spec.ScreenClient(dst).Give(ctxTimeout, *t, options.ServerAuthorizer{security.AllowEveryone()}); err != nil { cancel() returnTriangle(t, myScreen) ctx.Infof("%q.Give failed: %v, aborting connection with remote screen", dst, err) errch <- err break } cancel() } for t := range src { returnTriangle(t, myScreen) } ctx.VI(1).Infof("Exiting goroutine with connection to %q", dst) }