Documentation
¶
Overview ¶
Package server is dromas-server's HTTP API (PROTOCOL.md §11, the status map in §11.3) over a Store.
Index ¶
- Constants
- Variables
- func AWSLogger(w io.Writer) logging.Logger
- func HTTPServer(addr string, h http.Handler, l Limits, idle time.Duration) *http.Server
- func IsThrottle(err error) bool
- func LimitsFile(l Limits) []byte
- func Migrate(ctx context.Context, url, schema string, l *log.Logger) (applied []int64, version int64, err error)
- func NewAccountID() (string, error)
- func NewAdoptKey(account string) (string, [32]byte, error)
- func OpenValkey(url, password string) (valkey.Client, error)
- func ParseVersionPolicy(b []byte, l Limits) (protocol.ServerDocument, error)
- func ReadVersionPolicy(path string, l Limits) (protocol.ServerDocument, []byte, error)
- func Redacting(w io.Writer) io.Writer
- func SiteBackend(raw string) (*url.URL, error)
- type Account
- type AdoptKey
- type Backend
- type Change
- type ChangeKind
- type Config
- type Cursor
- type Expect
- type Header
- type Indebted
- type Limits
- type Mailbox
- type Memory
- func (s *Memory) Account(ctx context.Context, id string) (*Account, error)
- func (s *Memory) Adopt(ctx context.Context, b *Mailbox, account string, key [32]byte) error
- func (s *Memory) AdoptKey(ctx context.Context, account string, hash [32]byte) (*AdoptKey, error)
- func (s *Memory) After(ctx context.Context, mailbox protocol.Address, c *Cursor) (int, error)
- func (s *Memory) Begin(a protocol.Address) uint64
- func (s *Memory) Changed(a protocol.Address) <-chan struct{}
- func (s *Memory) Count(ctx context.Context, mailbox protocol.Address) (int, error)
- func (s *Memory) CreateAccount(ctx context.Context, a *Account) error
- func (s *Memory) CreateMailbox(ctx context.Context, b *Mailbox) error
- func (s *Memory) DeleteMailbox(ctx context.Context, a protocol.Address) error
- func (s *Memory) DeleteMessage(ctx context.Context, mailbox protocol.Address, id [32]byte) error
- func (s *Memory) DeleteMessages(ctx context.Context, mailbox protocol.Address) error
- func (s *Memory) Fetched(ctx context.Context, mailbox protocol.Address, id [32]byte) (held, again bool, err error)
- func (s *Memory) Header(ctx context.Context, mailbox protocol.Address, id [32]byte) (*Header, error)
- func (s *Memory) Held(a protocol.Address) (Standing, bool)
- func (s *Memory) Holds(ctx context.Context, mailbox protocol.Address, id [32]byte) (bool, error)
- func (s *Memory) Known(a protocol.Address) (*Mailbox, bool)
- func (s *Memory) Leave(ctx context.Context, b *Mailbox) error
- func (s *Memory) List(ctx context.Context, mailbox protocol.Address, after *Cursor, limit int, ...) ([]Header, error)
- func (s *Memory) Mailbox(ctx context.Context, a protocol.Address) (*Mailbox, error)
- func (s *Memory) Message(ctx context.Context, mailbox protocol.Address, id [32]byte, from int64) (*Header, []byte, error)
- func (s *Memory) NextExpiry(a protocol.Address) time.Time
- func (s *Memory) PassHeld(ctx context.Context) error
- func (s *Memory) PutAdoptKey(ctx context.Context, k *AdoptKey) error
- func (s *Memory) PutMessage(ctx context.Context, mailbox protocol.Address, h *Header, body []byte) (*Header, error)
- func (s *Memory) Ready() bool
- func (s *Memory) Reread(ctx context.Context, a protocol.Address) (*Mailbox, error)
- func (s *Memory) Revoke(ctx context.Context, a protocol.Address, rv *Revocations, want Expect) error
- func (s *Memory) Start(ctx context.Context) error
- func (s *Memory) UpdateMailbox(ctx context.Context, b *Mailbox) error
- type Metrics
- type PostgresConfig
- type Reloader
- type Retired
- type Revocations
- type Server
- func (s *Server) AdminHandler() http.Handler
- func (s *Server) ClearAddress(ip string) (key string, cleared []string, ok bool)
- func (s *Server) HTTPServer(addr string, idle time.Duration) *http.Server
- func (s *Server) Handler() http.Handler
- func (s *Server) Limits(path string, read []byte, base Limits) *Reloader
- func (s *Server) StopHolds()
- func (s *Server) Top(name string, n int) (top []Indebted, ok bool)
- func (s *Server) VersionPolicy(path string, read []byte) *Reloader
- type Shard
- type Standing
- type State
- type Store
Constants ¶
const DefaultMailboxCache = 10000
DefaultMailboxCache is how many mailbox records memory holds by default, as many account records, and as many mailboxes remembered as missing.
const MaxLimitsFile = 8 << 10
MaxLimitsFile is the most of a limits file read: four times its every member written with indents and its largest value (TestTheLargestLimitsFileFits).
const MaxVersionPolicy = 28 << 10
MaxVersionPolicy is the most of a version policy file read: a few KiB more than the largest the document's form allows, 64 deprecations and 64 sunsets of the longest versions, written with indents (TestTheLargestPolicyFits).
const ReceiveCeiling = time.Second / 10
ReceiveCeiling is the shortest refill of any mailbox's budget of new messages: no mailbox takes new messages faster than one each, ten a second, whatever its account lifts, and dromas-server serve does not start with flags that would (decided). Every message is a row and a body until it is acked or expires, so the ceiling bounds what one mailbox adds to the store (ARCHITECTURE.md § Storage).
const ReloadEvery = time.Minute
ReloadEvery is how often a Reloader reads its file again.
SharedWait bounds each call to the shared store, which is a round trip to a store in memory beside the processes: past it, the store is slow, and the count is the process's own (sharedBuckets). It is a send's wait at most, beside a send's own write to the database.
Variables ¶
var ( ErrNotFound = errors.New("not found") ErrExists = errors.New("already exists") ErrStale = errors.New("the record changed since it was read") // ErrKeyRefused is an adopt key that is spent, expired or gone. ErrKeyRefused = errors.New("the adopt key is spent, expired or revoked") // ErrUnknown is a write's error that leaves open whether it was // applied: an answer lost, a timeout, a fault of the backend's own, or // any error a backend did not state as a refusal. It wraps the cause. // A count reserved for the write is kept (LIMITS.md rule 4). ErrUnknown = errors.New("the write may have been applied") )
Store errors. A write's error is one of two outcomes (Memory.write): a refusal the store stated, of a write it did not make, which these name (and errNotStored, errRefused, a duplicate); or ErrUnknown, which leaves open whether the write was applied. A write that returns nil was applied.
Functions ¶
func AWSLogger ¶
AWSLogger is the logger for the AWS SDK's own lines, written to w through Redacting: its default writes to stderr apart from the redaction (dromas-dev/dromas-server#72).
func HTTPServer ¶
HTTPServer is the API's HTTP server, at addr, with h as its handler. It reads a request's head in at most l.HeadTimeout and to l.HeadBytes, no further, before any handler sees it, and so before any count (LIMITS.md, rule 1); every request after its head reaches h, OPTIONS * among them, which net/http would otherwise answer itself, uncounted (dromas-dev/dromas-server#75). An idle keep-alive connection is closed after idle.
func IsThrottle ¶
IsThrottle reports whether err is AWS refusing for capacity: a throttle, or the SDK's own retry quota running out.
func LimitsFile ¶ added in v0.5.1
LimitsFile writes l as a limits file, every member in Limits' order, with indents: dromas-server limits default writes DefaultLimits so.
func Migrate ¶ added in v0.5.3
func Migrate(ctx context.Context, url, schema string, l *log.Logger) (applied []int64, version int64, err error)
Migrate brings the database's schema up to date, as dromas-server migrate does: it makes the schema if it is not there and applies, in order, every migration this build holds that the database has not (migrations/), one process of a schema at a time (goose's session lock, keyed by the schema). It runs as the schema's owner, with CREATE on the database, as account does; serve runs as a role that owns nothing (ARCHITECTURE.md § Storage). url is a libpq connection string, empty for libpq's environment; schema, empty, is public. It returns the versions applied, and the schema's version after.
func NewAccountID ¶
NewAccountID returns a minted account id: 16 random bytes, in hex.
func NewAdoptKey ¶
NewAdoptKey returns a new adopt key into account, and the hash it is kept by.
func OpenValkey ¶ added in v0.6.6
OpenValkey is the client of the Valkey at url (valkey://[user@]host:port), with password, when set, as its password: given apart from the URL, so a secret need not sit in a command line or a file that names the store, and refused where the URL carries one too. It is made whether or not the store answers yet: a call to it that fails is counted by the process alone (Config.Valkey), and the client dials again on its next call. A store that answers and refuses the password is an operator's misconfiguration, and refuses the start. A client-side cache is off, since every read must be the store's; retries are off, since a failed call falls back at once.
func ParseVersionPolicy ¶ added in v0.1.6
func ParseVersionPolicy(b []byte, l Limits) (protocol.ServerDocument, error)
ParseVersionPolicy reads b as a version policy file (serve --version-policy): a JSON object in the form GET /v1/ answers (PROTOCOL.md §11.18), its min_version, latest_version, deprecations and sunsets, each optional, and no member else; capabilities are the code's, and max_certificate_lifetime_seconds the setting's, not the policy's. It returns the document the server answers with the policy in force, the setting of l among it, held to the document's form (protocol.ServerDocument.Check). Its errors name a member at most, never a value.
func ReadVersionPolicy ¶ added in v0.1.6
ReadVersionPolicy reads the version policy file at path, to MaxVersionPolicy bytes, and parses it with the limits l (ParseVersionPolicy); it returns the bytes read beside it, for the Reloader that keeps it in force.
Types ¶
type Account ¶
Account is an account's record (PROTOCOL.md §11.16). An account pays, from prepaid credit, for its mailboxes' sends past the free limits and for size over the cap; with no credit they have the free limits. An unmetered account's mailboxes have no daily limit, the largest cap and new messages at ReceiveCeiling, and are never charged: the echo account. Credit is not built yet, so a metered account's mailboxes have the free limits.
type AdoptKey ¶
type AdoptKey struct {
Account string
Hash [32]byte // SHA-256 of the key
Uses int // left
Expires time.Time
}
AdoptKey is what is kept of an adopt key: its hash, never the key (adoptkey.go).
type Backend ¶
type Backend interface {
// ReadAddress reads what is held of address a, strongly consistent:
// its mailbox's record and its identity's revocations, each nil if absent.
ReadAddress(ctx context.Context, a protocol.Address) (*Mailbox, *Revocations, error)
// ReadLive reads a mailbox's live messages, strongly consistent: what a
// mailbox's load counts (Memory.readMailbox).
ReadLive(ctx context.Context, mailbox protocol.Address) ([]Header, error)
// List returns up to limit live headers, oldest first by (ReceivedAt,
// ID), after the given key (nil: from the start); strongly consistent
// where consistent is set.
List(ctx context.Context, mailbox protocol.Address, after *Cursor, limit int, consistent bool) ([]Header, error)
// Message returns a live message and its body, from byte from on where
// from is inside it, above 0 and below its Size, and otherwise whole; or
// ErrNotFound; or errNoBody, with the header, for a live row whose body
// is gone.
Message(ctx context.Context, mailbox protocol.Address, id [32]byte, from int64) (*Header, []byte, error)
// Header returns the header of the live message mailbox holds with this
// id, or ErrNotFound: a message's HEAD, and a send's dedupe, whose
// context carries the sender's pass.
Header(ctx context.Context, mailbox protocol.Address, id [32]byte) (*Header, error)
// PassHeld reads whether ctx's pass still holds: nil, or ErrStale. A
// fetch or an ack of an id memory does not hold reads nothing else.
PassHeld(ctx context.Context) error
// Account reads an account's record, strongly consistent, or returns
// ErrNotFound.
Account(ctx context.Context, id string) (*Account, error)
// AdoptKey reads an adopt key's state, strongly consistent, or returns
// ErrNotFound.
AdoptKey(ctx context.Context, account string, hash [32]byte) (*AdoptKey, error)
// CreateMailbox stores b's record, at b.Rev, if the address has none and
// no revocation of the address, or of certificates through b.Rank, is
// kept; otherwise ErrExists, or ErrStale for a revocation.
CreateMailbox(ctx context.Context, b *Mailbox) error
// UpdateMailbox stores b's record at b.Rev+1 if the stored one is b's, at
// its version (b.Created, b.Rev); otherwise ErrStale. It writes nothing of
// the revocations, and leaves b as it is.
UpdateMailbox(ctx context.Context, b *Mailbox) error
// DeleteMailbox deletes a's record, and keeps its revocations.
DeleteMailbox(ctx context.Context, a protocol.Address) error
// Revoke keeps what the identity of address a revoked (Store.Revoke),
// and returns the address's revocations as they now are, and the version
// its mailbox's record is raised to, zero where it has none: a revocation
// raises its rev, so a write held to the record as read before
// (UpdateMailbox, a send's: sendHeld) is refused. ErrStale if a
// revocation of certificates through as high a serial was stored first,
// or if the address's revocations row is not what want asks: there, or
// not. The row exists only holding a revocation, since none is written
// that holds neither, so that is whether any is held.
Revoke(ctx context.Context, a protocol.Address, rv *Revocations, want Expect) (*Revocations, version, error)
// Adopt moves mailbox b, at its version, into account, spending a use of the
// account's adopt key whose hash is key, in one write: ErrStale,
// ErrKeyRefused.
Adopt(ctx context.Context, b *Mailbox, account string, key [32]byte) error
// Leave takes mailbox b, at its version, out of its account, or returns
// ErrStale.
Leave(ctx context.Context, b *Mailbox) error
// CreateAccount stores a new account at a.Rev, or returns ErrExists.
CreateAccount(ctx context.Context, a *Account) error
// PutAdoptKey stores a new adopt key's state, or returns ErrExists.
PutAdoptKey(ctx context.Context, k *AdoptKey) error
// PutMessage stores a message: its body, then its row. A live row of
// another send of the id refuses it (duplicate).
PutMessage(ctx context.Context, mailbox protocol.Address, h *Header, body []byte) error
// Retire deletes a live message's row, so it leaves the list and
// nothing of it is kept, and returns when it was received; ErrNotFound
// if it is not live, or, where received is not zero, if the live one
// was received at another time: a send of the same bytes since.
Retire(ctx context.Context, mailbox protocol.Address, id [32]byte, received time.Time) (time.Time, error)
// DeleteMessage acks a message: it is retired, then its body goes.
DeleteMessage(ctx context.Context, mailbox protocol.Address, id [32]byte) (time.Time, error)
// DeleteAll deletes, as acks do, every live message in a mailbox, and hands
// each retired as its row is deleted. A message already gone is no
// error.
DeleteAll(ctx context.Context, mailbox protocol.Address, retired func(id [32]byte, received time.Time)) error
// Start hands every change to what the backend keeps, from then on, to
// apply: in order for each row, and at least once. It returns once the
// feed is followed, and the feed ends with ctx.
Start(ctx context.Context, apply func(Change)) error
// Ready reports whether the feed is followed.
Ready() bool
}
Backend is what a store keeps durably, and the change feed of it: the durable operations only. Memory, the one Store, holds over it what a poll needs, and applies to that what each write and each change did (ARCHITECTURE.md § Storage). A backend maps its storage to these operations and their three outcomes, and nothing else: pgBackend (PostgreSQL, bodies in S3 or a directory) and memBackend (maps in this process).
Each write has exactly one of three outcomes, read in one place (Memory.write):
- applied: it returns nil (and what it returns beside);
- refused, as the store stated, of a write it did not make: ErrExists, ErrStale, ErrNotFound, ErrKeyRefused, a send's body not stored (errNotStored), a send that met another's row (duplicate, with that row's header), or errRefused (refused);
- unknown, which may have applied: ErrUnknown, wrapping its cause. Any other error is taken as unknown too.
A call carries in its context what its checks read of memory and relied on (held.go): the pass a call was taken under, which List, Message, Header, PassHeld, Retire, DeleteMessage, UpdateMailbox, Adopt and Leave are held to, and a send's recipient record and sender's pass, which PutMessage is. A call whose standing no longer holds is ErrStale, and reads or changes nothing.
A write of several steps is one operation, whose outcome is its row's write: a send writes its body, then its row, and a body that fails is a refusal, which changed nothing a reader of the list sees; an ack deletes its row, then its body; DeleteAll deletes a mailbox's live rows, hands each to retired, then deletes their bodies. A body left by a crash after its row's delete is an orphan, which goes by age.
type Change ¶
type Change struct {
Kind ChangeKind
// Addr is the record's address, the revocations', or the message's mailbox.
Addr protocol.Address
// AccountID is the account's id.
AccountID string
// Gone is a row deleted.
Gone bool
// Err is a row whose image does not read.
Err error
Mailbox *Mailbox // RecordChange
Revocations *Revocations // RevocationsChange
Header *Header // MessageChange: of a row deleted, its ID alone
Live bool // MessageChange: in the list
Account *Account // AccountChange
}
Change is one change to what a backend keeps, as its feed hands it over: what the row now holds, decoded by the backend, or that it is gone. A row that does not read is carried with Err, and applied as one gone, whatever its kind: memory then holds nothing of it, and its next use reads it again (dromas-dev/dromas-client#407 item 1).
type ChangeKind ¶
type ChangeKind int
ChangeKind is what a Change is a change to.
const ( // RecordChange is a mailbox's record. RecordChange ChangeKind = iota + 1 // RevocationsChange is an address's revocations. RevocationsChange // MessageChange is a message's row. MessageChange // AccountChange is an account's record. AccountChange )
The kinds of change, each with one rule in Memory.apply.
func (ChangeKind) String ¶
func (k ChangeKind) String() string
type Config ¶
type Config struct {
Store Store
Limits Limits
Now func() time.Time // time.Now if nil
Log *log.Logger // no access log if nil
// Ready, when set, reports whether the store has loaded its memory; until
// it has, every call is answered 503 rather than wrong (ARCHITECTURE.md
// § Startup).
Ready func() bool
// TrustedProxies are the peers whose X-Forwarded-For names the client
// (clientIP): behind a reverse proxy every request arrives from the
// proxy's address. From any other peer the header is ignored. None:
// the peer is always the client.
TrustedProxies []netip.Prefix
// Names are the names clients call this server by: the host of its URL,
// lowercase, with a port only when that is neither 80 nor 443. A pass is
// taken only on a request whose Host, written so, is one of them
// (PROTOCOL.md §8). None: any Host
// is taken, which is for the dev server and tests only, since a pass
// made for another server would then pass here.
Names []string
// IdentityTypes are the identity key types this server registers: some
// of protocol.IdentityTypes, ssh-ed25519 among them, since that is the
// one every client makes and verifies (PROTOCOL.md §4.1). None: every type
// this build verifies.
IdentityTypes []string
// SiteBackend, when set, is the web server every request outside /v1/
// and /to/, the API's and the link page's, is passed to (SiteBackend,
// siteProxy). None: those paths are 404.
SiteBackend *url.URL
// Metrics, when set, count what the server does and refuses
// (NewMetrics). None: nothing is counted.
Metrics *Metrics
// Policy is the server's version policy at start (PROTOCOL.md §11.17),
// which GET /v1/ answers with the server's own members and every request
// under /v1/ is held to (versioned), and which its file's Reloader
// replaces (Server.VersionPolicy); its caller holds it to
// protocol.ServerDocument.Check (ReadVersionPolicy). Its
// max_certificate_lifetime_seconds is Limits'. None: no floor, no deprecation,
// no sunset and no latest version.
Policy protocol.ServerDocument
// Shard is the part of the addresses this process answers for, when the
// reverse proxy in front routes each mailbox's calls by its address
// (owned). The zero Shard is every address.
Shard Shard
// Valkey, when set, is the store every process of the deployment
// shares, which keeps each sender's sends a day so that a sender has
// one budget across them (sharedBuckets). None: each process counts its
// own.
Valkey valkey.Client
}
Config configures a Server.
type Expect ¶
type Expect int
Expect is what a conditional write asks of its target as it writes: what a request's If-Match or If-None-Match held of the target at its read (expected; PROTOCOL.md §11.2), so that a change between the two refuses the write, ErrStale, and the request is answered 409 concurrent_modification. It is the write's own condition, beside any other it has, and asks nothing of a request that carried neither.
type Header ¶
type Header struct {
ID [32]byte // SHA-256 of the ciphertext
Size int
ReceivedAt time.Time // to the millisecond
ExpiresAt time.Time
}
Header is one message's metadata: everything but its body.
type Indebted ¶
type Indebted struct {
Key string `json:"key"`
FullIn int64 `json:"full_in"` // seconds, rounded up
}
Indebted is a key a limit holds, and how long until its bucket is full again: the deeper in debt, the longer.
type Limits ¶
type Limits struct {
MaxSize int // the cap on a ciphertext, in bytes, and what a send reads of its body; nothing may depend on its value
MailboxCap int // total per mailbox, a storage ceiling [tunable]
SendsPerDay int // per sender, a number a day: one back each day divided by it, into a bucket of SendsBurst (decided: 50)
SendsBurst int // per sender: the sends it may make at once, the bucket SendsPerDay refills (decided: 60)
PollBurst int // polls a mailbox may make at once (decided: 10); also the fetches of messages already fetched
PollRefill time.Duration // one more poll each (decided: 50 s; once a minute is stated); also one more such fetch
PollAfter int // seconds, told to clients (decided: 60)
MaxWait time.Duration // the longest a list is held, whatever its wait asks (PROTOCOL.md §11.11) [tunable]
MaxLongPolls int // long polls this process holds at once, one a mailbox; past it a long poll of a mailbox that holds none is answered 503 (0: none held) [tunable]
AccountMaxSize int // the most an account lifts MaxSize to, so what a send reads first; up to MaxSize, nothing
RenewalsPerDay int // prekey renewals per mailbox, a number a day as SendsPerDay (decided: 5), so no mailbox's renewals can fill the mailboxes table's writes (each one WAL and a feed change on every process)
RenewalsBurst int // per mailbox: the renewals it may make at once, the bucket RenewalsPerDay refills (decided: 5, as its number a day)
RetiredKept int // retired prekeys a mailbox record keeps for the new-key rule, newest first (decided: 10), so a record stays small
RegistrationsPerHour int // per IPv4 address or IPv6 /64, at once and an hour: a spike limit, which honest use meets once a mailbox (decided: 50, a household standing up dozens of agents at once)
RangeRegistrationsPerHour int // per IPv6 /48, beside the /64's (decided: 500, Let's Encrypt's ratio of the two, until measured)
SendsPerMinutePerIP int // the pre-auth send rate per IP [tunable]
RangeSendsPerMinute int // per IPv6 /48, beside the /64's [tunable]
MissesPerMinute int // per IP: reads of the mailboxes table that find no mailbox, and checks that fail (decided: 10 for now)
RangeMissesPerMinute int // per IPv6 /48, beside the /64's: a last-resort clamp on reads of the mailboxes table that every caller shares (decided: 100, ten /64s' worth; honest calls rarely miss)
MaxLongPollsPerRange int // per IPv4 address or IPv6 /48: long polls held at once, past which a long poll is answered 503 (0: off); a last-resort clamp so one range cannot fill MaxLongPolls, never a limit of normal use (decided: 10,000, ten held mailboxes for each of the thousand subscribers the densest carrier NAT puts behind one address)
// MaxBodiesBeforePass is how many request bodies the calls of one IPv4
// address or IPv6 /64 that are its address's (gate) may have open at
// once, and MaxBodiesBeforePassPerRange of one IPv6 /48: past either,
// 503 (0: off). A body the route reads before any pass is checked (a
// registration's, a renewal's, a revocation's) holds what it has read
// for as long as it takes to arrive (paced), so these bound the memory
// one range holds that way. Last-resort clamps: an honest body arrives
// in about a round trip, and the rate of the calls that send one is
// bounded by the registrations, the renewals and the flood budget, so
// honest use keeps few open at once (decided: 256 and 1,024, about 20 MB
// and 80 MB at the bodies' cap).
MaxBodiesBeforePass int
MaxBodiesBeforePassPerRange int
// Requests is the flood budget of an IPv4 address or IPv6 /64: every call
// with no pass and every request no route matches (decided: 100 at once,
// 50 a second).
RequestBurst int
RequestRefill time.Duration
// RangeRequests is the flood budget of an IPv6 /48, beside the /64's: a
// last-resort clamp, each call it counts up to two signature checks
// (decided: 2,000 at once, 1,000 a second, twenty /64s' worth).
RangeRequestBurst int
RangeRequestRefill time.Duration
// Budgets: a burst at once and one more each refill (LIMITS.md).
ReceiveBurst int // per mailbox: new messages it takes, from all senders together (decided: 50, on, and never off: ReceiveCeiling)
ReceiveRefill time.Duration // (decided: 6 s, ten a minute; never shorter than ReceiveCeiling, which an account lifts it to)
DrainBurst int // per mailbox: its first fetches of held messages, spent only by its own calls (decided: 50, on); an account lifts it
DrainRefill time.Duration // (decided: 6 s, ten a minute)
CallBurst int // per mailbox: its calls with its pass that no other budget counts [tunable]; an account lifts it
CallRefill time.Duration // [tunable]
CertificatesPerDay int // per mailbox, a number a day: renewals under a later certificate, but for one that replaces a revoked certificate (decided: 5, as renewals)
CertificateRevocationsPerDay int // per mailbox, a number a day: raises of its revocation of certificates (decided: a count of its own, apart from CertificatesPerDay; 10) [tunable]
CertificatesBurst int // per mailbox: the bucket CertificatesPerDay refills (decided: 5, as its number a day)
CertificateRevocationsBurst int // per mailbox: the bucket CertificateRevocationsPerDay refills (decided: 10, as its number a day) [tunable]
// MaxCertificateLifetime is the longest a certificate the server takes
// when it first takes one may run, its valid-before less its valid-after
// (PROTOCOL.md §11.7), in whole seconds: served as
// max_certificate_lifetime_seconds in the server's document (§11.18). A renewal
// under the mailbox's current certificate is not held to it. It must be
// above protocol.TTL and protocol.MaxSkew together and at most
// protocol.MaxCertificateLifetime, or dromas-server serve does not start:
// a client signs no message under a certificate with the TTL or less left,
// and dates one the hour back, and every verifier refuses a longer one
// (decided: the protocol's maximum, 45 days and the hour).
MaxCertificateLifetime time.Duration
// ACLEntries is the most entries a mailbox's ACL holds, its two lists
// together [tunable]: a mailbox's record, with its ACL, is held in the mailbox
// cache, so this bounds what one record costs memory there. Never off,
// and at most protocol.MaxACLEntries: dromas-server serve does not start
// otherwise.
ACLEntries int
// How long a body may take: BodyTimeout, and one second more for each
// BodyMinRate bytes its handler reads, as Apache's RequestReadTimeout
// counts; each write of a response the same, for the bytes of it already
// written. A body that stops coming is cut off after BodyTimeout. What the
// server drains of a body after its handler has what the handler's reads
// left, and the answer's time runs from the end of the drain (paced). It
// is also the longest a send waits for the one large read.
BodyTimeout time.Duration // [tunable]
BodyMinRate int // bytes a second [tunable]
// HeadBytes is the most of a request's head, its request line and its
// headers, that the server reads (http.Server.MaxHeaderBytes): what the
// longest call needs, a pass of protocol.MaxPassAuthorization bytes
// with the request line and the other headers a client and a proxy in
// front of it send, and no more (decided: least need). Its default
// follows the longest pass (headBytes).
// A head is read before any count, since the address a call is counted
// by may be one of its headers (LIMITS.md, rule 1).
HeadBytes int
// HeadTimeout is how long a request's head may take to arrive
// (http.Server.ReadHeaderTimeout), before any handler sees it.
HeadTimeout time.Duration
}
Limits are the server's numbers. Decided ones are marked; the rest are tunables, and a zero turns that limit off.
func DefaultLimits ¶
func DefaultLimits() Limits
DefaultLimits are the decided numbers, and the proposed values of the tunables that have one. Tunables with no proposed value are off.
func ParseLimits ¶ added in v0.5.1
ParseLimits reads b as a limits file laid over base: each member it holds replaces its field, and every other field is base's, the startup-only ones among them. It returns the limits held to Limits.Check. Its errors name a member at most, never a value.
func ReadLimits ¶ added in v0.5.1
ReadLimits reads the limits file at path, to MaxLimitsFile bytes, laid over base (ParseLimits); it returns the bytes read beside it, for the Reloader that keeps it in force.
func (Limits) Check ¶ added in v0.5.1
Check refuses limits the server cannot run under, naming the limits file's member: a cap on a ciphertext the protocol does not allow, a budget of new messages past ReceiveCeiling, a number a day whose bucket holds nothing, a longest certificate that signs no message or that no reader takes, and a bound on an ACL that is off or past the protocol's.
type Mailbox ¶ added in v0.1.5
type Mailbox struct {
Addr protocol.Address
Identity []byte // the identity document, exactly as registered or as the revocations carried it
State State
// The current prekey: its statement, its signer's signature over it,
// which carries the signing key, and the statement parsed.
Statement []byte
Signature []byte
Prekey *protocol.Prekey
// The current statement's signer (PROTOCOL.md §5): its rank, 0 for the
// identity and a certificate's serial for a working key, and the SHA-256
// of its signing key's wire bytes, the identity's key or the certificate.
// A pass is taken only by it or the identity, and a prekey only by it or a
// signer of a higher rank. A mailbox's statements are ordered by this rank first, and
// by the prekey's own serial second.
Rank uint64
Signer [32]byte
// SenderKeyTypes is what the mailbox declared with its current prekey: the
// optional identity key types it takes senders of (PROTOCOL.md §7), of those
// this build verifies (protocol.Declaration). A sender of a type §4.1
// defines needs no declaration.
SenderKeyTypes []string
// Retired holds the newest retired prekeys (Limits.RetiredKept), each
// until its not_after: its key may not come back.
Retired []Retired
Rev uint64 // the record's revision, 0 with no record; a write must name the one it read
Created time.Time
// Expires is when the record may go: the sweep deletes it some time
// after (PROTOCOL.md §13). Every registration and renewal raises it to
// when nothing the mailbox has published is valid any more, and nothing
// lowers it (keep). Zero: never.
Expires time.Time
// Account is the account the mailbox belongs to, or "" (PROTOCOL.md §11.16).
// Only Adopt and Leave change it.
Account string
// What the identity revoked, from the address's revocations row
// (Revocations): kept for good and served to whoever asks.
//
// Revocation is the identity's signature that revoked the address
// (PROTOCOL.md §10.1): nil unless State is Revoked. With Identity it
// proves itself, so nobody takes this server's word that the mailbox is
// revoked.
Revocation []byte
// RevokedCerts is the identity's highest revocation of its certificates,
// exactly as it signed it, and RevokedCertsSig its signature
// (PROTOCOL.md §10.2): nil until one is published. The address goes on.
// Served with Identity to whoever asks, it proves itself as Revocation
// does. It was verified when it was stored, and only one through a higher
// serial replaces it.
RevokedCerts []byte
RevokedCertsSig []byte
// ACL is the mailbox's sender ACL (PROTOCOL.md §11.14): who may send to it,
// deny read first and then allow. nil until the mailbox puts one, and a mailbox
// with none takes messages from everyone. It is replaced whole, and never
// removed.
ACL *protocol.ACL
}
Mailbox is what a server holds of an address: its mailbox's record, if it has one, and what its identity revoked, if anything, which is kept in a row of its own (Revocations) with or without a mailbox. A revocation of the address is the State whatever the record says.
type Memory ¶
type Memory struct {
// contains filtered or unexported fields
}
Memory is the store: what this process holds in memory, over a Backend that holds the durable state (ARCHITECTURE.md § Memory). What a poll needs lives here (index), loaded per mailbox on its first use, and bounded caches of mailbox and account records serve sends and reads of a mailbox (recCache). Every write goes through one function (write), which applies its outcome, and every change the backend's feed hands over goes through one (apply). It is the one implementation of Store, whatever the backend: NewPostgresStore and NewMemStore make it.
func NewMemStore ¶
NewMemStore returns the dev server's store: Memory over a backend of maps in this process (memBackend), on the given clock, nothing persisted. Memory follows its feed from the start.
func NewPostgresStore ¶ added in v0.5.3
func NewPostgresStore(ctx context.Context, c PostgresConfig) (*Memory, error)
NewPostgresStore returns the store over PostgreSQL: Memory over the PostgreSQL backend, on a schema Migrate has brought up to date, not ready until Start returns. The pool is closed when ctx ends.
func (*Memory) Account ¶
Account implements Store: the cache, or a strongly consistent read, so a change made before it is in it (one made after reaches the cache by the feed, or, where it was counted after the read's token, keeps the fill out: recCache.fill).
func (*Memory) AdoptKey ¶
AdoptKey implements Store: a strongly consistent read, so a key just made is found.
func (*Memory) After ¶
After implements Store: from memory, after the mailbox's load on its first use.
func (*Memory) Changed ¶
Changed returns a channel closed at mailbox a's next change in memory (Store.Changed).
func (*Memory) Count ¶
Count implements Store: from memory, after the mailbox's load on its first use.
func (*Memory) CreateAccount ¶
CreateAccount implements Store.
func (*Memory) CreateMailbox ¶ added in v0.1.5
CreateMailbox implements Store.
func (*Memory) DeleteMailbox ¶ added in v0.1.5
DeleteMailbox implements Store.
func (*Memory) DeleteMessage ¶
DeleteMessage implements Store (ack): the row, then the body. A crash between them leaves a body no row names, which goes by age.
func (*Memory) DeleteMessages ¶
DeleteMessages implements Store (a revocation): every live message in the mailbox, as acks, each out of memory as its row is deleted.
func (*Memory) Fetched ¶
func (s *Memory) Fetched(ctx context.Context, mailbox protocol.Address, id [32]byte) (held, again bool, err error)
Fetched implements Store, from memory as Holds does.
func (*Memory) Header ¶ added in v0.5.6
func (s *Memory) Header(ctx context.Context, mailbox protocol.Address, id [32]byte) (*Header, error)
Header implements Store: the live message's row, held to ctx's pass. A stale miss of a send's dedupe is caught by PutMessage's conditional write.
func (*Memory) Holds ¶
Holds implements Store: from memory, after the mailbox's load on its first use. A message another process stored is held once the feed has brought it.
func (*Memory) Known ¶
Known implements Store: the record cache, or the memory of a mailbox a read did not find.
func (*Memory) List ¶
func (s *Memory) List(ctx context.Context, mailbox protocol.Address, after *Cursor, limit int, consistent bool) ([]Header, error)
List implements Store: the backend's page. consistent asks for a read strongly consistent, as a long poll's must be, which no later change may wake (Server.list); both backends here read every page as committed, and ignore it.
func (*Memory) Mailbox ¶ added in v0.1.5
Mailbox implements Store: the cache, or a read. An address the read finds nothing of is remembered as missing for a while (missCache), so naming it again costs no read. The read fills the cache, so it is strongly consistent, as a mailbox's load is: a write made before it is in it, and one made after reaches the cache by the feed, or, where it was counted after the read's token, keeps the fill out (recCache.fill, missed).
func (*Memory) Message ¶
func (s *Memory) Message(ctx context.Context, mailbox protocol.Address, id [32]byte, from int64) (*Header, []byte, error)
Message implements Store. A live message whose body is gone (errNoBody) is retired and answered as gone.
func (*Memory) NextExpiry ¶ added in v0.1.3
NextExpiry implements Store, from the index.
func (*Memory) PutAdoptKey ¶
PutAdoptKey implements Store. Memory holds no adopt key.
func (*Memory) PutMessage ¶
func (s *Memory) PutMessage(ctx context.Context, mailbox protocol.Address, h *Header, body []byte) (*Header, error)
PutMessage implements Store: stored, the message's mark joins memory; met by another send's live row of the same ciphertext, that row's header is returned.
func (*Memory) Reread ¶ added in v0.6.1
Reread implements Store. An address it finds nothing of is not remembered as missing: memory may hold a record the feed has yet to bring the delete of.
func (*Memory) Revoke ¶
func (s *Memory) Revoke(ctx context.Context, a protocol.Address, rv *Revocations, want Expect) error
Revoke implements Store. The record's version the revocation raised is applied to the copy memory holds of it, where that copy is of the same record, made at the same time: it is kept where it holds that rev or a later one already, the feed's echo of the revocation having reached it first, raised where it holds the rev before, and forgotten otherwise (Backend.Revoke). A copy of a record made at another time is of another record of the address, whatever its rev (version), and is forgotten; so is any record memory holds where the backend found none (version zero), the sweep having taken it.
func (*Memory) Start ¶
Start follows the backend's feed: from then on every change it hands over is applied (apply). Memory starts empty, and a mailbox is loaded on its first use, after the feed is followed: a change made before its load is in the load, one made after reaches memory by the feed, or both; applying it twice is harmless but for the cases ARCHITECTURE.md § The in-process plan, rule 5, names, each wrong only until the changes after it on the feed are applied (§ Startup). Nothing is kept across restarts.
type Metrics ¶
type Metrics struct {
// contains filtered or unexported fields
}
Metrics count what this server does and refuses, for its operator (dromas-dev/dromas-server#59; ARCHITECTURE.md § Metrics), as Prometheus counts a service: its requests, errors and latency, every failure beside its attempts. They are served on a listener of their own (dromas-server serve --metrics-listen), never the API's.
No label is a value a caller chooses: no address, IP, mailbox, message id, cursor or path as sent, each of which would be a series per caller and is what the logs leave out. Every label is from a set this code defines: a route is the router's pattern, a code the protocol's, a limit the name a refusal gives it. A nil *Metrics counts nothing.
func NewMetrics ¶
func NewMetrics(reg prometheus.Registerer) *Metrics
NewMetrics makes the server's metrics and registers them with reg.
func (*Metrics) ConnState ¶
ConnState counts the API listener's open connections, as http.Server's ConnState.
func (*Metrics) InstrumentAWS ¶
InstrumentAWS counts and times every call the clients made from cfg make, each with its retries, by service, operation and outcome.
type PostgresConfig ¶ added in v0.5.3
type PostgresConfig struct {
// URL is a libpq connection string, a URL or key=value pairs; empty,
// the database is found as libpq finds one, by its environment
// (PGHOST, PGDATABASE, PGUSER, PGPASSWORD, PGSERVICE and the rest),
// which is how dromas-server serve finds it.
URL string
// Schema holds the tables, and names the publication the feed reads
// (publicationName); empty: public.
Schema string
// Bodies are kept in a bucket, through AWS, or under the data
// directory, in its bodies/ (dataBodies): one of the two, or neither for
// a store that keeps no messages (the operator's account commands).
AWS aws.Config
Bucket string
DataDir string
Now func() time.Time // time.Now if nil
// MailboxCache is how many mailbox records memory holds, as many account
// records, and as many mailboxes remembered as missing; 0: none.
MailboxCache int
// MaxConns bounds the pool; 0: pgxpool's default.
MaxConns int32
Log *log.Logger // nil: no log
// Fatal is called if the feed loses its place. Memory can no longer be
// shown current; the process must restart, which rebuilds it from the
// tables.
Fatal func(error)
// SweepInterval is how often expired rows are deleted, and bodies on
// disk collected; 0: never. SweepGrace is how long past its expiry a
// row is kept.
SweepInterval, SweepGrace time.Duration
// SyncInterval is how often the feed shows itself current (postgres_feed.go);
// 0: feedSyncEvery.
SyncInterval time.Duration
// Metrics, if set, count the caches' hits, misses and evictions, and how
// far behind the feed memory follows.
Metrics *Metrics
}
PostgresConfig configures a store over PostgreSQL.
type Reloader ¶ added in v0.1.6
type Reloader struct {
// contains filtered or unexported fields
}
Reloader keeps what one runtime file says in force: it reads the file again on each signal and each interval (Run), and applies what it reads where its bytes differ from the last read, or on a signal whatever they are. A read that fails, a file larger than its bound, or one apply refuses keeps what is in force, is logged in one line naming the file's path and why, never its contents, and counted failed in dromas_server_runtime_config_reloads_total, by the file's name.
type Retired ¶
type Retired struct {
Type protocol.KeyType
NotAfter time.Time
KeyHash [32]byte // SHA-256 of the age recipient
}
Retired is what is kept of a retired prekey while it is live.
type Revocations ¶
type Revocations struct {
Identity []byte
// Address is the identity's signature that revoked the address, or nil.
Address []byte
// Certs and CertsSig are its highest revocation of its certificates, or
// nil; Through is the serial it revokes through, 0 with none.
Certs, CertsSig []byte
Through uint64
}
Revocations is what an address's identity has revoked, as kept in a row of its own beside the mailbox's record, mailbox or none (PROTOCOL.md §10.1, §10.2): the revocation of the address once, and the highest revocation of its certificates. Nothing in it is ever taken away, so two copies merge to the larger of each.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the API.
func (*Server) AdminHandler ¶
AdminHandler is the operator's interface:
- POST /limits/clear?ip=<address> answers {"address":"<the key cleared>","cleared":[<the limits that held anything of it>]} (ClearAddress);
- GET /limits/top?limit=<name>&n=<count> answers {"limit":"<name>", "keys":[{"key":"<a mailbox or an address>","full_in":<seconds>}]}, deepest in debt first (Top).
func (*Server) ClearAddress ¶
ClearAddress forgets what the limits keyed by a caller's address hold of ip, by its IPv4 address or IPv6 /64 and by its IPv6 /48: its misses, its registrations, its sends before their pass and its calls with no checked pass, each bucket full again as if the address had never been seen. ip is an IPv4 address or any IPv6 address of a /64, with or without a zone, which is how the limits key a caller (ipKey). It returns that key and the names of the limits that held anything of it, and false if ip is no address.
func (*Server) HTTPServer ¶ added in v0.1.3
HTTPServer is the API's HTTP server for s, at addr: HTTPServer with s's handler and limits, which answers every list s holds 304 at once when it shuts down (StopHolds, by http.Server.RegisterOnShutdown), so its clients list again at once and Shutdown waits for none of them.
func (*Server) Handler ¶
Handler returns the API's routes, the page a mailbox's link opens, and the site, if there is one. Every answer is paced, and every request is counted before anything is done for it (LIMITS.md, rule 1): each handler is put on its router by mount, through the gate, and a request no route answers is counted instead by unrouted. Both pages are answered before the API is ready, since neither reads a store. Every request under /v1/ is held to the version policy first (versioned): one of a retired version is counted and answered there, before any route is matched.
func (*Server) Limits ¶ added in v0.5.1
Limits is the Reloader of s's limits from the file at path, laid over base (the defaults with serve's startup-only flags), whose bytes read at start were read: each file it reads that holds replaces the limits in force at once, for the next request, every bucket keeping its keys.
func (*Server) StopHolds ¶
func (s *Server) StopHolds()
StopHolds answers every long poll, now and from now on, at once: for http.Server.RegisterOnShutdown, so the clients list again at once and Shutdown waits for none of them.
func (*Server) Top ¶
Top returns, for the limit named name, the n keys it holds deepest in debt now, deepest first: which mailboxes or addresses spend it most. It reads memory and keeps nothing (dromas-dev/dromas-server#59). ok is false for a name that is no limit's.
func (*Server) VersionPolicy ¶ added in v0.1.6
VersionPolicy is the Reloader of s's version policy from the file at path, whose bytes read at start were read: each policy it reads that parses replaces the one in force at once, for the next request.
type Shard ¶ added in v0.5.3
type Shard struct{ I, N int }
Shard is the part of the addresses one process answers for, when the reverse proxy in front sends each mailbox's calls to one process by its address (ARCHITECTURE.md § Routing by address). An address is "d_" and base64url of a SHA-384, so its first character after "d_" is uniform over base64url's 64 values: shard I of N, N a power of two up to 64 and I from 1 to N, is the characters whose value v has v*N/64 == I-1, v being the top six bits of the address's first byte. Shards of different N may sit side by side, so one half splits into two quarters with the other half untouched. The zero Shard is every address.
func ParseShard ¶ added in v0.5.3
ParseShard reads a shard written "I/N" (Shard.String); "" is every address.
type Standing ¶
type Standing struct {
State State
Key string // the identity's key in SSH wire form, of whatever type: what line 2 of its document holds
Signer [32]byte // Mailbox.Signer
// Rank is Mailbox.Rank, which Listed is judged by.
Rank uint64
// Listed is true while the revocation of certificates held covers the
// mailbox's current signer (PROTOCOL.md §10.2): a certificate at or below
// it, never the identity. Only the identity's pass is taken until the
// mailbox publishes a prekey under a certificate above it.
Listed bool
// InAccount is true for a mailbox in an account, whose limits are read from
// it; a mailbox in none has the server's, with nothing to read.
InAccount bool
}
Standing is what checking a mailbox's pass needs of it (PROTOCOL.md §8): its state, its identity's public key, which signer is its current one, and whether its identity's revocation of certificates covers that signer.
type State ¶
type State string
State is what a server holds of an address (PROTOCOL.md §11.6). A mailbox's record is Active, the one state a record is written in or read back as; Revoked and NoMailbox are what the store answers from the address's revocations alone.
const ( // Active is a registered mailbox. Active State = "active" // Revoked is an address its identity revoked. Its record is deleted, // and the revocation is kept for good. Revoked State = "revoked" // NoMailbox is an address with no mailbox whose identity revoked certificates: // a later registration is held above them. NoMailbox State = "none" )
The states.
type Store ¶
type Store interface {
// Held returns the standing of a mailbox memory holds, with no read. ok is
// false for a mailbox this process has not loaded, which only its record
// answers for: Known, then Mailbox (ARCHITECTURE.md § Memory).
Held(a protocol.Address) (st Standing, ok bool)
// Changed returns a channel closed at mailbox a's next change in memory, by
// a write of this process or one the feed brings: what a long poll
// waits on (PROTOCOL.md §11.11). It reads nothing.
Changed(a protocol.Address) <-chan struct{}
// NextExpiry returns when the first of mailbox a's messages in memory
// expires, by the store's clock, with no read: past, for one that
// expired since the mailbox was last read; zero for a mailbox with none, or one
// memory has not loaded. An expiry is no change memory applies, so a
// long poll waits until it, and no longer (PROTOCOL.md §11.11).
NextExpiry(a protocol.Address) time.Time
// Mailbox returns what is held of an address (view): its mailbox's record and
// its identity's revocations, or ErrNotFound if neither.
Mailbox(ctx context.Context, a protocol.Address) (*Mailbox, error)
// Reread is Mailbox's read, made whatever memory holds of the address,
// for a call that has shown memory to be behind: it fills the record
// cache as Mailbox does, so memory's copy moves forward and never back
// (recCache.fill), and a write during the read keeps the fill out.
Reread(ctx context.Context, a protocol.Address) (*Mailbox, error)
// Known returns what memory holds of an address, with no read: what Mailbox
// returns, or nil for an address it holds as missing. ok is false when
// only a read can tell, which is what Mailbox then does.
Known(a protocol.Address) (b *Mailbox, ok bool)
// Begin returns a token of address a, which only grows: what Mailbox
// answers once it is taken holds every write this process applied to a
// before it.
Begin(a protocol.Address) uint64
// CreateMailbox stores a new mailbox's record at Rev 1, or returns ErrExists if
// the address has one.
CreateMailbox(ctx context.Context, b *Mailbox) error
// UpdateMailbox stores b's record if the stored one is still b's, at its
// version (b.Created, b.Rev), and bumps b.Rev; otherwise ErrStale. It
// writes nothing of the revocations.
UpdateMailbox(ctx context.Context, b *Mailbox) error
// DeleteMailbox deletes a's record, and keeps its revocations.
DeleteMailbox(ctx context.Context, a protocol.Address) error
// Revoke keeps what the identity of address a revoked, mailbox or none, in
// the address's revocations row: rv's revocation of the address, kept
// once, and its revocation of certificates, which only one through a
// higher serial replaces: ErrStale if one through as high a serial was
// stored first, or if the address's revocations are not what want asks
// of them, some held or none.
Revoke(ctx context.Context, a protocol.Address, rv *Revocations, want Expect) error
// Header returns the header of the live message mailbox holds with this
// id, or ErrNotFound: nothing is kept of one acked or expired. It is held
// to ctx's pass, where it carries one (ErrStale): the mailbox's own on a
// message's HEAD, the sender's on a send's dedupe.
Header(ctx context.Context, mailbox protocol.Address, id [32]byte) (*Header, error)
// PassHeld reads whether ctx's pass still holds, in one statement: nil,
// or ErrStale, and memory forgets the pass's address. What a fetch or an
// ack of an id memory does not hold is held to.
PassHeld(ctx context.Context) error
// PutMessage stores a message: its body, then its header. If a live
// message of the id appeared first, it returns that one's header
// instead.
PutMessage(ctx context.Context, mailbox protocol.Address, h *Header, body []byte) (*Header, error)
// List returns up to limit live headers, oldest first by (ReceivedAt,
// ID), after the given key (nil: from the start). Consistent reads them
// strongly consistent: every write applied to memory before the read is
// in the page.
List(ctx context.Context, mailbox protocol.Address, after *Cursor, limit int, consistent bool) ([]Header, error)
// Message returns a live message and its body, or ErrNotFound: the body
// from byte from on where from is inside it, above 0 and below its Size,
// and otherwise whole, as a fetch answers a range (PROTOCOL.md §11.12).
// So a fetch that resumes reads only the rest from where a body is kept.
Message(ctx context.Context, mailbox protocol.Address, id [32]byte, from int64) (*Header, []byte, error)
// DeleteMessage acks a message: its body goes, then its row, and
// nothing of it is kept (PROTOCOL.md §13). ErrNotFound if it is not
// live.
DeleteMessage(ctx context.Context, mailbox protocol.Address, id [32]byte) error
// DeleteMessages deletes every live message in a mailbox, as acks do (a
// revocation of its address). A message already gone is no error.
DeleteMessages(ctx context.Context, mailbox protocol.Address) error
// Account returns an account's record, or ErrNotFound: read on its
// first use, then answered from memory.
Account(ctx context.Context, id string) (*Account, error)
// CreateAccount stores a new account at Rev 1, or returns ErrExists.
CreateAccount(ctx context.Context, a *Account) error
// PutAdoptKey stores a new adopt key's state, or returns ErrExists.
PutAdoptKey(ctx context.Context, k *AdoptKey) error
// AdoptKey returns the state of account's adopt key whose hash is given,
// or ErrNotFound. It reads it strongly consistent, so a key just made is
// found.
AdoptKey(ctx context.Context, account string, hash [32]byte) (*AdoptKey, error)
// Adopt moves mailbox b, as read, into account, spending a use of account's
// adopt key whose hash is given, in one write: ErrStale if the record
// changed or is another, ErrKeyRefused if the key is spent, expired or gone. It sets
// b.Account and bumps b.Rev.
Adopt(ctx context.Context, b *Mailbox, account string, key [32]byte) error
// Leave takes mailbox b, as read, out of its account, or returns ErrStale.
// It clears b.Account and bumps b.Rev.
Leave(ctx context.Context, b *Mailbox) error
// Count returns the number of live messages in a mailbox, from memory: the
// mailbox is loaded on its first use, and answered from memory after that.
Count(ctx context.Context, mailbox protocol.Address) (n int, err error)
// After returns how many live messages a mailbox holds past a list position,
// from memory as Count does: what a list from that cursor would return.
After(ctx context.Context, mailbox protocol.Address, c *Cursor) (int, error)
// Holds reports whether a mailbox holds a live message with this id, from
// memory as Count does. False is certain; true may be another message
// whose id starts alike, so the caller still reads it.
Holds(ctx context.Context, mailbox protocol.Address, id [32]byte) (bool, error)
// Fetched is Holds for a fetch: it also reports whether this process has
// served the message before, and counts this serving. The count lives
// with the message in memory, so a restart forgets it.
Fetched(ctx context.Context, mailbox protocol.Address, id [32]byte) (held, again bool, err error)
}
Store is the server's state: mailbox records, message headers and bodies, and what a poll needs of them in memory. Its one implementation is Memory, over a Backend: PostgreSQL (NewPostgresStore), or maps in this process (NewMemStore, the dev server).
Source Files
¶
- accounts.go
- acl.go
- admin.go
- adoptkey.go
- backend.go
- bodies.go
- boxcache.go
- boxes.go
- compress.go
- conditions.go
- held.go
- index.go
- limits.go
- limitsfile.go
- link.go
- memory.go
- memstore.go
- messages.go
- metrics.go
- migrate.go
- pass.go
- postgres.go
- postgres_feed.go
- postgres_sweep.go
- problem.go
- runtimeconfig.go
- send.go
- server.go
- shard.go
- shared.go
- site.go
- store.go
- version.go