Get rid of all transport types and settle on Protobuf (#25)

* Get rid of all transport types and settle on Protobuf

hope i don't regret this

* Update Cargo.toml

* Update agent.py
This commit is contained in:
Josh Thomas 2024-12-12 16:53:49 -06:00 committed by GitHub
parent 643a47953e
commit 0a6e975ca5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 1484 additions and 685 deletions

View file

@ -1,5 +1,5 @@
use djls_ipc::{JsonResponse, PythonProcess, TransportError, TransportMessage, TransportResponse};
use serde::Deserialize;
use djls_ipc::v1::*;
use djls_ipc::{ProcessError, PythonProcess};
use std::fmt;
#[derive(Debug)]
@ -20,23 +20,6 @@ impl fmt::Display for App {
#[derive(Debug, Default)]
pub struct Apps(Vec<App>);
#[derive(Debug, Deserialize)]
struct InstalledAppsCheck {
has_app: bool,
}
impl TryFrom<JsonResponse> for InstalledAppsCheck {
type Error = TransportError;
fn try_from(response: JsonResponse) -> Result<Self, Self::Error> {
response
.data()
.clone()
.ok_or_else(|| TransportError::Process("No data in response".to_string()))
.and_then(|data| serde_json::from_value(data).map_err(TransportError::Json))
}
}
impl Apps {
pub fn from_strings(apps: Vec<String>) -> Self {
Self(apps.into_iter().map(App).collect())
@ -54,18 +37,21 @@ impl Apps {
self.apps().iter()
}
pub fn check_installed(python: &mut PythonProcess, app: &str) -> Result<bool, TransportError> {
let message = TransportMessage::Json("installed_apps_check".to_string());
let response = python.send(message, Some(vec![app.to_string()]))?;
match response {
TransportResponse::Json(json_str) => {
let json_response: JsonResponse = serde_json::from_str(&json_str)?;
let result = InstalledAppsCheck::try_from(json_response)?;
Ok(result.has_app)
}
_ => Err(TransportError::Process(
"Unexpected response type".to_string(),
pub fn check_installed(python: &mut PythonProcess, app: &str) -> Result<bool, ProcessError> {
let request = messages::Request {
command: Some(messages::request::Command::CheckAppInstalled(
check::AppInstalledRequest {
app_name: app.to_string(),
},
)),
};
let response = python.send(request).map_err(ProcessError::Transport)?;
match response.result {
Some(messages::response::Result::CheckAppInstalled(response)) => Ok(response.passed),
Some(messages::response::Result::Error(e)) => Err(ProcessError::Health(e.message)),
_ => Err(ProcessError::Response),
}
}
}

View file

@ -1,63 +1,26 @@
use crate::apps::Apps;
use crate::gis::{check_gis_setup, GISError};
use crate::templates::TemplateTags;
use djls_ipc::{JsonResponse, PythonProcess, TransportError, TransportMessage, TransportResponse};
use djls_ipc::v1::*;
use djls_ipc::{ProcessError, PythonProcess, TransportError};
use djls_python::{ImportCheck, Python};
use serde::Deserialize;
use std::fmt;
#[derive(Debug)]
pub struct DjangoProject {
py: Python,
python: PythonProcess,
settings_module: String,
installed_apps: Apps,
templatetags: TemplateTags,
}
#[derive(Debug, Deserialize)]
struct DjangoSetup {
installed_apps: Vec<String>,
templatetags: TemplateTags,
}
impl DjangoSetup {
pub fn setup(python: &mut PythonProcess) -> Result<JsonResponse, ProjectError> {
let message = TransportMessage::Json("django_setup".to_string());
let response = python.send(message, None)?;
match response {
TransportResponse::Json(json_str) => {
let json_response: JsonResponse = serde_json::from_str(&json_str)?;
Ok(json_response)
}
_ => Err(ProjectError::Transport(TransportError::Process(
"Unexpected response type".to_string(),
))),
}
}
version: String,
}
impl DjangoProject {
fn new(
py: Python,
python: PythonProcess,
settings_module: String,
installed_apps: Apps,
templatetags: TemplateTags,
) -> Self {
fn new(py: Python, python: PythonProcess, version: String) -> Self {
Self {
py,
python,
settings_module,
installed_apps,
templatetags,
version,
}
}
pub fn setup(mut python: PythonProcess) -> Result<Self, ProjectError> {
let settings_module =
std::env::var("DJANGO_SETTINGS_MODULE").expect("DJANGO_SETTINGS_MODULE must be set");
let py = Python::setup(&mut python)?;
let has_django = ImportCheck::check(&mut python, Some(vec!["django".to_string()]))?;
@ -74,45 +37,52 @@ impl DjangoProject {
return Ok(Self {
py,
python,
settings_module,
installed_apps: Apps::default(),
templatetags: TemplateTags::default(),
version: String::new(),
});
}
let response = DjangoSetup::setup(&mut python)?;
let setup: DjangoSetup = response
.data()
.clone()
.ok_or_else(|| TransportError::Process("No data in response".to_string()))
.and_then(|data| serde_json::from_value(data).map_err(TransportError::Json))?;
let request = messages::Request {
command: Some(messages::request::Command::DjangoGetProjectInfo(
django::GetProjectInfoRequest {},
)),
};
Ok(Self::new(
let response = python
.send(request)
.map_err(|e| ProjectError::Transport(e))?;
let version = match response.result {
Some(messages::response::Result::DjangoGetProjectInfo(response)) => {
response.project.unwrap().version
}
Some(messages::response::Result::Error(e)) => {
return Err(ProjectError::Process(ProcessError::Health(e.message)));
}
_ => {
return Err(ProjectError::Process(ProcessError::Response));
}
};
Ok(Self {
py,
python,
settings_module,
Apps::from_strings(setup.installed_apps.to_vec()),
setup.templatetags,
))
version,
})
}
pub fn py(&self) -> &Python {
&self.py
}
fn settings_module(&self) -> &String {
&self.settings_module
fn version(&self) -> &String {
&self.version
}
}
impl fmt::Display for DjangoProject {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Django Project")?;
writeln!(f, "Settings Module: {}", self.settings_module)?;
writeln!(f, "Installed Apps:")?;
write!(f, "{}", self.installed_apps)?;
writeln!(f, "Template Tags:")?;
write!(f, "{}", self.templatetags)?;
writeln!(f, "Version: {}", self.version)?;
Ok(())
}
}
@ -121,22 +91,18 @@ impl fmt::Display for DjangoProject {
pub enum ProjectError {
#[error("Django is not installed or cannot be imported")]
DjangoNotFound,
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("GIS error: {0}")]
Gis(#[from] GISError),
#[error("JSON parsing error: {0}")]
Json(#[from] serde_json::Error),
#[error(transparent)]
Packaging(#[from] djls_python::PackagingError),
#[error("Process error: {0}")]
Process(#[from] ProcessError),
#[error(transparent)]
Python(#[from] djls_python::PythonError),
#[error("Transport error: {0}")]
Transport(#[from] TransportError),
}

View file

@ -1,5 +1,5 @@
use crate::apps::Apps;
use djls_ipc::{PythonProcess, TransportError};
use djls_ipc::{ProcessError, PythonProcess, TransportError};
use std::process::Command;
pub fn check_gis_setup(python: &mut PythonProcess) -> Result<bool, GISError> {
@ -17,10 +17,10 @@ pub fn check_gis_setup(python: &mut PythonProcess) -> Result<bool, GISError> {
pub enum GISError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("JSON parsing error: {0}")]
Json(#[from] serde_json::Error),
#[error("Process error: {0}")]
Process(#[from] ProcessError),
#[error("Transport error: {0}")]
Transport(#[from] TransportError),
}