12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- // Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
- // released under the MIT license
-
- package history
-
- import (
- "time"
- )
-
- // Selector represents a parameter to a CHATHISTORY command
- type Selector struct {
- Msgid string
- Time time.Time
- }
-
- // Sequence is an abstract sequence of history entries that can be queried;
- // it encapsulates restrictions such as registration time cutoffs, or
- // only looking at a single "query buffer" (DMs with a particular correspondent)
- type Sequence interface {
- Between(start, end Selector, limit int) (results []Item, err error)
- Around(start Selector, limit int) (results []Item, err error)
-
- ListCorrespondents(start, end Selector, limit int) (results []TargetListing, err error)
-
- // this are weird hacks that violate the encapsulation of Sequence to some extent;
- // Cutoff() returns the cutoff time for other code to use (it returns the zero time
- // if none is set), and Ephemeral() returns whether the backing store is in-memory
- // or a persistent database.
- Cutoff() time.Time
- Ephemeral() bool
- }
-
- // This is a bad, slow implementation of CHATHISTORY AROUND using the BETWEEN semantics
- func GenericAround(seq Sequence, start Selector, limit int) (results []Item, err error) {
- var halfLimit int
- halfLimit = (limit + 1) / 2
- initialResults, err := seq.Between(Selector{}, start, halfLimit)
- if err != nil {
- return
- } else if len(initialResults) == 0 {
- // TODO: this fails if we're doing an AROUND on the first message in the buffer
- // would be nice to fix this but whatever
- return
- }
- newStart := Selector{Time: initialResults[0].Message.Time}
- results, err = seq.Between(newStart, Selector{}, limit)
- return
- }
-
- // MinMaxAsc converts CHATHISTORY arguments into time intervals, handling the most
- // general case (BETWEEN going forwards or backwards) natively and the other ordering
- // queries (AFTER, BEFORE, LATEST) as special cases.
- func MinMaxAsc(after, before, cutoff time.Time) (min, max time.Time, ascending bool) {
- startIsZero, endIsZero := after.IsZero(), before.IsZero()
- if !startIsZero && endIsZero {
- // AFTER
- ascending = true
- } else if startIsZero && !endIsZero {
- // BEFORE
- ascending = false
- } else if !startIsZero && !endIsZero {
- if before.Before(after) {
- // BETWEEN going backwards
- before, after = after, before
- ascending = false
- } else {
- // BETWEEN going forwards
- ascending = true
- }
- } else if startIsZero && endIsZero {
- // LATEST
- ascending = false
- }
- if after.IsZero() || after.Before(cutoff) {
- // this may result in an impossible query, which is fine
- after = cutoff
- }
- return after, before, ascending
- }
|