package storage import ( "context" "errors" ) // Errors of the admin store. var ( // ErrNoSuchRegistrationToken is an unknown registration token — or, // from UseRegistrationToken, one that is known but expired or used // up. A client is told the same thing either way. ErrNoSuchRegistrationToken = errors.New("no such registration token") // ErrRegistrationTokenExists is CreateRegistrationToken's answer for a // token that is already there. ErrRegistrationTokenExists = errors.New("registration token already exists") // ErrNoServerNoticeRoom is a user who has never been sent a server // notice. ErrNoServerNoticeRoom = errors.New("no server notice room") ) // RegistrationToken is a token made through the admin API. type RegistrationToken struct { Token string // UsesAllowed is how many registrations may spend the token; nil is // no limit. UsesAllowed *int // Completed is how many registrations have spent it. Completed int // ExpiresAtMS is when the token stops working, or 0 for never. ExpiresAtMS int64 CreatedAtMS int64 } // Usable reports whether the token can still be spent at nowMS. func (t RegistrationToken) Usable(nowMS int64) bool { if t.ExpiresAtMS != 0 && t.ExpiresAtMS <= nowMS { return false } return t.UsesAllowed == nil || t.Completed < *t.UsesAllowed } // AuditEntry is one change made through the admin API. type AuditEntry struct { // ID orders the log; it is assigned by AppendAudit. ID int64 TSMS int64 // Actor is the full user ID of the admin. Actor string // Action names what was done, e.g. "user.deactivate". Action string // Target is what it was done to, or empty for a server-wide change. Target string // Details is a JSON object with whatever else is worth keeping: the // new value of a switch, whether a deactivation erased the profile. Details []byte } // AuditFilter narrows and pages the audit log, newest first. type AuditFilter struct { // Before returns entries with an ID below it; 0 starts at the newest. Before int64 // Limit caps the returned entries; 0 means the store's own default. Limit int // Actor and Action, when set, must match exactly. Actor string Action string } // AdminStore keeps the state of the admin API's own: registration tokens, // the room each user's server notices go to, and the audit log. type AdminStore interface { // CreateRegistrationToken stores a new token, returning // ErrRegistrationTokenExists when it is taken. CreateRegistrationToken(ctx context.Context, t RegistrationToken) error // RegistrationToken reads one token. RegistrationToken(ctx context.Context, token string) (RegistrationToken, error) // RegistrationTokens lists every token, ordered by token. RegistrationTokens(ctx context.Context) ([]RegistrationToken, error) // UpdateRegistrationToken replaces a token's use limit and expiry; the // count of uses it has had stays. UpdateRegistrationToken(ctx context.Context, token string, usesAllowed *int, expiresAtMS int64) error // DeleteRegistrationToken removes a token. DeleteRegistrationToken(ctx context.Context, token string) error // UseRegistrationToken spends one use of a token, if it is usable at // nowMS, in a single statement: two registrations racing for the last // use cannot both have it. A token that is not usable is // ErrNoSuchRegistrationToken. UseRegistrationToken(ctx context.Context, token string, nowMS int64) error // ReleaseRegistrationToken gives back a use taken by a registration // that then failed. ReleaseRegistrationToken(ctx context.Context, token string) error // AppendAudit records an entry and returns its ID. AppendAudit(ctx context.Context, e AuditEntry) (int64, error) // AuditLog reads a page of the log, newest first. AuditLog(ctx context.Context, f AuditFilter) ([]AuditEntry, error) // ServerNoticeRoom returns the room a user's server notices go to, // or ErrNoServerNoticeRoom. ServerNoticeRoom(ctx context.Context, localpart string) (string, error) // SetServerNoticeRoom records it, replacing any earlier one. SetServerNoticeRoom(ctx context.Context, localpart, roomID string) error } // AppServiceState is where an application service is in the event stream. type AppServiceState struct { ID string // StreamPos is the last position whose events have been delivered or // skipped. StreamPos int64 // TxnID is the ID of the last transaction begun. While TxnTo is // non-zero that transaction is in flight and holds the events in // (StreamPos, TxnTo]. TxnID int64 TxnTo int64 } // AppServiceStore keeps the application services' delivery cursors. type AppServiceStore interface { // AppServiceState reads an application service's cursor, creating it // at startPos the first time the service is seen: a newly registered // service is sent what happens from now on, not the server's history. AppServiceState(ctx context.Context, id string, startPos int64) (AppServiceState, error) // BeginTransaction records a transaction as in flight. BeginTransaction(ctx context.Context, id string, txnID, to int64) error // CompleteTransaction moves the cursor to `to` and clears the // transaction in flight. It is also how a stretch of the stream with // nothing of interest in it is skipped. CompleteTransaction(ctx context.Context, id string, to int64) error }