use crate::value::value::MapImpl;
use std::collections::HashMap;
use crate::internal::msgapi::codes::*;
use serde::Serialize;
use crate::{
EvaluatorOptions,
api::{
evaluator::CREATE_EVALUATOR_REQUEST_ID,
reader::{PklModuleReader, PklResourceReader},
},
internal::msgapi::impl_pkl_message,
};
impl From<&dyn PklModuleReader> for ClientModuleReader {
fn from(reader: &dyn PklModuleReader) -> Self {
ClientModuleReader {
scheme: reader.scheme().to_string(),
has_hierarchical_uris: reader.has_hierarchical_uris(),
is_globbable: reader.is_globbable(),
is_local: reader.is_local(),
}
}
}
impl From<&dyn PklResourceReader> for ClientResourceReader {
fn from(reader: &dyn PklResourceReader) -> Self {
ClientResourceReader {
scheme: reader.scheme().to_string(),
has_hierarchical_uris: reader.has_hierarchical_uris(),
is_globbable: reader.is_globbable(),
}
}
}
#[derive(Serialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct HttpProxy {
#[serde(skip_serializing_if = "Option::is_none")]
pub address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub no_proxy: Option<Vec<String>>,
}
#[derive(Serialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Http {
#[serde(skip_serializing_if = "Option::is_none")]
pub proxy: Option<HttpProxy>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ca_certificates: Option<Vec<u8>>,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct CreateEvaluator<'a> {
pub request_id: u64,
pub allowed_modules: Vec<String>,
pub allowed_resources: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_module_readers: Option<Vec<ClientModuleReader>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_resource_readers: Option<Vec<ClientResourceReader>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub env: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub properties: Option<&'a MapImpl<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub external_resource_readers: Option<&'a HashMap<String, ExternalReader>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub external_module_readers: Option<&'a HashMap<String, ExternalReader>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub http: Option<Http>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout_seconds: Option<u64>,
}
impl Default for CreateEvaluator<'_> {
fn default() -> Self {
let env_vars: HashMap<String, String> = std::env::vars().collect();
Self {
request_id: CREATE_EVALUATOR_REQUEST_ID,
allowed_modules: vec![
"pkl:".into(),
"repl:".into(),
"file:".into(),
"https:".into(),
"package:".into(),
],
allowed_resources: vec![
"env:".into(),
"prop:".into(),
"package:".into(),
"https:".into(),
"projectpackage:".into(),
],
env: Some(env_vars),
client_module_readers: None,
client_resource_readers: None,
properties: None,
external_resource_readers: None,
external_module_readers: None,
http: None,
timeout_seconds: None,
}
}
}
impl<'a> From<&'a EvaluatorOptions> for CreateEvaluator<'a> {
fn from(opts: &'a EvaluatorOptions) -> Self {
let mut evaluator_message = CreateEvaluator::default();
{
if let Some(props) = &opts.properties {
evaluator_message.properties = Some(props);
}
if let Some(readers) = opts.client_module_readers.as_ref() {
for reader in readers {
evaluator_message
.allowed_modules
.push(reader.scheme().to_string());
}
let module_readers: Vec<ClientModuleReader> = readers
.iter()
.map(|r| {
let reader: &dyn PklModuleReader = r.as_ref();
reader.into()
})
.collect();
evaluator_message.client_module_readers = Some(module_readers);
}
if let Some(readers) = opts.client_resource_readers.as_ref() {
for reader in readers {
evaluator_message
.allowed_resources
.push(reader.scheme().to_string());
}
let resource_readers: Vec<ClientResourceReader> =
readers.iter().map(|r| r.as_ref().into()).collect();
evaluator_message.client_resource_readers = Some(resource_readers);
}
if let Some(readers) = &opts.external_resource_readers {
for uri in readers.keys() {
evaluator_message.allowed_resources.push(uri.clone());
}
evaluator_message.external_resource_readers = Some(readers);
}
if let Some(readers) = &opts.external_module_readers {
for uri in readers.keys() {
evaluator_message.allowed_modules.push(uri.clone());
}
evaluator_message.external_module_readers = Some(readers);
}
if let Some(http_opts) = &opts.http {
let http = Http {
proxy: http_opts.proxy.as_ref().map(|p| HttpProxy {
address: p.address.clone(),
no_proxy: p.no_proxy.clone(),
}),
ca_certificates: http_opts.ca_certificates.clone(),
};
evaluator_message.http = Some(http);
}
if let Some(timeout) = opts.timeout_seconds {
evaluator_message.timeout_seconds = Some(timeout);
}
}
evaluator_message
}
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ClientModuleReader {
pub scheme: String,
pub has_hierarchical_uris: bool,
pub is_globbable: bool,
pub is_local: bool,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ClientResourceReader {
pub scheme: String,
pub has_hierarchical_uris: bool,
pub is_globbable: bool,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CloseEvaluator {
pub evaluator_id: i64,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct EvaluateRequest {
pub request_id: u64,
pub evaluator_id: i64,
pub module_uri: String,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ReadResourceResponse {
pub request_id: i64,
pub evaluator_id: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub contents: Option<Vec<u8>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ReadModuleResponse {
pub request_id: i64,
pub evaluator_id: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub contents: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct InitializeResourceReaderResponse {
pub request_id: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub spec: Option<ClientResourceReader>,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct InitializeModuleReaderResponse {
pub request_id: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub spec: Option<ClientModuleReader>,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ListResourcesResponse {
pub request_id: i64,
pub evaluator_id: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub path_elements: Option<Vec<PathElements>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ListModulesResponse {
pub request_id: i64,
pub evaluator_id: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub path_elements: Option<Vec<PathElements>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PathElements {
pub name: String,
pub is_directory: bool,
}
impl PathElements {
pub fn new(name: impl Into<String>, is_directory: bool) -> Self {
Self {
name: name.into(),
is_directory,
}
}
}
#[derive(Serialize, Clone)]
pub struct ExternalReader {
pub executable: String,
pub arguments: Vec<String>,
}
impl_pkl_message!(CreateEvaluator<'a>, CREATE_EVALUATOR);
impl_pkl_message!(EvaluateRequest, EVALUATE_REQUEST);
impl_pkl_message!(CloseEvaluator, CLOSE);
impl_pkl_message!(
InitializeResourceReaderResponse,
INITIALIZE_RESOURCE_READER_RESPONSE
);
impl_pkl_message!(
InitializeModuleReaderResponse,
INITIALIZE_MODULE_READER_RESPONSE
);
impl_pkl_message!(ReadResourceResponse, READ_RESOURCE_RESPONSE);
impl_pkl_message!(ReadModuleResponse, READ_MODULE_RESPONSE);
impl_pkl_message!(ListResourcesResponse, LIST_RESOURCES_RESPONSE);
impl_pkl_message!(ListModulesResponse, LIST_MODULES_RESPONSE);