141 lines
5.9 KiB
Forth
141 lines
5.9 KiB
Forth
module Degenz.Messaging
|
|
|
|
open System
|
|
open System.Threading.Tasks
|
|
open DSharpPlus
|
|
open DSharpPlus.Entities
|
|
open DSharpPlus.EventArgs
|
|
open DSharpPlus.SlashCommands
|
|
|
|
type InteractiveMessage = {
|
|
ButtonId : string
|
|
ButtonText : string
|
|
Message : string
|
|
}
|
|
|
|
type DiscordContext =
|
|
| Interaction of InteractionContext
|
|
| Event of ComponentInteractionCreateEventArgs
|
|
|
|
type IDiscordContext =
|
|
abstract member Respond : InteractionResponseType -> Task
|
|
abstract member Respond : InteractionResponseType * DiscordInteractionResponseBuilder -> Task
|
|
abstract member FollowUp : DiscordFollowupMessageBuilder -> Task
|
|
abstract member GetDiscordMember : unit -> DiscordMember
|
|
abstract member GetGuild : unit -> DiscordGuild
|
|
abstract member GetInteraction : unit -> DiscordInteraction
|
|
abstract member GetInteractionId : unit -> string
|
|
abstract member GetChannel : unit -> DiscordChannel
|
|
abstract member GetContext : unit -> obj
|
|
|
|
type DiscordInteractionContext(ctx : InteractionContext) =
|
|
interface IDiscordContext with
|
|
member this.Respond responseType =
|
|
async {
|
|
do! ctx.Interaction.CreateResponseAsync(responseType) |> Async.AwaitTask
|
|
} |> Async.StartAsTask :> Task
|
|
member this.Respond (responseType, builder) =
|
|
async {
|
|
do! ctx.Interaction.CreateResponseAsync(responseType, builder) |> Async.AwaitTask
|
|
} |> Async.StartAsTask :> Task
|
|
member this.FollowUp(builder) =
|
|
async {
|
|
do! ctx.Interaction.CreateFollowupMessageAsync(builder) |> Async.AwaitTask |> Async.Ignore
|
|
} |> Async.StartAsTask :> Task
|
|
member this.GetDiscordMember() = ctx.Member
|
|
member this.GetGuild() = ctx.Guild
|
|
member this.GetInteraction() = ctx.Interaction
|
|
member this.GetInteractionId() = string ctx.InteractionId
|
|
member this.GetChannel() = ctx.Channel
|
|
member this.GetContext() = ctx
|
|
|
|
type DiscordEventContext(ctx : ComponentInteractionCreateEventArgs) =
|
|
interface IDiscordContext with
|
|
member this.Respond responseType =
|
|
async {
|
|
do! ctx.Interaction.CreateResponseAsync(responseType) |> Async.AwaitTask
|
|
} |> Async.StartAsTask :> Task
|
|
member this.Respond (responseType, builder) =
|
|
async {
|
|
do! ctx.Interaction.CreateResponseAsync(responseType, builder) |> Async.AwaitTask
|
|
} |> Async.StartAsTask :> Task
|
|
member this.FollowUp(builder) =
|
|
async {
|
|
do! ctx.Interaction.CreateFollowupMessageAsync(builder) |> Async.AwaitTask |> Async.Ignore
|
|
} |> Async.StartAsTask :> Task
|
|
member this.GetDiscordMember() = ctx.User :?> DiscordMember
|
|
member this.GetGuild() = ctx.Guild
|
|
member this.GetInteraction() = ctx.Interaction
|
|
member this.GetInteractionId() = ctx.Id
|
|
member this.GetChannel() = ctx.Channel
|
|
member this.GetContext() = ctx
|
|
|
|
let getTimeText isCooldown (timespan : TimeSpan) timestamp =
|
|
let span =
|
|
if isCooldown
|
|
then timespan - (DateTime.UtcNow - timestamp)
|
|
else (DateTime.UtcNow - timestamp)
|
|
let plural amount = if amount = 1 then "" else "s"
|
|
let ``and`` = if span.Hours > 0 then "and " else ""
|
|
let hours = if span.Hours > 0 then $"{span.Hours} hour{plural span.Hours} {``and``}" else String.Empty
|
|
let totalMins = span.Minutes
|
|
let minutes = if totalMins > 0 then $"{totalMins} minute{plural totalMins}" else "1 minute"
|
|
$"{hours}{minutes}"
|
|
|
|
let getShortTimeText (timespan : TimeSpan) timestamp =
|
|
let remaining = timespan - (DateTime.UtcNow - timestamp)
|
|
let hours = if remaining.Hours > 0 then $"{remaining.Hours}h " else String.Empty
|
|
let minutesRemaining = if remaining.Hours = 0 then remaining.Minutes + 1 else remaining.Minutes
|
|
$"{hours}{minutesRemaining}min"
|
|
|
|
let defer (ctx: IDiscordContext) = async {
|
|
let builder = DiscordInteractionResponseBuilder()
|
|
builder.IsEphemeral <- true
|
|
do! ctx.Respond(InteractionResponseType.DeferredChannelMessageWithSource, builder) |> Async.AwaitTask
|
|
}
|
|
|
|
let sendSimpleResponse (ctx: IDiscordContext) msg =
|
|
async {
|
|
let builder = DiscordInteractionResponseBuilder()
|
|
builder.Content <- msg
|
|
builder.AsEphemeral true |> ignore
|
|
do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask
|
|
}
|
|
|
|
let sendFollowUpMessage (ctx : IDiscordContext) msg =
|
|
async {
|
|
let builder = DiscordFollowupMessageBuilder()
|
|
builder.IsEphemeral <- true
|
|
builder.Content <- msg
|
|
do! ctx.FollowUp(builder) |> Async.AwaitTask
|
|
}
|
|
|
|
let sendFollowUpEmbed (ctx : IDiscordContext) embed =
|
|
async {
|
|
let builder =
|
|
DiscordFollowupMessageBuilder()
|
|
.AsEphemeral(true)
|
|
.AddEmbed(embed)
|
|
do! ctx.FollowUp(builder) |> Async.AwaitTask
|
|
}
|
|
|
|
let sendFollowUpMessageWithButton (ctx : IDiscordContext) interactiveMessage =
|
|
async {
|
|
let builder = DiscordFollowupMessageBuilder()
|
|
let button = DiscordButtonComponent(ButtonStyle.Success, interactiveMessage.ButtonId, interactiveMessage.ButtonText) :> DiscordComponent
|
|
builder.AddComponents [| button |] |> ignore
|
|
builder.IsEphemeral <- true
|
|
builder.Content <- interactiveMessage.Message
|
|
do! ctx.FollowUp(builder) |> Async.AwaitTask
|
|
}
|
|
|
|
let updateMessageWithGreyedOutButtons (ctx : IDiscordContext) interactiveMessage =
|
|
async {
|
|
let builder = DiscordInteractionResponseBuilder()
|
|
let button = DiscordButtonComponent(ButtonStyle.Success, interactiveMessage.ButtonId, interactiveMessage.ButtonText, true) :> DiscordComponent
|
|
builder.AddComponents [| button |] |> ignore
|
|
builder.IsEphemeral <- true
|
|
builder.Content <- interactiveMessage.Message
|
|
do! ctx.Respond(InteractionResponseType.UpdateMessage, builder) |> Async.AwaitTask
|
|
}
|