// Package rpc implements an optional, versioned JSON protocol over ws sessions. // Both endpoints may issue calls and events. It does not provide durable delivery. package rpc import ( "context" "errors" "time" ) const Subprotocol = "go-omni.rpc.v1" var ( ErrClosed = errors.New("rpc: closed") ErrNotConnected = errors.New("rpc: not connected") ErrBusy = errors.New("rpc: capacity reached") ErrProtocol = errors.New("rpc: invalid protocol message") ) // Config bounds allocations, concurrency, and the lifetime of incoming work. // Zero fields select defaults. A canceled handler must return before Wait succeeds. type Config struct { MaxMessageBytes int `json:"maxMessageBytes"` MaxPending int `json:"maxPending"` MaxConcurrent int `json:"maxConcurrent"` CallTimeout time.Duration `json:"callTimeout"` WriteTimeout time.Duration `json:"writeTimeout"` // OnEventError observes local notification failures; they have no reply on // the wire. This callback runs within the handler completion barrier. OnEventError func(context.Context, error) `json:"-"` } func DefaultConfig() Config { return Config{MaxMessageBytes: 1 << 20, MaxPending: 128, MaxConcurrent: 32, CallTimeout: 30 * time.Second, WriteTimeout: 5 * time.Second} } func (c Config) Validate() error { _, err := normalize(c); return err } func normalize(c Config) (Config, error) { if c.MaxMessageBytes < 0 || c.MaxMessageBytes > 16<<20 || c.MaxPending < 0 || c.MaxPending > 65536 || c.MaxConcurrent < 0 || c.MaxConcurrent > 4096 || c.CallTimeout < 0 || c.CallTimeout > 24*time.Hour || c.WriteTimeout < 0 || c.WriteTimeout > time.Minute { return c, errors.New("rpc: configuration exceeds supported bounds") } d := DefaultConfig() if c.MaxMessageBytes == 0 { c.MaxMessageBytes = d.MaxMessageBytes } if c.MaxPending == 0 { c.MaxPending = d.MaxPending } if c.MaxConcurrent == 0 { c.MaxConcurrent = d.MaxConcurrent } if c.CallTimeout == 0 { c.CallTimeout = d.CallTimeout } if c.WriteTimeout == 0 { c.WriteTimeout = d.WriteTimeout } return c, nil } // Error is an explicitly public error. Only this type's code/message may be // sent to the other endpoint; all other handler errors become INTERNAL. type Error struct { Code string `json:"code"` Message string `json:"message"` } func (e *Error) Error() string { return "rpc: " + e.Code }