github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/gregor/interface.go (about)

     1  package gregor
     2  
     3  import (
     4  	"net"
     5  	"time"
     6  
     7  	"github.com/keybase/clockwork"
     8  	"golang.org/x/net/context"
     9  )
    10  
    11  type InBandMsgType int
    12  
    13  const (
    14  	InBandMsgTypeNone   InBandMsgType = 0
    15  	InBandMsgTypeUpdate InBandMsgType = 1
    16  	InBandMsgTypeSync   InBandMsgType = 2
    17  )
    18  
    19  type UID interface {
    20  	Bytes() []byte
    21  	String() string
    22  }
    23  
    24  type MsgID interface {
    25  	Bytes() []byte
    26  	String() string
    27  }
    28  
    29  type DeviceID interface {
    30  	Bytes() []byte
    31  	String() string
    32  }
    33  
    34  type System interface {
    35  	String() string
    36  }
    37  
    38  type Category interface {
    39  	String() string
    40  }
    41  
    42  type Body interface {
    43  	Bytes() []byte
    44  }
    45  
    46  type Metadata interface {
    47  	UID() UID
    48  	MsgID() MsgID
    49  	CTime() time.Time
    50  	DeviceID() DeviceID
    51  	InBandMsgType() InBandMsgType
    52  }
    53  
    54  type MessageWithMetadata interface {
    55  	Metadata() Metadata
    56  }
    57  
    58  type InBandMessage interface {
    59  	MessageWithMetadata
    60  	ToStateUpdateMessage() StateUpdateMessage
    61  	ToStateSyncMessage() StateSyncMessage
    62  	Merge(m1 InBandMessage) (InBandMessage, error)
    63  }
    64  
    65  type StateUpdateMessage interface {
    66  	MessageWithMetadata
    67  	Creation() Item
    68  	Dismissal() Dismissal
    69  }
    70  
    71  type StateSyncMessage interface {
    72  	MessageWithMetadata
    73  }
    74  
    75  type OutOfBandMessage interface {
    76  	System() System
    77  	UID() UID
    78  	Body() Body
    79  }
    80  
    81  type TimeOrOffset interface {
    82  	Time() *time.Time
    83  	Offset() *time.Duration
    84  	Before(t time.Time) bool
    85  	IsZero() bool
    86  }
    87  
    88  type Item interface {
    89  	MessageWithMetadata
    90  	DTime() TimeOrOffset
    91  	RemindTimes() []TimeOrOffset
    92  	Body() Body
    93  	Category() Category
    94  }
    95  
    96  type Reminder interface {
    97  	Item() Item
    98  	RemindTime() time.Time
    99  	Seqno() int
   100  }
   101  
   102  type MsgRange interface {
   103  	EndTime() TimeOrOffset
   104  	Category() Category
   105  	SkipMsgIDs() []MsgID
   106  }
   107  
   108  type Dismissal interface {
   109  	MsgIDsToDismiss() []MsgID
   110  	RangesToDismiss() []MsgRange
   111  }
   112  
   113  type State interface {
   114  	Items() ([]Item, error)
   115  	GetItem(msgID MsgID) (Item, bool)
   116  	ItemsInCategory(c Category) ([]Item, error)
   117  	ItemsWithCategoryPrefix(c Category) ([]Item, error)
   118  	Marshal() ([]byte, error)
   119  	Hash() ([]byte, error)
   120  	Export() (ProtocolState, error)
   121  }
   122  
   123  type ProtocolState interface {
   124  	State
   125  	ProtocolName() string
   126  }
   127  
   128  type Message interface {
   129  	ToInBandMessage() InBandMessage
   130  	ToOutOfBandMessage() OutOfBandMessage
   131  	Marshal() ([]byte, error)
   132  }
   133  
   134  type ReminderSet interface {
   135  	Reminders() []Reminder
   136  	MoreRemindersReady() bool
   137  }
   138  
   139  type ReminderID interface {
   140  	MsgID() MsgID
   141  	UID() UID
   142  	Seqno() int
   143  }
   144  
   145  // MessageConsumer consumes state update messages. It's half of
   146  // the state machine protocol
   147  type MessageConsumer interface {
   148  	// ConsumeMessage is called on a new incoming message to mutate the state
   149  	// of the state machine. Of course messages can be "inband" which actually
   150  	// perform state mutations, or might be "out-of-band" that just use the
   151  	// Gregor broadcast mechanism to make sure that all clients get the
   152  	// notification. It returns a version of the message to broadcast to clients.
   153  	ConsumeMessage(ctx context.Context, m Message) (Message, error)
   154  }
   155  
   156  // StateMachine is the central interface of the Gregor system. Various parts of the
   157  // server and client infrastructure will implement various parts of this interface,
   158  // to ensure that the state machine can be replicated, and that it can be queried.
   159  type StateMachine interface {
   160  	MessageConsumer
   161  
   162  	// State returns the state for the user u on device d at time t.
   163  	// d can be nil, in which case the global state (across all devices)
   164  	// is returned. If t is nil, then use Now, otherwise, return the state
   165  	// at the given time.
   166  	State(ctx context.Context, u UID, d DeviceID, t TimeOrOffset) (State, error)
   167  
   168  	// StateByCategoryPrefix returns the IBMs in the given state that match
   169  	// the given category prefix. It's similar to calling State().ItemsInCategory()
   170  	// but results in less data transfer.
   171  	StateByCategoryPrefix(ctx context.Context, u UID, d DeviceID, t TimeOrOffset, cp Category) (State, error)
   172  
   173  	// IsEphemeral returns whether the backend storage needs to be saved/restored.
   174  	IsEphemeral() bool
   175  
   176  	// InitState iterates through the given State's Items, setting the
   177  	// StateMachine's storage. Note: This should only be called to
   178  	// initialize an ephemeral StateMachine.
   179  	InitState(s State) error
   180  
   181  	// LatestCTime returns the CTime of the newest item for the given user & device.
   182  	LatestCTime(ctx context.Context, u UID, d DeviceID) *time.Time
   183  
   184  	// Clear removes all existing state from the StateMachine.
   185  	Clear() error
   186  
   187  	// InBandMessagesSince returns all messages since the given time
   188  	// for the user u on device d.  If d is nil, then we'll return
   189  	// all messages across all devices.  If d is a device, then we'll
   190  	// return global messages and per-device messages for that device.
   191  	InBandMessagesSince(ctx context.Context, u UID, d DeviceID, t time.Time) ([]InBandMessage, error)
   192  
   193  	// Reminders returns a slice of non-dismissed items past their RemindTimes.
   194  	Reminders(ctx context.Context, maxReminders int) (ReminderSet, error)
   195  
   196  	// DeleteReminder deletes a reminder so it won't be in the queue any longer.
   197  	DeleteReminder(ctx context.Context, r ReminderID) error
   198  
   199  	// ObjFactory returns the ObjFactory used by this StateMachine.
   200  	ObjFactory() ObjFactory
   201  
   202  	// Clock returns the clockwork.Clock used by this StateMachine.
   203  	Clock() clockwork.Clock
   204  
   205  	// How long we lock access to reminders; after this time, it's open to other
   206  	// consumers.
   207  	ReminderLockDuration() time.Duration
   208  
   209  	// Local dismissals for the device this state machine runs on
   210  	LocalDismissals(context.Context, UID) ([]MsgID, error)
   211  
   212  	// Set local dismissals on the state machine storage to the given list
   213  	InitLocalDismissals(context.Context, UID, []MsgID) error
   214  
   215  	// Consume a local dismissal in state machine storage
   216  	ConsumeLocalDismissal(context.Context, UID, MsgID) error
   217  
   218  	// Outbox gives all of the pending messages in the outbox
   219  	Outbox(context.Context, UID) ([]Message, error)
   220  	RemoveFromOutbox(context.Context, UID, MsgID) error
   221  
   222  	// InitOutbox initializes a users outbox with the given messages
   223  	InitOutbox(context.Context, UID, []Message) error
   224  
   225  	// ConsumeOutboxMessage add a message to the outbox
   226  	ConsumeOutboxMessage(context.Context, UID, Message) error
   227  }
   228  
   229  type ObjFactory interface {
   230  	MakeUID(b []byte) (UID, error)
   231  	MakeMsgID(b []byte) (MsgID, error)
   232  	MakeDeviceID(b []byte) (DeviceID, error)
   233  	MakeBody(b []byte) (Body, error)
   234  	MakeCategory(s string) (Category, error)
   235  	MakeItem(u UID, msgid MsgID, deviceid DeviceID, ctime time.Time, c Category, dtime *time.Time, body Body) (Item, error)
   236  	MakeReminder(i Item, seqno int, t time.Time) (Reminder, error)
   237  	MakeReminderID(u UID, msgid MsgID, seqno int) (ReminderID, error)
   238  	MakeDismissalByRange(uid UID, msgid MsgID, devid DeviceID, ctime time.Time, c Category, d time.Time,
   239  		skipMsgIDs []MsgID) (InBandMessage, error)
   240  	MakeDismissalByIDs(uid UID, msgid MsgID, devid DeviceID, ctime time.Time, d []MsgID) (InBandMessage, error)
   241  	MakeStateSyncMessage(uid UID, msgid MsgID, devid DeviceID, ctime time.Time) (InBandMessage, error)
   242  	MakeState(i []Item) (State, error)
   243  	MakeStateWithLookupTable(i []Item, table map[string]Item) (State, error)
   244  	MakeMetadata(uid UID, msgid MsgID, devid DeviceID, ctime time.Time, i InBandMsgType) (Metadata, error)
   245  	MakeInBandMessageFromItem(i Item) (InBandMessage, error)
   246  	MakeMessageFromInBandMessage(i InBandMessage) (Message, error)
   247  	MakeTimeOrOffsetFromTime(t time.Time) (TimeOrOffset, error)
   248  	MakeTimeOrOffsetFromOffset(d time.Duration) (TimeOrOffset, error)
   249  	MakeReminderSetFromReminders([]Reminder, bool) (ReminderSet, error)
   250  	UnmarshalState([]byte) (State, error)
   251  	UnmarshalMessage([]byte) (Message, error)
   252  }
   253  
   254  type MainLoopServer interface {
   255  	ListenLoop(n net.Listener) error
   256  }
   257  
   258  func UIDFromMessage(m Message) UID {
   259  	ibm := m.ToInBandMessage()
   260  	if ibm != nil && ibm.Metadata() != nil {
   261  		return ibm.Metadata().UID()
   262  	}
   263  	if oobm := m.ToOutOfBandMessage(); oobm != nil {
   264  		return oobm.UID()
   265  	}
   266  	return nil
   267  }