tnn 0.1.3

A quality of life developer tool to interact with Telenor services
Documentation
use crate::{
	call,
	core::api::{calls::WithCore, calls::WITH_CORE, Core, NAME},
	extension::{Call, CallContext, CallOutput, Extension, ExtensionContext},
	util::parent_command::ParentCommand,
};
use anyhow::Result;
use clap::CommandFactory;
use thiserror::Error;

use super::app::App;

pub const RUN: Call<(), ()> = call!((), (), "run", NAME);

pub static MANIFEST: Extension = Extension {
	name: env!("CARGO_PKG_NAME"),
	version: env!("CARGO_PKG_VERSION"),
	dependencies: &[],
	init: &|ctx| Box::pin(async { core_init(ctx).await }),
};

async fn core_init(ctx: ExtensionContext) -> Result<()> {
	ctx.state
		.lock()
		.await
		.put(Core::new(ParentCommand::new(<App as CommandFactory>::command())));
	crate::debug!("Added core");

	ctx.add_call(&RUN, &run).await?;
	ctx.add_call(&WITH_CORE, &with_core).await?;
	Ok(())
}

fn with_core(ctx: CallContext<WithCore>) -> CallOutput<()> {
	Box::pin(async move {
		let mut state = ctx.state.lock().await;
		crate::debug!("Taking core by {}", ctx.caller);
		let core1 = state.take::<Core>()?;
		crate::debug!("Core stolen by {}", ctx.caller);
		state.put(ctx.argument.0(core1)?);
		crate::debug!("Core given back by {}", ctx.caller);
		Ok(())
	})
}

fn run(ctx: CallContext<()>) -> CallOutput<()> {
	Box::pin(async move {
		if ctx.caller != "" {
			return Err(CallerNotAllowedError("tnn/run", ctx.caller).into());
		}

		let (command, handler) = ctx.state.lock().await.take::<Core>()?.finish().build();

		let matches = command.get_matches();

		crate::debug!("Running application!");
		handler(&matches).await?;

		Ok(())
	})
}

#[derive(Error, Debug)]
#[error("Call '{0}' can only be executed by owner, called by '{1}'")]
struct CallerNotAllowedError(&'static str, &'static str);