use std::rc::Rc;
use std::time::Duration;
use futures::future::LocalBoxFuture;
use serde_json::Value;
use crate::Result;
use crate::bindings::oino::extension::registry as wr;
use crate::command::{Command, Flag, Shortcut};
use crate::context::Ctx;
use crate::events::{Event, EventKind, IntoEventResult};
use crate::rt::Handlers;
use crate::tool::Tool;
pub trait Extension: Default + 'static {
fn init(&'static self, cx: &mut Init<Self>) -> impl Future<Output = Result<()>>;
#[cfg(feature = "provider")]
fn provider(&'static self) -> Option<&'static dyn crate::provider::Provider> {
None
}
}
pub struct Init<E: 'static> {
pub(crate) ext: &'static E,
pub(crate) ctx: Ctx,
pub(crate) manifest: Value,
pub(crate) settings: Value,
pub(crate) flags: Value,
pub(crate) registration: wr::Registration,
pub(crate) handlers: Handlers,
pub(crate) timers: Vec<(String, Duration, bool)>,
}
impl<E: 'static> Init<E> {
#[must_use]
pub fn ctx(&self) -> &Ctx {
&self.ctx
}
#[must_use]
pub fn manifest(&self) -> &Value {
&self.manifest
}
#[must_use]
pub fn settings(&self) -> &Value {
&self.settings
}
#[must_use]
pub fn flags(&self) -> &Value {
&self.flags
}
pub fn on<F, Fut, R>(&mut self, kind: EventKind, f: F) -> &mut Self
where
F: Fn(&'static E, Event, Ctx) -> Fut + 'static,
Fut: Future<Output = Result<R>> + 'static,
R: IntoEventResult,
{
if !self.registration.events.contains(&kind) {
self.registration.events.push(kind);
}
let ext = self.ext;
let f = Rc::new(f);
self.handlers.events.push((
kind,
Rc::new(move |ev, cx| {
let f = Rc::clone(&f);
Box::pin(
async move { f(ext, ev, cx).await.map(IntoEventResult::into_event_result) },
) as LocalBoxFuture<'static, _>
}),
));
self
}
pub fn tool(&mut self, tool: Tool<E>) -> &mut Self {
self.registration.tools.push(tool.spec.clone());
self.handlers.install_tool(self.ext, tool);
self
}
pub fn command(&mut self, command: Command<E>) -> &mut Self {
self.registration.commands.push(command.spec.clone());
self.handlers.install_command(self.ext, command);
self
}
pub fn shortcut(&mut self, shortcut: Shortcut<E>) -> &mut Self {
self.registration.shortcuts.push(shortcut.spec.clone());
self.handlers.install_shortcut(self.ext, shortcut);
self
}
pub fn flag(&mut self, flag: Flag) -> &mut Self {
self.registration.flags.push(flag.0);
self
}
pub fn renderer<F>(
&mut self,
target: wr::RendererTarget,
key: impl Into<String>,
f: F,
) -> &mut Self
where
F: Fn(&'static E, Value, Ctx) -> Option<Value> + 'static,
{
let key = key.into();
self.registration.renderers.push(wr::RendererSpec {
target,
key: key.clone(),
});
let ext = self.ext;
self.handlers
.renderers
.push((key, Rc::new(move |req, cx| f(ext, req, cx))));
self
}
pub fn service<F, Fut>(&mut self, name: impl Into<String>, f: F) -> &mut Self
where
F: Fn(&'static E, Value, String, Ctx) -> Fut + 'static,
Fut: Future<Output = Result<Value>> + 'static,
{
let name = name.into();
self.registration.services.push(name.clone());
let ext = self.ext;
let f = Rc::new(f);
self.handlers.services.insert(
name,
Rc::new(move |payload, caller, cx| {
let f = Rc::clone(&f);
Box::pin(async move { f(ext, payload, caller, cx).await })
}),
);
self
}
pub fn settings_namespace(&mut self, namespace: &Value) -> &mut Self {
self.registration.settings.push(namespace.to_string());
self
}
pub fn nudge_provider<F, Fut>(&mut self, f: F) -> &mut Self
where
F: Fn(&'static E, Ctx) -> Fut + 'static,
Fut: Future<Output = Option<Value>> + 'static,
{
self.registration.arbiter.nudge_provider = true;
let ext = self.ext;
let f = Rc::new(f);
self.handlers.nudge = Some(Rc::new(move |cx| {
let f = Rc::clone(&f);
Box::pin(async move { f(ext, cx).await })
}));
self
}
pub fn on_nudge_delivered(
&mut self,
f: impl Fn(&'static E, String, Ctx) + 'static,
) -> &mut Self {
let ext = self.ext;
self.handlers.nudge_delivered = Some(Rc::new(move |id, cx| f(ext, id, cx)));
self
}
pub fn wait_source<F, Fut>(&mut self, f: F) -> &mut Self
where
F: Fn(&'static E, Ctx) -> Fut + 'static,
Fut: Future<Output = Option<String>> + 'static,
{
self.registration.arbiter.wait_source = true;
let ext = self.ext;
let f = Rc::new(f);
self.handlers.wait_reason = Some(Rc::new(move |cx| {
let f = Rc::clone(&f);
Box::pin(async move { f(ext, cx).await })
}));
self
}
pub fn router<F, Fut>(&mut self, f: F) -> &mut Self
where
F: Fn(&'static E, Value, Ctx) -> Fut + 'static,
Fut: Future<Output = Result<Value>> + 'static,
{
let ext = self.ext;
let f = Rc::new(f);
self.handlers.route = Some(Rc::new(move |req, cx| {
let f = Rc::clone(&f);
Box::pin(async move { f(ext, req, cx).await })
}));
self
}
pub fn input_completer<F, Fut>(&mut self, f: F) -> &mut Self
where
F: Fn(&'static E, Value, Ctx) -> Fut + 'static,
Fut: Future<Output = Option<Value>> + 'static,
{
let ext = self.ext;
let f = Rc::new(f);
self.handlers.complete_input = Some(Rc::new(move |req, cx| {
let f = Rc::clone(&f);
Box::pin(async move { f(ext, req, cx).await })
}));
self
}
pub fn on_shutdown<F, Fut>(&mut self, f: F) -> &mut Self
where
F: Fn(&'static E, String) -> Fut + 'static,
Fut: Future<Output = ()> + 'static,
{
let ext = self.ext;
let f = Rc::new(f);
self.handlers.shutdown = Some(Rc::new(move |reason| {
let f = Rc::clone(&f);
Box::pin(async move { f(ext, reason).await })
}));
self
}
pub fn timer(&mut self, id: impl Into<String>, delay: Duration, repeat: bool) -> &mut Self {
if !self.registration.events.contains(&EventKind::OinoTimer) {
self.registration.events.push(EventKind::OinoTimer);
}
self.timers.push((id.into(), delay, repeat));
self
}
}