Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions broadcast/dtos/dtos.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Package dtos implements all data transfer objects used from outside the broadcast implementation context.
package dtos
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a package doc comment for dtos to explain what it is and provides.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the package name could be more specific. I can't figure out what it means, so I can't think of something better.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's supposed to contain all dto's that are referenced outside of the broadcast package context (including subfolders). The main idea is to prevent cyclic imports and provide a common namespace for dto's pertaining to broadcast outside of the broadcast context. I.e. instead of referencing processor.RequestDto and router.Msg in gorums/server.go, I thought it would be easier to use dtos.RequestDto and dtos.Msg. Hoping this would reduce the cognitive load of developers working with higher level functionality such as nodes/channels, as both processor and router are implementation details specific to broadcasting.

Naming things are not my strong suit, so feel free to rename/change. If you think it is better, the dtos could also be moved to their respective packages (RequestDto -> processor, the rest -> router).


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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be quite useful with doc comments for structs, methods, fields etc. Especially, those fields that aren't common knowledge, such as Info, Options, OriginAddr.

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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This question applies to the all types and fields in the PR: Is it intentional that all types and fields are exported? Are they needed outside the broadcast/dtos package?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they are. I provided a longer explanation to one of the comments above. 👍

ServerAddresses []string
AllowDuplication bool
SkipSelf bool
ProgressTo string
RelatedToReq uint64
}
49 changes: 49 additions & 0 deletions broadcast/errors/errors.go
Original file line number Diff line number Diff line change
@@ -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{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to have doc comments on these errors too.


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
}
2 changes: 1 addition & 1 deletion examples/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand Down
1 change: 1 addition & 0 deletions examples/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
Loading