Skip to main content
Glama
debug.rs11.6 kB
use std::collections::HashMap; use serde::{ Deserialize, Serialize, }; use si_id::SchemaId; use telemetry::prelude::*; use thiserror::Error; use super::socket::{ ComponentInputSocket, ComponentOutputSocket, }; use crate::{ AttributeValue, AttributeValueId, Component, ComponentError, ComponentId, DalContext, FuncError, InputSocket, OutputSocket, PropId, SchemaVariantError, SchemaVariantId, SecretError, SecretId, attribute::value::{ AttributeValueError, debug::{ AttributeDebugView, AttributeDebugViewError, }, }, diagram::{ DiagramError, geometry::Geometry, view::{ View, ViewId, }, }, prop::PropError, socket::{ debug::{ SocketDebugView, SocketDebugViewError, }, input::InputSocketError, output::OutputSocketError, }, workspace_snapshot::{ WorkspaceSnapshotError, node_weight::NodeWeightError, }, }; type ComponentDebugViewResult<T> = Result<T, ComponentDebugViewError>; /// A generated view for an [`Component`](crate::Component) that contains metadata about each of /// the components attributes. Used for constructing a debug view of the component and also for /// cloning a component #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComponentDebugView { pub name: String, pub schema_id: SchemaId, pub schema_variant_id: SchemaVariantId, pub attributes: Vec<AttributeDebugView>, pub input_sockets: Vec<SocketDebugView>, pub output_sockets: Vec<SocketDebugView>, pub geometry: HashMap<ViewId, Geometry>, } /// A generated view for an [`Component`](crate::Component) that contains metadata about each of /// the components attributes. Used for constructing a debug view of the component and also for /// cloning a component #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ComponentDebugData { pub name: String, pub schema_id: SchemaId, pub schema_variant_id: SchemaVariantId, pub attribute_tree: HashMap<AttributeValueId, Vec<AttributeValueId>>, pub input_sockets: Vec<ComponentInputSocket>, pub output_sockets: Vec<ComponentOutputSocket>, } #[remain::sorted] #[derive(Error, Debug)] pub enum ComponentDebugViewError { #[error("attribute debug view error: {0}")] AttributeDebugViewError(#[from] Box<AttributeDebugViewError>), #[error("attribute value error: {0}")] AttributeValue(#[from] Box<AttributeValueError>), #[error("Attribute Value tree badly constructed with root prop of {0}")] AttributeValueTreeBad(AttributeValueId), #[error("component error: {0}")] Component(String), #[error("component error: {0}")] ComponentError(#[from] Box<ComponentError>), #[error("diagram error: {0}")] Diagram(#[from] Box<DiagramError>), #[error("func error: {0}")] Func(#[from] Box<FuncError>), #[error("input socket error: {0}")] InputSocketError(#[from] Box<InputSocketError>), #[error("json pointer not found: {1:?} at {0}")] JSONPointerNotFound(serde_json::Value, String), #[error("node weight error: {0}")] NodeWeightError(#[from] Box<NodeWeightError>), #[error("no internal provider for prop {0}")] NoInternalProvider(PropId), #[error("no root prop found for schema variant {0}")] NoRootProp(SchemaVariantId), #[error("schema variant not found for component {0}")] NoSchemaVariant(ComponentId), #[error("component not found {0}")] NotFound(ComponentId), #[error("output socket error: {0}")] OutputSocketError(#[from] Box<OutputSocketError>), #[error("prop error: {0}")] Prop(#[from] Box<PropError>), #[error("schema variant error: {0}")] SchemaVariant(#[from] Box<SchemaVariantError>), #[error("secret error: {0}")] Secret(#[from] Box<SecretError>), #[error("secret not found: {0}")] SecretNotFound(SecretId), #[error("serde json error: {0}")] SerdeJson(#[from] serde_json::Error), #[error("socket debug view error: {0}")] SocketDebugViewError(#[from] Box<SocketDebugViewError>), #[error("workspace snapshot error: {0}")] WorkspaceSnapshotError(#[from] Box<WorkspaceSnapshotError>), } impl ComponentDebugView { #[instrument(level = "trace", skip_all)] pub async fn new( ctx: &DalContext, component_id: ComponentId, ) -> ComponentDebugViewResult<Self> { // get ComponentDebugData let component = Component::get_by_id(ctx, component_id).await?; let component_debug_data = ComponentDebugData::new(ctx, &component).await?; let mut attributes = vec![]; let mut input_sockets = vec![]; let mut output_sockets = vec![]; let mut cache: Vec<AttributeValueId> = vec![]; //construct attribute value debug views from the debug data for (av, children) in component_debug_data.attribute_tree { if !cache.contains(&av) { let avd = AttributeDebugView::new(ctx, av, None, None).await?; attributes.push(avd); cache.push(av); } for child_av in children { if !cache.contains(&child_av) { let child_avd = AttributeDebugView::new(ctx, child_av, None, Some(av)).await?; attributes.push(child_avd); cache.push(child_av); } } } //sort alphabetically by path for the view attributes.sort_by_key(|view| view.path.to_lowercase()); for component_input_socket in component_debug_data.input_sockets { let avd = SocketDebugView::new_for_input_socket(ctx, component_input_socket).await?; input_sockets.push(avd); } for component_output_socket in component_debug_data.output_sockets { let avd = SocketDebugView::new_for_output_socket(ctx, component_output_socket).await?; output_sockets.push(avd); } let mut geometry = HashMap::new(); for view in View::list(ctx).await? { let Some(geo) = Geometry::try_get_by_component_and_view(ctx, component.id, view.id()).await? else { continue; }; geometry.insert(view.id(), geo); } let debug_view = ComponentDebugView { name: component_debug_data.name, schema_id: component_debug_data.schema_id, schema_variant_id: component_debug_data.schema_variant_id, attributes, input_sockets, output_sockets, geometry, }; Ok(debug_view) } } impl ComponentDebugData { #[instrument(level = "trace", skip_all)] pub async fn new(ctx: &DalContext, component: &Component) -> ComponentDebugViewResult<Self> { let schema_variant_id = Component::schema_variant_id(ctx, component.id()).await?; let schema_id = Component::schema_id_for_component_id(ctx, component.id()).await?; let attribute_tree = Self::get_attribute_value_tree_for_component(ctx, component.id()).await?; let input_sockets = Self::get_input_sockets_for_component(ctx, schema_variant_id, component.id()).await?; let output_sockets = Self::get_output_sockets_for_component(ctx, schema_variant_id, component.id()).await?; let name = component .name(ctx) .await .map_err(|e| ComponentDebugViewError::Component(format!("get name error: {e}")))?; let debug_view = ComponentDebugData { name, schema_id, schema_variant_id, attribute_tree, input_sockets, output_sockets, }; Ok(debug_view) } #[instrument(level = "trace", skip_all)] pub async fn get_input_sockets_for_component( ctx: &DalContext, schema_variant_id: SchemaVariantId, component_id: ComponentId, ) -> ComponentDebugViewResult<Vec<ComponentInputSocket>> { let mut input_sockets = Vec::new(); let sockets = InputSocket::list_ids_for_schema_variant(ctx, schema_variant_id).await?; for socket in sockets { if let Some(input_socket_match) = ComponentInputSocket::get_by_ids(ctx, component_id, socket).await? { input_sockets.push(input_socket_match); } } Ok(input_sockets) } #[instrument(level = "trace", skip_all)] pub async fn get_output_sockets_for_component( ctx: &DalContext, schema_variant_id: SchemaVariantId, component_id: ComponentId, ) -> ComponentDebugViewResult<Vec<ComponentOutputSocket>> { let mut output_sockets = Vec::new(); let sockets = OutputSocket::list_ids_for_schema_variant(ctx, schema_variant_id).await?; for socket in sockets { if let Some(output_socket_match) = ComponentOutputSocket::get_by_ids(ctx, component_id, socket).await? { output_sockets.push(output_socket_match); } } Ok(output_sockets) } #[instrument(level = "trace", skip_all)] pub async fn get_attribute_value_tree_for_component( ctx: &DalContext, component_id: ComponentId, ) -> ComponentDebugViewResult<HashMap<AttributeValueId, Vec<AttributeValueId>>> { Ok(AttributeValue::tree_for_component(ctx, component_id).await?) } } impl From<AttributeDebugViewError> for ComponentDebugViewError { fn from(value: AttributeDebugViewError) -> Self { Box::new(value).into() } } impl From<AttributeValueError> for ComponentDebugViewError { fn from(value: AttributeValueError) -> Self { Box::new(value).into() } } impl From<ComponentError> for ComponentDebugViewError { fn from(value: ComponentError) -> Self { Box::new(value).into() } } impl From<DiagramError> for ComponentDebugViewError { fn from(value: DiagramError) -> Self { Box::new(value).into() } } impl From<FuncError> for ComponentDebugViewError { fn from(value: FuncError) -> Self { Box::new(value).into() } } impl From<InputSocketError> for ComponentDebugViewError { fn from(value: InputSocketError) -> Self { Box::new(value).into() } } impl From<NodeWeightError> for ComponentDebugViewError { fn from(value: NodeWeightError) -> Self { Box::new(value).into() } } impl From<OutputSocketError> for ComponentDebugViewError { fn from(value: OutputSocketError) -> Self { Box::new(value).into() } } impl From<PropError> for ComponentDebugViewError { fn from(value: PropError) -> Self { Box::new(value).into() } } impl From<SchemaVariantError> for ComponentDebugViewError { fn from(value: SchemaVariantError) -> Self { Box::new(value).into() } } impl From<SecretError> for ComponentDebugViewError { fn from(value: SecretError) -> Self { Box::new(value).into() } } impl From<SocketDebugViewError> for ComponentDebugViewError { fn from(value: SocketDebugViewError) -> Self { Box::new(value).into() } } impl From<WorkspaceSnapshotError> for ComponentDebugViewError { fn from(value: WorkspaceSnapshotError) -> Self { Box::new(value).into() } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server