use std::{any::Any, sync::Arc};
use serde::de::DeserializeOwned;
use serde_json::Value;
use super::{
cell::{FilteredViewCellMap, erase_typed_view_map},
context::{ViewBuildContext, ViewContext},
request::ViewRequest,
traits::{AnyView, ViewBuildArgs, ViewHandler, ViewId, ViewIdStatic, ViewItemType, ViewParams},
};
use crate::{
common::with_id::WithId, item::Eventable, request::RequestContext, server::MykoServerContext,
store::StoreRegistry,
};
pub type ViewParseFn = fn(Value) -> Result<Arc<dyn AnyView>, anyhow::Error>;
pub type ViewCellFactory = fn(
Arc<dyn AnyView>,
Arc<StoreRegistry>,
Arc<RequestContext>,
Arc<MykoServerContext>,
) -> Result<FilteredViewCellMap, String>;
pub struct ViewRegistration {
pub view_id: &'static str,
pub view_item_type: &'static str,
pub crate_name: &'static str,
pub parse: ViewParseFn,
pub cell_factory: ViewCellFactory,
pub args: &'static [crate::reflection::OperationArgField],
pub description: Option<&'static str>,
}
inventory::collect!(ViewRegistration);
pub trait ViewFactory: ViewParams {
fn parse(value: Value) -> Result<Arc<dyn AnyView>, anyhow::Error>;
fn cell_factory(
view: Arc<dyn AnyView>,
registry: Arc<StoreRegistry>,
request_ctx: Arc<RequestContext>,
server_ctx: Arc<MykoServerContext>,
) -> Result<FilteredViewCellMap, String>;
}
impl<V> ViewFactory for V
where
V: ViewParams
+ ViewId
+ ViewIdStatic
+ ViewItemType
+ ViewHandler
+ std::fmt::Debug
+ DeserializeOwned,
<V as ViewItemType>::Item:
Eventable + WithId + DeserializeOwned + Clone + std::fmt::Debug + Send + Sync + 'static,
{
fn parse(value: Value) -> Result<Arc<dyn AnyView>, anyhow::Error> {
tracing::trace!("ViewFactory::parse view_id={}", V::view_id_static());
let view = serde_json::from_value::<ViewRequest<V>>(value)?;
Ok(Arc::new(view))
}
fn cell_factory(
any_view: Arc<dyn AnyView>,
registry: Arc<StoreRegistry>,
request_ctx: Arc<RequestContext>,
server_ctx: Arc<MykoServerContext>,
) -> Result<FilteredViewCellMap, String> {
let _span =
tracing::trace_span!("myko.view", view = V::view_id_static().as_ref()).entered();
crate::server::dispatch_metrics::record_view(
V::view_id_static().as_ref(),
request_ctx.origin(),
);
tracing::trace!(
"ViewFactory::cell_factory start view_id={}",
V::view_id_static()
);
let any_ref: &dyn Any = any_view.as_ref();
let request: ViewRequest<V> =
crate::common::downcast::downcast_request(any_ref, "view payload")?;
let view: Arc<V> = Arc::new(request.view);
let view_ctx = Arc::new(ViewContext::new(request_ctx, registry, server_ctx));
let view_cell_ctx = ViewBuildContext::new(view_ctx);
let built = V::build_cell(ViewBuildArgs {
view,
view_context: view_cell_ctx,
});
tracing::trace!(
"ViewFactory::cell_factory using build_cell view_id={}",
V::view_id_static()
);
Ok(erase_typed_view_map(hyphae::MapQuery::materialize(built)))
}
}