use crate::error::Result;
use crate::server::channel::Channel;
use crate::server::channel_owner::{
ChannelOwner, ChannelOwnerImpl, DisposeReason, ParentOrConnection,
};
use crate::server::connection::ConnectionLike;
use serde_json::Value;
use std::any::Any;
use std::sync::Arc;
#[derive(Debug, Clone, Default)]
pub struct TracingStartOptions {
pub name: Option<String>,
pub screenshots: Option<bool>,
pub snapshots: Option<bool>,
}
#[derive(Debug, Clone, Default)]
pub struct TracingStopOptions {
pub path: Option<String>,
}
#[derive(Clone)]
pub struct Tracing {
base: ChannelOwnerImpl,
}
impl Tracing {
pub fn new(
parent: ParentOrConnection,
type_name: String,
guid: Arc<str>,
initializer: Value,
) -> Result<Self> {
Ok(Self {
base: ChannelOwnerImpl::new(parent, type_name, guid, initializer),
})
}
pub async fn start(&self, options: Option<TracingStartOptions>) -> Result<()> {
let opts = options.unwrap_or_default();
let mut start_params = serde_json::json!({});
if let Some(ref name) = opts.name {
start_params["name"] = serde_json::Value::String(name.clone());
}
if let Some(screenshots) = opts.screenshots {
start_params["screenshots"] = serde_json::Value::Bool(screenshots);
}
if let Some(snapshots) = opts.snapshots {
start_params["snapshots"] = serde_json::Value::Bool(snapshots);
}
self.channel()
.send_no_result("tracingStart", start_params)
.await?;
let mut chunk_params = serde_json::json!({});
if let Some(name) = opts.name {
chunk_params["name"] = serde_json::Value::String(name);
}
self.channel()
.send_no_result("tracingStartChunk", chunk_params)
.await
}
pub async fn stop(&self, options: Option<TracingStopOptions>) -> Result<()> {
let path = options.and_then(|o| o.path);
let mode = if path.is_some() { "archive" } else { "discard" };
let stop_chunk_params = serde_json::json!({ "mode": mode });
let chunk_result: Value = self
.channel()
.send("tracingStopChunk", stop_chunk_params)
.await?;
self.channel()
.send_no_result("tracingStop", serde_json::json!({}))
.await?;
if let Some(dest_path) = path
&& let Some(artifact_guid) = chunk_result
.get("artifact")
.and_then(|a| a.get("guid"))
.and_then(|g| g.as_str())
{
self.save_artifact(artifact_guid, &dest_path).await?;
}
Ok(())
}
async fn save_artifact(&self, artifact_guid: &str, dest_path: &str) -> Result<()> {
use crate::protocol::artifact::Artifact;
use crate::server::connection::ConnectionExt;
let artifact = self
.connection()
.get_typed::<Artifact>(artifact_guid)
.await?;
artifact.save_as(dest_path).await
}
}
impl ChannelOwner for Tracing {
fn guid(&self) -> &str {
self.base.guid()
}
fn type_name(&self) -> &str {
self.base.type_name()
}
fn parent(&self) -> Option<Arc<dyn ChannelOwner>> {
self.base.parent()
}
fn connection(&self) -> Arc<dyn ConnectionLike> {
self.base.connection()
}
fn initializer(&self) -> &Value {
self.base.initializer()
}
fn channel(&self) -> &Channel {
self.base.channel()
}
fn dispose(&self, reason: DisposeReason) {
self.base.dispose(reason)
}
fn adopt(&self, child: Arc<dyn ChannelOwner>) {
self.base.adopt(child)
}
fn add_child(&self, guid: Arc<str>, child: Arc<dyn ChannelOwner>) {
self.base.add_child(guid, child)
}
fn remove_child(&self, guid: &str) {
self.base.remove_child(guid)
}
fn on_event(&self, method: &str, params: Value) {
self.base.on_event(method, params)
}
fn was_collected(&self) -> bool {
self.base.was_collected()
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl std::fmt::Debug for Tracing {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Tracing")
.field("guid", &self.guid())
.finish()
}
}