use std::collections::HashMap;
use std::sync::Arc;
use async_trait::async_trait;
use log::trace;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::child_process::ChildPluginProcess;
use crate::proto::*;
use crate::proto::pact_plugin_client::PactPluginClient;
#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Debug, Hash)]
pub enum PluginDependencyType {
OSPackage,
Plugin,
Library,
Executable
}
impl Default for PluginDependencyType {
fn default() -> Self {
PluginDependencyType::Plugin
}
}
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug, Hash)]
#[serde(rename_all = "camelCase")]
pub struct PluginDependency {
pub name: String,
pub version: Option<String>,
#[serde(default)]
pub dependency_type: PluginDependencyType
}
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PactPluginManifest {
#[serde(skip)]
pub plugin_dir: String,
pub plugin_interface_version: u8,
pub name: String,
pub version: String,
pub executable_type: String,
pub minimum_required_version: Option<String>,
pub entry_point: String,
#[serde(default)]
pub entry_points: HashMap<String, String>,
pub dependencies: Option<Vec<PluginDependency>>,
#[serde(default)]
pub plugin_config: HashMap<String, Value>
}
impl PactPluginManifest {
pub fn as_dependency(&self) -> PluginDependency {
PluginDependency {
name: self.name.clone(),
version: Some(self.version.clone()),
dependency_type: PluginDependencyType::Plugin
}
}
}
impl Default for PactPluginManifest {
fn default() -> Self {
PactPluginManifest {
plugin_dir: "".to_string(),
plugin_interface_version: 1,
name: "".to_string(),
version: "".to_string(),
executable_type: "".to_string(),
minimum_required_version: None,
entry_point: "".to_string(),
entry_points: Default::default(),
dependencies: None,
plugin_config: Default::default()
}
}
}
#[async_trait]
pub trait PactPluginRpc {
async fn init_plugin(&self, request: InitPluginRequest) -> anyhow::Result<InitPluginResponse>;
async fn compare_contents(&self, request: CompareContentsRequest) -> anyhow::Result<CompareContentsResponse>;
async fn configure_interaction(&self, request: ConfigureInteractionRequest) -> anyhow::Result<ConfigureInteractionResponse>;
async fn generate_content(&self, request: GenerateContentRequest) -> anyhow::Result<GenerateContentResponse>;
}
#[derive(Debug, Clone)]
pub struct PactPlugin {
pub manifest: PactPluginManifest,
pub child: Arc<ChildPluginProcess>,
access_count: usize
}
#[async_trait]
impl PactPluginRpc for PactPlugin {
async fn init_plugin(&self, request: InitPluginRequest) -> anyhow::Result<InitPluginResponse> {
let mut client = PactPluginClient::connect(format!("http://127.0.0.1:{}", self.child.port())).await?;
let response = client.init_plugin(tonic::Request::new(request)).await?;
Ok(response.get_ref().clone())
}
async fn compare_contents(&self, request: CompareContentsRequest) -> anyhow::Result<CompareContentsResponse> {
let mut client = PactPluginClient::connect(format!("http://127.0.0.1:{}", self.child.port())).await?;
let response = client.compare_contents(tonic::Request::new(request)).await?;
Ok(response.get_ref().clone())
}
async fn configure_interaction(&self, request: ConfigureInteractionRequest) -> anyhow::Result<ConfigureInteractionResponse> {
let mut client = PactPluginClient::connect(format!("http://127.0.0.1:{}", self.child.port())).await?;
let response = client.configure_interaction(tonic::Request::new(request)).await?;
Ok(response.get_ref().clone())
}
async fn generate_content(&self, request: GenerateContentRequest) -> anyhow::Result<GenerateContentResponse> {
let mut client = PactPluginClient::connect(format!("http://127.0.0.1:{}", self.child.port())).await?;
let response = client.generate_content(tonic::Request::new(request)).await?;
Ok(response.get_ref().clone())
}
}
impl PactPlugin {
pub fn new(manifest: &PactPluginManifest, child: ChildPluginProcess) -> Self {
PactPlugin { manifest: manifest.clone(), child: Arc::new(child), access_count: 1 }
}
pub fn port(&self) -> u16 {
self.child.port()
}
pub fn kill(&self) {
self.child.kill();
}
pub fn update_access(&mut self) {
self.access_count += 1;
trace!("update_access: Plugin {}/{} access is now {}", self.manifest.name, self.manifest.version,
self.access_count);
}
pub fn drop_access(&mut self) -> usize {
if self.access_count > 0 {
self.access_count -= 1;
}
trace!("drop_access: Plugin {}/{} access is now {}", self.manifest.name, self.manifest.version,
self.access_count);
self.access_count
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct PluginInteractionConfig {
pub pact_configuration: HashMap<String, Value>,
pub interaction_configuration: HashMap<String, Value>
}