///|
/// The routed target of an interaction entering the middleware chain.
/// Autocomplete, gateway events, and services never pass through it.
pub(all) enum InteractionTarget {
Command(name~ : String)
Component(custom_id~ : String)
Modal(custom_id~ : String)
} derive(Debug)
///|
/// Read-only context handed to interaction middleware, before any initial
/// response has been sent.
pub struct InteractionCtx {
priv target_ : InteractionTarget
priv raw_ : FailureRaw
}
///|
/// The routed command, component, or modal being invoked.
pub fn InteractionCtx::target(self : InteractionCtx) -> InteractionTarget {
self.target_
}
///|
/// The full interaction payload.
pub fn InteractionCtx::interaction(self : InteractionCtx) -> @model.Interaction {
match self.raw_ {
RawCommand(ctx) => ctx.interaction
RawComponent(ctx) => ctx.interaction
RawModal(ctx) => ctx.interaction
}
}
///|
/// The invoking user.
pub fn InteractionCtx::user(self : InteractionCtx) -> @model.User {
match self.raw_ {
RawCommand(ctx) => ctx.user()
RawComponent(ctx) => ctx.user()
RawModal(ctx) => ctx.user()
}
}
///|
/// Guild or DM invocation scope, carrying the invoking member or user.
pub fn InteractionCtx::scope(
self : InteractionCtx,
) -> @framework.InvocationScope {
match self.raw_ {
RawCommand(ctx) => ctx.scope()
RawComponent(ctx) => ctx.scope()
RawModal(ctx) => ctx.scope()
}
}
///|
/// The validated guild invocation. In a DM this raises
/// `HandlerError::GuildOnly`, which the error policy renders normally.
pub fn InteractionCtx::guild_scope(
self : InteractionCtx,
) -> @framework.GuildInvocation raise HandlerError {
let scope = match self.raw_ {
RawCommand(ctx) => ctx.guild_scope()
RawComponent(ctx) => ctx.guild_scope()
RawModal(ctx) => ctx.guild_scope()
}
require_guild(scope)
}
///|
/// The guild the interaction was invoked in, or `None` outside guilds. Use
/// `guild_scope()` for flows that require a guild; this accessor is for
/// maybe-guild flows where DMs are valid.
pub fn InteractionCtx::guild_id(self : InteractionCtx) -> @model.GuildId? {
self.interaction().guild_id
}
///|
/// Send the initial response from middleware, short-circuiting the handler.
pub async fn InteractionCtx::respond(
self : InteractionCtx,
message : String,
ephemeral? : Bool = true,
) -> Unit {
match self.raw_ {
RawCommand(ctx) => ctx.respond(content=message, ephemeral~)
RawComponent(ctx) => ctx.respond(content=message, ephemeral~)
RawModal(ctx) => ctx.respond(content=message, ephemeral~)
}
}
///|
/// Middleware around interaction dispatch: receives the read-only
/// context and a `next` continuation. Call `next()` to continue the
/// chain; skip it (typically after `InteractionCtx::respond`) to
/// short-circuit the handler.
pub type InteractionMiddleware = async (InteractionCtx, async () -> Unit) -> Unit
///|
async fn App::run_middleware(
self : App,
ctx : InteractionCtx,
index : Int,
terminal : async () -> Unit,
) -> Unit {
if index < self.middleware_.length() {
self.middleware_[index](ctx, () => {
self.run_middleware(ctx, index + 1, terminal)
})
} else {
terminal()
}
}