package rpc import ( "errors" "fmt" "zombiezen.com/go/capnproto2" rpccapnp "zombiezen.com/go/capnproto2/std/capnp/rpc" ) // An Exception is a Cap'n Proto RPC error. type Exception struct { rpccapnp.Exception } // Error returns the exception's reason. func (e Exception) Error() string { r, err := e.Reason() if err != nil { return "rpc exception" } return "rpc exception: " + r } // An Abort is a hang-up by a remote vat. type Abort Exception func copyAbort(m rpccapnp.Message) (Abort, error) { ma, err := m.Abort() if err != nil { return Abort{}, err } msg, _, _ := capnp.NewMessage(capnp.SingleSegment(nil)) if err := msg.SetRootPtr(ma.ToPtr()); err != nil { return Abort{}, err } p, err := msg.RootPtr() if err != nil { return Abort{}, err } return Abort{rpccapnp.Exception{Struct: p.Struct()}}, nil } // Error returns the exception's reason. func (a Abort) Error() string { r, err := a.Reason() if err != nil { return "rpc: aborted by remote" } return "rpc: aborted by remote: " + r } // toException sets fields on exc to match err. func toException(exc rpccapnp.Exception, err error) { if ee, ok := err.(Exception); ok { // TODO(light): copy struct r, err := ee.Reason() if err == nil { exc.SetReason(r) } exc.SetType(ee.Type()) return } exc.SetReason(err.Error()) exc.SetType(rpccapnp.Exception_Type_failed) } // Errors var ( ErrConnClosed = errors.New("rpc: connection closed") ) // Internal errors var ( errQuestionReused = errors.New("rpc: question ID reused") errNoMainInterface = errors.New("rpc: no bootstrap interface") errBadTarget = errors.New("rpc: target not found") errShutdown = errors.New("rpc: shutdown") errUnimplemented = errors.New("rpc: remote used unimplemented protocol feature") ) type bootstrapError struct { err error } func (e bootstrapError) Error() string { return "rpc bootstrap:" + e.err.Error() } type questionError struct { id questionID method *capnp.Method // nil if this is bootstrap err error } func (qe *questionError) Error() string { if qe.method == nil { return fmt.Sprintf("bootstrap call id=%d: %v", qe.id, qe.err) } return fmt.Sprintf("%v call id=%d: %v", qe.method, qe.id, qe.err) }