Documentation
¶
Overview ¶
Package server provides a gRPC service implementation for the mailbox library. Users wire it into their own gRPC server:
svc, _ := mailbox.New(cfg, mailbox.WithStore(store))
server, _ := server.New(svc, server.WithSecurityGuard(myGuard))
grpcServer := grpc.NewServer(
grpc.ChainUnaryInterceptor(
server.AuthInterceptor(myGuard),
server.LoggingInterceptor(logger),
server.RecoveryInterceptor(logger),
),
grpc.ChainStreamInterceptor(
server.StreamAuthInterceptor(myGuard),
server.StreamLoggingInterceptor(logger),
server.StreamRecoveryInterceptor(logger),
),
)
mailboxpb.RegisterMailboxServiceServer(grpcServer, server)
Index ¶
- func AuthInterceptor(guard SecurityGuard) grpc.UnaryServerInterceptor
- func ContextWithIdentity(ctx context.Context, id Identity) context.Context
- func LoggingInterceptor(logger *slog.Logger) grpc.UnaryServerInterceptor
- func RecoveryInterceptor(logger *slog.Logger) grpc.UnaryServerInterceptor
- func StreamAuthInterceptor(guard SecurityGuard) grpc.StreamServerInterceptor
- func StreamLoggingInterceptor(logger *slog.Logger) grpc.StreamServerInterceptor
- func StreamRecoveryInterceptor(logger *slog.Logger) grpc.StreamServerInterceptor
- type Action
- type Decision
- type Identity
- type Option
- type Resource
- type SecurityGuard
- type Server
- func (s *Server) AddTag(ctx context.Context, req *mailboxpb.TagRequest) (*emptypb.Empty, error)
- func (s *Server) BulkAddTag(ctx context.Context, req *mailboxpb.BulkTagRequest) (*mailboxpb.BulkResultResponse, error)
- func (s *Server) BulkDelete(ctx context.Context, req *mailboxpb.BulkDeleteRequest) (*mailboxpb.BulkResultResponse, error)
- func (s *Server) BulkMove(ctx context.Context, req *mailboxpb.BulkMoveRequest) (*mailboxpb.BulkResultResponse, error)
- func (s *Server) BulkPermanentlyDelete(ctx context.Context, req *mailboxpb.BulkPermanentlyDeleteRequest) (*mailboxpb.BulkResultResponse, error)
- func (s *Server) BulkRemoveTag(ctx context.Context, req *mailboxpb.BulkTagRequest) (*mailboxpb.BulkResultResponse, error)
- func (s *Server) BulkUpdateFlags(ctx context.Context, req *mailboxpb.BulkUpdateFlagsRequest) (*mailboxpb.BulkResultResponse, error)
- func (s *Server) ComposeDraft(ctx context.Context, req *mailboxpb.ComposeDraftRequest) (*mailboxpb.DraftResponse, error)
- func (s *Server) DeleteDraft(ctx context.Context, req *mailboxpb.DeleteDraftRequest) (*emptypb.Empty, error)
- func (s *Server) DeleteMessage(ctx context.Context, req *mailboxpb.DeleteMessageRequest) (*emptypb.Empty, error)
- func (s *Server) GetMessage(ctx context.Context, req *mailboxpb.GetMessageRequest) (*mailboxpb.MessageResponse, error)
- func (s *Server) GetReplies(ctx context.Context, req *mailboxpb.GetRepliesRequest) (*mailboxpb.MessageListResponse, error)
- func (s *Server) GetStats(ctx context.Context, req *mailboxpb.GetStatsRequest) (*mailboxpb.StatsResponse, error)
- func (s *Server) GetThread(ctx context.Context, req *mailboxpb.GetThreadRequest) (*mailboxpb.MessageListResponse, error)
- func (s *Server) ListDrafts(ctx context.Context, req *mailboxpb.ListDraftsRequest) (*mailboxpb.DraftListResponse, error)
- func (s *Server) ListFolders(ctx context.Context, req *mailboxpb.ListFoldersRequest) (*mailboxpb.FolderListResponse, error)
- func (s *Server) ListMessages(ctx context.Context, req *mailboxpb.ListMessagesRequest) (*mailboxpb.MessageListResponse, error)
- func (s *Server) MarkAllRead(ctx context.Context, req *mailboxpb.MarkAllReadRequest) (*mailboxpb.CountResponse, error)
- func (s *Server) MoveMessage(ctx context.Context, req *mailboxpb.MoveMessageRequest) (*emptypb.Empty, error)
- func (s *Server) PermanentlyDeleteMessage(ctx context.Context, req *mailboxpb.PermanentlyDeleteMessageRequest) (*emptypb.Empty, error)
- func (s *Server) RemoveTag(ctx context.Context, req *mailboxpb.TagRequest) (*emptypb.Empty, error)
- func (s *Server) RestoreMessage(ctx context.Context, req *mailboxpb.RestoreMessageRequest) (*emptypb.Empty, error)
- func (s *Server) SearchMessages(ctx context.Context, req *mailboxpb.SearchMessagesRequest) (*mailboxpb.MessageListResponse, error)
- func (s *Server) SendDraft(ctx context.Context, req *mailboxpb.SendDraftRequest) (*mailboxpb.MessageResponse, error)
- func (s *Server) SendMessage(ctx context.Context, req *mailboxpb.SendMessageRequest) (*mailboxpb.MessageResponse, error)
- func (s *Server) StreamNotifications(req *mailboxpb.StreamNotificationsRequest, ...) error
- func (s *Server) UnreadCount(ctx context.Context, req *mailboxpb.UnreadCountRequest) (*mailboxpb.CountResponse, error)
- func (s *Server) UpdateDraft(ctx context.Context, req *mailboxpb.UpdateDraftRequest) (*mailboxpb.DraftResponse, error)
- func (s *Server) UpdateFlags(ctx context.Context, req *mailboxpb.UpdateFlagsRequest) (*emptypb.Empty, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AuthInterceptor ¶
func AuthInterceptor(guard SecurityGuard) grpc.UnaryServerInterceptor
AuthInterceptor returns a unary interceptor that authenticates every request using the provided SecurityGuard. On success the Identity is stored in the context so RPC methods can call Authorize without a redundant Authenticate. On failure the request is rejected with codes.Unauthenticated.
func ContextWithIdentity ¶
ContextWithIdentity returns a new context carrying id.
func LoggingInterceptor ¶
func LoggingInterceptor(logger *slog.Logger) grpc.UnaryServerInterceptor
LoggingInterceptor returns a unary interceptor that logs each request at Debug level on success and Error level on failure.
func RecoveryInterceptor ¶
func RecoveryInterceptor(logger *slog.Logger) grpc.UnaryServerInterceptor
RecoveryInterceptor returns a unary interceptor that catches panics, logs the stack trace, and returns codes.Internal to the caller.
func StreamAuthInterceptor ¶
func StreamAuthInterceptor(guard SecurityGuard) grpc.StreamServerInterceptor
StreamAuthInterceptor returns a stream interceptor that authenticates every stream using the provided SecurityGuard.
func StreamLoggingInterceptor ¶
func StreamLoggingInterceptor(logger *slog.Logger) grpc.StreamServerInterceptor
StreamLoggingInterceptor returns a stream interceptor that logs each stream.
func StreamRecoveryInterceptor ¶
func StreamRecoveryInterceptor(logger *slog.Logger) grpc.StreamServerInterceptor
StreamRecoveryInterceptor returns a stream interceptor that catches panics.
Types ¶
type Option ¶
type Option func(*serverOptions)
Option configures a Server.
func WithLogger ¶
WithLogger sets the structured logger used by the server. If l is nil the option is ignored.
func WithMaxBulkSize ¶
WithMaxBulkSize sets the maximum number of message IDs accepted in a single bulk request (BulkDelete, BulkMove, etc.). Requests exceeding this limit are rejected with codes.InvalidArgument. Default: 500.
func WithSecurityGuard ¶
func WithSecurityGuard(g SecurityGuard) Option
WithSecurityGuard sets the SecurityGuard used for authentication and authorization. If g is nil the option is ignored and the default DenyAll guard is kept.
func WithStreamMaxDuration ¶
WithStreamMaxDuration sets a hard upper bound on how long a StreamNotifications stream may remain open. After the duration elapses the stream is closed with a normal EOF, forcing clients to reconnect. This prevents half-open connections from holding goroutines indefinitely. A zero or negative duration disables the limit (default: no limit).
type Resource ¶
type Resource struct {
OwnerID string
}
Resource identifies the mailbox resource being accessed. OwnerID is the user whose mailbox is the target of the operation. An empty OwnerID means the check is method-level only (no specific user).
type SecurityGuard ¶
type SecurityGuard interface {
// Authenticate extracts and validates the caller's identity from the context.
// Return a gRPC status error (e.g. codes.Unauthenticated) on failure.
Authenticate(ctx context.Context) (Identity, error)
// Authorize checks whether id may perform action on resource.
// resource.OwnerID is the target mailbox user.
Authorize(ctx context.Context, id Identity, action Action, resource Resource) (Decision, error)
}
SecurityGuard handles authentication and authorization for every RPC.
Authentication (Authenticate) runs once per RPC inside AuthInterceptor and stores the Identity in the context. Authorization (Authorize) runs inside each RPC method with the specific OwnerID and action being requested.
Typical custom guard:
func (g *myGuard) Authenticate(ctx context.Context) (server.Identity, error) {
md, _ := metadata.FromIncomingContext(ctx)
token := md.Get("authorization")[0]
claims, err := validateJWT(token)
if err != nil {
return nil, status.Errorf(codes.Unauthenticated, "invalid token: %v", err)
}
return &myIdentity{userID: claims.Sub, claims: claims.Extra}, nil
}
func (g *myGuard) Authorize(_ context.Context, id server.Identity, action server.Action, res server.Resource) (server.Decision, error) {
// allow users to access only their own mailbox
if id.UserID() == res.OwnerID {
return server.Decision{Allowed: true}, nil
}
return server.Decision{Allowed: false, Reason: "access denied"}, nil
}
func AllowAll ¶
func AllowAll() SecurityGuard
AllowAll returns a SecurityGuard that authenticates every caller as an anonymous identity and permits all actions. Use only in development or tests.
func DenyAll ¶
func DenyAll() SecurityGuard
DenyAll returns a SecurityGuard whose Authenticate always fails with Unauthenticated. Use as a safe placeholder when no guard is configured.
type Server ¶
type Server struct {
mailboxpb.UnimplementedMailboxServiceServer
// contains filtered or unexported fields
}
Server implements the MailboxServiceServer gRPC interface. Use New to create an instance and register it with a grpc.Server:
grpcServer := grpc.NewServer(...) mailboxpb.RegisterMailboxServiceServer(grpcServer, server)
func New ¶
New creates a Server backed by svc. The server is ready to be registered with a grpc.Server immediately; no additional lifecycle management is needed. Returns an error if svc is nil.
func (*Server) BulkAddTag ¶
func (s *Server) BulkAddTag(ctx context.Context, req *mailboxpb.BulkTagRequest) (*mailboxpb.BulkResultResponse, error)
BulkAddTag adds a tag to multiple messages.
func (*Server) BulkDelete ¶
func (s *Server) BulkDelete(ctx context.Context, req *mailboxpb.BulkDeleteRequest) (*mailboxpb.BulkResultResponse, error)
BulkDelete moves multiple messages to trash.
func (*Server) BulkMove ¶
func (s *Server) BulkMove(ctx context.Context, req *mailboxpb.BulkMoveRequest) (*mailboxpb.BulkResultResponse, error)
BulkMove moves multiple messages to a folder.
func (*Server) BulkPermanentlyDelete ¶
func (s *Server) BulkPermanentlyDelete(ctx context.Context, req *mailboxpb.BulkPermanentlyDeleteRequest) (*mailboxpb.BulkResultResponse, error)
BulkPermanentlyDelete hard-deletes multiple messages from trash.
func (*Server) BulkRemoveTag ¶
func (s *Server) BulkRemoveTag(ctx context.Context, req *mailboxpb.BulkTagRequest) (*mailboxpb.BulkResultResponse, error)
BulkRemoveTag removes a tag from multiple messages.
func (*Server) BulkUpdateFlags ¶
func (s *Server) BulkUpdateFlags(ctx context.Context, req *mailboxpb.BulkUpdateFlagsRequest) (*mailboxpb.BulkResultResponse, error)
BulkUpdateFlags changes the read/archived status of multiple messages.
func (*Server) ComposeDraft ¶
func (s *Server) ComposeDraft(ctx context.Context, req *mailboxpb.ComposeDraftRequest) (*mailboxpb.DraftResponse, error)
ComposeDraft creates and saves a new draft.
func (*Server) DeleteDraft ¶
func (s *Server) DeleteDraft(ctx context.Context, req *mailboxpb.DeleteDraftRequest) (*emptypb.Empty, error)
DeleteDraft permanently deletes a draft.
func (*Server) DeleteMessage ¶
func (s *Server) DeleteMessage(ctx context.Context, req *mailboxpb.DeleteMessageRequest) (*emptypb.Empty, error)
DeleteMessage moves a message to trash.
func (*Server) GetMessage ¶
func (s *Server) GetMessage(ctx context.Context, req *mailboxpb.GetMessageRequest) (*mailboxpb.MessageResponse, error)
GetMessage retrieves a single message by ID.
func (*Server) GetReplies ¶
func (s *Server) GetReplies(ctx context.Context, req *mailboxpb.GetRepliesRequest) (*mailboxpb.MessageListResponse, error)
GetReplies returns direct replies to a message.
func (*Server) GetStats ¶
func (s *Server) GetStats(ctx context.Context, req *mailboxpb.GetStatsRequest) (*mailboxpb.StatsResponse, error)
GetStats returns aggregate statistics for a user's mailbox.
func (*Server) GetThread ¶
func (s *Server) GetThread(ctx context.Context, req *mailboxpb.GetThreadRequest) (*mailboxpb.MessageListResponse, error)
GetThread returns all messages in a thread.
func (*Server) ListDrafts ¶
func (s *Server) ListDrafts(ctx context.Context, req *mailboxpb.ListDraftsRequest) (*mailboxpb.DraftListResponse, error)
ListDrafts lists all drafts for a user.
func (*Server) ListFolders ¶
func (s *Server) ListFolders(ctx context.Context, req *mailboxpb.ListFoldersRequest) (*mailboxpb.FolderListResponse, error)
ListFolders lists all folders (system and custom) for a user.
func (*Server) ListMessages ¶
func (s *Server) ListMessages(ctx context.Context, req *mailboxpb.ListMessagesRequest) (*mailboxpb.MessageListResponse, error)
ListMessages lists messages in a folder with pagination.
func (*Server) MarkAllRead ¶
func (s *Server) MarkAllRead(ctx context.Context, req *mailboxpb.MarkAllReadRequest) (*mailboxpb.CountResponse, error)
MarkAllRead marks all unread messages in a folder as read.
func (*Server) MoveMessage ¶
func (s *Server) MoveMessage(ctx context.Context, req *mailboxpb.MoveMessageRequest) (*emptypb.Empty, error)
MoveMessage moves a message to a different folder.
func (*Server) PermanentlyDeleteMessage ¶
func (s *Server) PermanentlyDeleteMessage(ctx context.Context, req *mailboxpb.PermanentlyDeleteMessageRequest) (*emptypb.Empty, error)
PermanentlyDeleteMessage hard-deletes a message from trash.
func (*Server) RestoreMessage ¶
func (s *Server) RestoreMessage(ctx context.Context, req *mailboxpb.RestoreMessageRequest) (*emptypb.Empty, error)
RestoreMessage restores a message from trash.
func (*Server) SearchMessages ¶
func (s *Server) SearchMessages(ctx context.Context, req *mailboxpb.SearchMessagesRequest) (*mailboxpb.MessageListResponse, error)
SearchMessages performs full-text search across a user's messages.
func (*Server) SendDraft ¶
func (s *Server) SendDraft(ctx context.Context, req *mailboxpb.SendDraftRequest) (*mailboxpb.MessageResponse, error)
SendDraft sends an existing draft.
func (*Server) SendMessage ¶
func (s *Server) SendMessage(ctx context.Context, req *mailboxpb.SendMessageRequest) (*mailboxpb.MessageResponse, error)
SendMessage sends a message without the draft workflow.
func (*Server) StreamNotifications ¶
func (s *Server) StreamNotifications(req *mailboxpb.StreamNotificationsRequest, stream mailboxpb.MailboxService_StreamNotificationsServer) error
StreamNotifications streams real-time notification events for a user. The stream stays open until the client disconnects, the server context is cancelled, or WithStreamMaxDuration elapses (forcing a reconnect cycle). Use last_event_id to replay events missed since the last connection ("" for new events only).
func (*Server) UnreadCount ¶
func (s *Server) UnreadCount(ctx context.Context, req *mailboxpb.UnreadCountRequest) (*mailboxpb.CountResponse, error)
UnreadCount returns the total number of unread messages for a user.
func (*Server) UpdateDraft ¶
func (s *Server) UpdateDraft(ctx context.Context, req *mailboxpb.UpdateDraftRequest) (*mailboxpb.DraftResponse, error)
UpdateDraft patches an existing draft. Non-empty string fields replace the current value; empty strings are ignored. Non-empty repeated fields replace the current list; empty slices are ignored. Header and metadata entries are merged into the existing maps.
func (*Server) UpdateFlags ¶
func (s *Server) UpdateFlags(ctx context.Context, req *mailboxpb.UpdateFlagsRequest) (*emptypb.Empty, error)
UpdateFlags changes the read or archived status of a message.