// send is the synchronous variant of SendAsync func (acl *APIClient) send(req *wire.Request) (resp *wire.Response, err error) { // `0` is reserved for broadcast counters, // increment first therefore. acl.idcnt++ req.ID = acl.idcnt done := make(chan util.Empty) err = acl.cnv.SendAsync(req, func(respIn *wire.Response) { resp = respIn done <- util.Empty{} }) // TODO: Make that configurable? timer := time.NewTimer(10 * time.Second) // Wait until we got a response from SendAsync or until // we time out. select { case <-done: break case stamp := <-timer.C: log.Warningf("APIClient operation timed out at %v", stamp) return nil, util.ErrTimeout } return }
// broadcast implements the actual network broadcasting. // It just sends the request over all conversations in the pool. func (cn *Connector) broadcast(req *wire.Request) error { var errs util.Errors req.ID = 0 for cnv := range cn.cp.Iter() { if err := cnv.SendAsync(req, nil); err != nil { errs = append(errs, err) } } return errs.ToErr() }
// SendAsync sends `req` to the other end and calls callback on the response. func (cnv *Conversation) SendAsync(req *wire.Request, callback transfer.AsyncFunc) error { cnv.Lock() defer cnv.Unlock() // Add a nonce so that the same message is guaranteed to result // in a different ciphertext: req.Nonce = rand.Int63() // Broadcast messages usually do not register a callback. // (it wouldn't have been called anyways) if callback != nil { cnv.notifees[req.ID] = callback } return cnv.proto.Send(req) }