using System.Collections.Generic; using System.Threading.Tasks; using NodaTime; namespace PluralKit.Core { public enum AutoproxyMode { Off = 1, Front = 2, Latch = 3, Member = 4 } public class FullMessage { public PKMessage Message; public PKMember Member; public PKSystem System; } public struct PKMessage { public ulong Mid; public ulong? Guild; // null value means "no data" (ie. from before this field being added) public ulong Channel; public ulong Sender; public ulong? OriginalMid; } public struct SwitchListEntry { public ICollection Members; public Instant TimespanStart; public Instant TimespanEnd; } public struct FrontBreakdown { public Dictionary MemberSwitchDurations; public Duration NoFronterDuration; public Instant RangeStart; public Instant RangeEnd; } public struct SwitchMembersListEntry { public MemberId Member; public Instant Timestamp; } public interface IDataStore { /// /// Gets a system by its user-facing human ID. /// /// The with the given human ID, or null if no system was found. Task GetSystemByHid(string systemHid); /// /// Gets a system by one of its linked Discord account IDs. Multiple IDs can return the same system. /// /// The with the given linked account, or null if no system was found. Task GetSystemByAccount(ulong linkedAccount); /// /// Gets a system by its API token. /// /// The with the given API token, or null if no corresponding system was found. Task GetSystemByToken(string apiToken); /// /// Gets the Discord account IDs linked to a system. /// /// An enumerable of Discord account IDs linked to this system. Task> GetSystemAccounts(PKSystem system); /// /// Gets the member count of a system. /// /// Whether the returned count should include private members. Task GetSystemMemberCount(PKSystem system, bool includePrivate); /// /// Gets a list of members with proxy tags that conflict with the given tags. /// /// A set of proxy tags A conflict with proxy tags B if both A's prefix and suffix /// are a "subset" of B's. In other words, if A's prefix *starts* with B's prefix /// and A's suffix *ends* with B's suffix, the tag pairs are considered conflicting. /// /// The system to check in. Task> GetConflictingProxies(PKSystem system, ProxyTag tag); /// /// Creates a system, auto-generating its corresponding IDs. /// /// An optional system name to set. If `null`, will not set a system name. /// The created system model. Task CreateSystem(string systemName); // TODO: throw exception if account is present (when adding) or account isn't present (when removing) /// /// Links a Discord account to a system. /// /// Throws an exception (TODO: which?) if the given account is already linked to a system. Task AddAccount(PKSystem system, ulong accountToAdd); /// /// Unlinks a Discord account from a system. /// /// Will *not* throw if this results in an orphaned system - this is the caller's responsibility to ensure. /// /// Throws an exception (TODO: which?) if the given account is not linked to the given system. Task RemoveAccount(PKSystem system, ulong accountToRemove); /// /// Saves the information within the given struct to the data store. /// Task SaveSystem(PKSystem system); /// /// Deletes the given system from the database. /// /// /// This will also delete all the system's members, all system switches, and every message that has been proxied /// by members in the system. /// Task DeleteSystem(PKSystem system); /// /// Gets a system by its internal member ID. /// /// The with the given internal ID, or null if no member was found. Task GetMemberById(MemberId memberId); /// /// Gets a member by its user-facing human ID. /// /// The with the given human ID, or null if no member was found. Task GetMemberByHid(string memberHid); /// /// Gets a member by its member name within one system. /// /// /// Member names are *usually* unique within a system (but not always), whereas member names /// are almost certainly *not* unique globally - therefore only intra-system lookup is /// allowed. /// /// The with the given name, or null if no member was found. Task GetMemberByName(PKSystem system, string name); /// /// Gets all members inside a given system. /// /// An enumerable of structs representing each member in the system, in no particular order. IAsyncEnumerable GetSystemMembers(PKSystem system, bool orderByName = false); /// /// Creates a member, auto-generating its corresponding IDs. /// /// The system in which to create the member. /// The name of the member to create. /// The created system model. Task CreateMember(PKSystem system, string name); /// /// Saves the information within the given struct to the data store. /// Task SaveMember(PKMember member); /// /// Deletes the given member from the database. /// /// /// This will remove this member from any switches it's involved in, as well as all the messages /// proxied by this member. /// Task DeleteMember(PKMember member); /// /// Gets a message and its information by its ID. /// /// The message ID to look up. This can be either the ID of the trigger message containing the proxy tags or the resulting proxied webhook message. /// An extended message object, containing not only the message data itself but the associated system and member structs. Task GetMessage(ulong id); // id is both original and trigger, also add return type struct /// /// Saves a posted message to the database. /// /// The ID of the account that sent the original trigger message. /// The ID of the guild the message was posted to. /// The ID of the channel the message was posted to. /// The ID of the message posted by the webhook. /// The ID of the original trigger message containing the proxy tags. /// The member (and by extension system) that was proxied. /// Task AddMessage(IPKConnection conn, ulong senderAccount, ulong guildId, ulong channelId, ulong postedMessageId, ulong triggerMessageId, MemberId proxiedMemberId); /// /// Deletes a message from the data store. /// /// The ID of the webhook message to delete. Task DeleteMessage(ulong postedMessageId); /// /// Deletes messages from the data store in bulk. /// /// The IDs of the webhook messages to delete. Task DeleteMessagesBulk(IReadOnlyCollection postedMessageIds); /// /// Gets switches from a system. /// /// An enumerable of the *count* latest switches in the system, in latest-first order. May contain fewer elements than requested. IAsyncEnumerable GetSwitches(PKSystem system); /// /// Gets the total amount of switches in a given system. /// Task GetSwitchCount(PKSystem system); /// /// Gets the latest (temporally; closest to now) switch of a given system. /// Task GetLatestSwitch(PKSystem system); /// /// Gets the members a given switch consists of. /// IAsyncEnumerable GetSwitchMembers(PKSwitch sw); /// /// Gets a list of fronters over a given period of time. /// /// /// This list is returned as an enumerable of "switch members", each containing a timestamp /// and a member ID. /// /// Switches containing multiple members will be returned as multiple switch members each with the same /// timestamp, and a change in timestamp should be interpreted as the start of a new switch. /// /// An enumerable of the aforementioned "switch members". Task> GetPeriodFronters(PKSystem system, Instant periodStart, Instant periodEnd); /// /// Calculates a breakdown of a system's fronters over a given period, including how long each member has /// been fronting, and how long *no* member has been fronting. /// /// /// Switches containing multiple members will count the full switch duration for all members, meaning /// the total duration may add up to longer than the breakdown period. /// /// /// /// /// Task GetFrontBreakdown(PKSystem system, Instant periodStart, Instant periodEnd); /// /// Registers a switch with the given members in the given system. /// /// Throws an exception (TODO: which?) if any of the members are not in the given system. Task AddSwitch(PKSystem system, IEnumerable switchMembers); /// /// Updates the timestamp of a given switch. /// Task MoveSwitch(PKSwitch sw, Instant time); /// /// Deletes a given switch from the data store. /// Task DeleteSwitch(PKSwitch sw); /// /// Deletes all switches in a given system from the data store. /// Task DeleteAllSwitches(PKSystem system); } }