diff --git a/broadcast/dtos/dtos.go b/broadcast/dtos/dtos.go new file mode 100644 index 00000000..0877c9b5 --- /dev/null +++ b/broadcast/dtos/dtos.go @@ -0,0 +1,86 @@ +// Package dtos implements all data transfer objects used from outside the broadcast implementation context. +package dtos + +import ( + "context" + "google.golang.org/protobuf/reflect/protoreflect" + "time" +) + +// Msg defines the message sent from a server to another server or client. The messages should be sent by the router. +type Msg interface { + GetBroadcastID() uint64 + GetMethod() string + String() string +} + +// BroadcastMsg is a data transfer object of a message received by another server or client. +type BroadcastMsg struct { + Ctx context.Context + Options BroadcastOptions + // The address of the client or server that originated the broadcast request + OriginAddr string + Info Info +} + +func (msg *BroadcastMsg) GetBroadcastID() uint64 { + return msg.Info.BroadcastID +} + +func (msg *BroadcastMsg) GetMethod() string { + return msg.Info.Method +} + +func (msg *BroadcastMsg) String() string { + return "broadcast" +} + +// ReplyMsg is similar to BroadcastMsg, but is strictly used for replying to a client. +type ReplyMsg struct { + Info Info + // The address of the client that originated the broadcast request + ClientAddr string + Err error +} + +func (r *ReplyMsg) GetBroadcastID() uint64 { + return r.Info.BroadcastID +} + +func (r *ReplyMsg) GetMethod() string { + return "reply" +} + +func (r *ReplyMsg) String() string { + return "reply" +} + +// Info contains data pertaining to the current message such as routing information, contents, and which server handler +// should receive the message. +type Info struct { + Message protoreflect.ProtoMessage + BroadcastID uint64 + Method string + Addr string + OriginMethod string + OriginDigest []byte + OriginSignature []byte + OriginPubKey string +} + +// Client is a data structure used when sending a reply to a client. +type Client struct { + Addr string + SendMsg func(timeout time.Duration, dto *ReplyMsg) error + Close func() error +} + +// BroadcastOptions is used to configure a particular broadcast, e.g. by only broadcasting to a subset of the servers in +// a view. +type BroadcastOptions struct { + ServerAddresses []string + AllowDuplication bool + SkipSelf bool + ProgressTo string + RelatedToReq uint64 +} diff --git a/broadcast/errors/errors.go b/broadcast/errors/errors.go new file mode 100644 index 00000000..468d61ce --- /dev/null +++ b/broadcast/errors/errors.go @@ -0,0 +1,49 @@ +package errors + +// IDErr should be used when a message with a BroadcastID is sent to a broadcast processor with another BroadcastID. This +// can happen if a user deliberately changes the BroadcastID of a message. +type IDErr struct{} + +func (err IDErr) Error() string { + return "broadcast: wrong ID" +} + +// MissingClientReqErr signifies that a server tries to reply to a client, but has not yet received the original request +// form the client. This is especially important when the message does not contain routing information, such as in QuorumCalls. +type MissingClientReqErr struct{} + +func (err MissingClientReqErr) Error() string { + return "broadcast: has not received client req yet" +} + +// AlreadyProcessedErr is used when a message is received after the broadcast processor has stopped. This means that the +// server has sent a reply to the client and thus the incoming message needs not be processed. +type AlreadyProcessedErr struct{} + +func (err AlreadyProcessedErr) Error() string { + return "broadcast: already processed request" +} + +// ClientReqAlreadyReceivedErr should be used when a duplicate client request is received. +type ClientReqAlreadyReceivedErr struct{} + +func (err ClientReqAlreadyReceivedErr) Error() string { + return "broadcast: client request already received (dropped)" +} + +// OutOfOrderErr should be used when the preserve ordering configuration option is used and a message is received out of +// order. +type OutOfOrderErr struct{} + +func (err OutOfOrderErr) Error() string { + return "broadcast: the message is out of order" +} + +// InvalidAddrErr should be used when an invalid server/client address is provided. +type InvalidAddrErr struct { + Addr string +} + +func (err InvalidAddrErr) Error() string { + return "broadcast: provided Addr is invalid. got: " + err.Addr +} diff --git a/examples/go.mod b/examples/go.mod index 2342412b..c2c0e059 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/relab/gorums v0.7.0 golang.org/x/term v0.18.0 - google.golang.org/grpc v1.62.1 + google.golang.org/grpc v1.63.0 google.golang.org/protobuf v1.33.0 ) diff --git a/examples/go.sum b/examples/go.sum index 48e13940..8b52f1ee 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -22,6 +22,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=