mirror of
https://github.com/joshuadavidthomas/django-language-server.git
synced 2025-07-16 08:55:04 +00:00
add protobuf transport and refactor to support (#24)
This commit is contained in:
parent
b3e0ee7b6e
commit
643a47953e
21 changed files with 406 additions and 74 deletions
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
|
@ -35,6 +35,11 @@ jobs:
|
|||
enable-cache: true
|
||||
version: ${{ env.UV_VERSION }}
|
||||
|
||||
- name: Install Protoc
|
||||
uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install dependencies and build
|
||||
run: |
|
||||
uv sync --frozen
|
||||
|
|
37
.just/proto.just
Normal file
37
.just/proto.just
Normal file
|
@ -0,0 +1,37 @@
|
|||
set unstable := true
|
||||
|
||||
justfile := justfile_directory() + "/.just/proto.just"
|
||||
|
||||
[private]
|
||||
default:
|
||||
@just --list --justfile {{ justfile }}
|
||||
|
||||
[no-cd]
|
||||
[private]
|
||||
check:
|
||||
#!/usr/bin/env sh
|
||||
if ! command -v protoc > /dev/null 2>&1; then
|
||||
echo "protoc is not installed. Please install protobuf-compiler"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[private]
|
||||
fmt:
|
||||
@just --fmt --justfile {{ justfile }}
|
||||
|
||||
# Generate protobuf code for both Rust and Python
|
||||
[no-cd]
|
||||
gen:
|
||||
@just proto rust
|
||||
@just proto py
|
||||
|
||||
# Generate protobuf code for Rust
|
||||
[no-cd]
|
||||
rust: check
|
||||
cargo build -p djls-types
|
||||
|
||||
# Generate protobuf code for Python
|
||||
[no-cd]
|
||||
py: check
|
||||
protoc -I=proto --python_out=python/djls proto/*.proto
|
||||
|
|
@ -9,10 +9,13 @@ djls-django = { path = "crates/djls-django" }
|
|||
djls-ipc = { path = "crates/djls-ipc" }
|
||||
djls-python = { path = "crates/djls-python" }
|
||||
djls-server = { path = "crates/djls-server" }
|
||||
djls-types = { path = "crates/djls-types" }
|
||||
djls-worker = { path = "crates/djls-worker" }
|
||||
|
||||
anyhow = "1.0.94"
|
||||
async-trait = "0.1.83"
|
||||
prost = "0.13"
|
||||
bytes = "1.9"
|
||||
serde = { version = "1.0.215", features = ["derive"] }
|
||||
serde_json = "1.0.133"
|
||||
thiserror = "2.0.6"
|
||||
|
|
2
Justfile
2
Justfile
|
@ -1,6 +1,8 @@
|
|||
set dotenv-load := true
|
||||
set unstable := true
|
||||
|
||||
mod proto ".just/proto.just"
|
||||
|
||||
# List all available commands
|
||||
[private]
|
||||
default:
|
||||
|
|
|
@ -9,6 +9,7 @@ djls-ipc = { workspace = true }
|
|||
djls-server = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
clap = { version = "4.5.23", features = ["derive"] }
|
||||
|
|
|
@ -33,10 +33,6 @@ impl CommonOpts {
|
|||
enum Commands {
|
||||
/// Start the LSP server
|
||||
Serve(CommonOpts),
|
||||
/// Get Python environment information
|
||||
Info(CommonOpts),
|
||||
/// Print the version
|
||||
Version(CommonOpts),
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
|
@ -49,22 +45,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
PythonProcess::new("djls.lsp", Transport::Json, opts.health_check_interval())?;
|
||||
djls_server::serve(python).await?
|
||||
}
|
||||
Commands::Info(opts) => {
|
||||
let mut python =
|
||||
PythonProcess::new("djls.lsp", Transport::Json, opts.health_check_interval())?;
|
||||
match python.send("python_setup", None) {
|
||||
Ok(info) => println!("{}", info),
|
||||
Err(e) => eprintln!("Failed to get info: {}", e),
|
||||
}
|
||||
}
|
||||
Commands::Version(opts) => {
|
||||
let mut python =
|
||||
PythonProcess::new("djls.lsp", Transport::Json, opts.health_check_interval())?;
|
||||
match python.send("version", None) {
|
||||
Ok(version) => println!("Python module version: {}", version),
|
||||
Err(e) => eprintln!("Failed to get version: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use djls_ipc::{parse_json_response, JsonResponse, PythonProcess, TransportError};
|
||||
use djls_ipc::{JsonResponse, PythonProcess, TransportError, TransportMessage, TransportResponse};
|
||||
use serde::Deserialize;
|
||||
use std::fmt;
|
||||
|
||||
|
@ -55,10 +55,18 @@ impl Apps {
|
|||
}
|
||||
|
||||
pub fn check_installed(python: &mut PythonProcess, app: &str) -> Result<bool, TransportError> {
|
||||
let response = python.send("installed_apps_check", Some(vec![app.to_string()]))?;
|
||||
let response = parse_json_response(response)?;
|
||||
let result = InstalledAppsCheck::try_from(response)?;
|
||||
Ok(result.has_app)
|
||||
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(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::apps::Apps;
|
||||
use crate::gis::{check_gis_setup, GISError};
|
||||
use crate::templates::TemplateTags;
|
||||
use djls_ipc::{parse_json_response, JsonResponse, PythonProcess, TransportError};
|
||||
use djls_ipc::{JsonResponse, PythonProcess, TransportError, TransportMessage, TransportResponse};
|
||||
use djls_python::{ImportCheck, Python};
|
||||
use serde::Deserialize;
|
||||
use std::fmt;
|
||||
|
@ -23,9 +23,17 @@ struct DjangoSetup {
|
|||
|
||||
impl DjangoSetup {
|
||||
pub fn setup(python: &mut PythonProcess) -> Result<JsonResponse, ProjectError> {
|
||||
let response = python.send("django_setup", None)?;
|
||||
let response = parse_json_response(response)?;
|
||||
Ok(response)
|
||||
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(),
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,12 @@ version = "0.0.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
djls-types = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
prost = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
|
|
@ -7,3 +7,5 @@ pub use transport::parse_raw_response;
|
|||
pub use transport::JsonResponse;
|
||||
pub use transport::Transport;
|
||||
pub use transport::TransportError;
|
||||
pub use transport::TransportMessage;
|
||||
pub use transport::TransportResponse;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::transport::{Transport, TransportError, TransportProtocol};
|
||||
use crate::transport::{
|
||||
Transport, TransportError, TransportMessage, TransportProtocol, TransportResponse,
|
||||
};
|
||||
use std::process::{Child, Command, Stdio};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
@ -72,9 +74,9 @@ impl PythonProcess {
|
|||
|
||||
pub fn send(
|
||||
&mut self,
|
||||
message: &str,
|
||||
message: TransportMessage,
|
||||
args: Option<Vec<String>>,
|
||||
) -> Result<String, TransportError> {
|
||||
) -> Result<TransportResponse, TransportError> {
|
||||
let mut transport = self.transport.lock().unwrap();
|
||||
transport.send(message, args)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use djls_types::proto::*;
|
||||
use prost::Message;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::fmt::Debug;
|
||||
use std::io::Read;
|
||||
use std::io::{BufRead, BufReader, BufWriter, Write};
|
||||
use std::process::{ChildStdin, ChildStdout};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
@ -19,6 +22,7 @@ pub enum TransportError {
|
|||
pub enum Transport {
|
||||
Raw,
|
||||
Json,
|
||||
Protobuf,
|
||||
}
|
||||
|
||||
impl Transport {
|
||||
|
@ -30,6 +34,7 @@ impl Transport {
|
|||
let transport_type = match self {
|
||||
Transport::Raw => "raw",
|
||||
Transport::Json => "json",
|
||||
Transport::Protobuf => "protobuf",
|
||||
};
|
||||
|
||||
writeln!(stdin, "{}", transport_type).map_err(TransportError::Io)?;
|
||||
|
@ -48,10 +53,25 @@ impl Transport {
|
|||
match self {
|
||||
Transport::Raw => Ok(Box::new(RawTransport::new(stdin, stdout)?)),
|
||||
Transport::Json => Ok(Box::new(JsonTransport::new(stdin, stdout)?)),
|
||||
Transport::Protobuf => Ok(Box::new(ProtobufTransport::new(stdin, stdout)?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TransportMessage {
|
||||
Raw(String),
|
||||
Json(String),
|
||||
Protobuf(ToAgent),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TransportResponse {
|
||||
Raw(String),
|
||||
Json(String),
|
||||
Protobuf(FromAgent),
|
||||
}
|
||||
|
||||
pub trait TransportProtocol: Debug + Send {
|
||||
fn new(stdin: ChildStdin, stdout: ChildStdout) -> Result<Self, TransportError>
|
||||
where
|
||||
|
@ -60,11 +80,15 @@ pub trait TransportProtocol: Debug + Send {
|
|||
fn clone_box(&self) -> Box<dyn TransportProtocol>;
|
||||
fn send_impl(
|
||||
&mut self,
|
||||
message: &str,
|
||||
message: TransportMessage,
|
||||
args: Option<Vec<String>>,
|
||||
) -> Result<String, TransportError>;
|
||||
) -> Result<TransportResponse, TransportError>;
|
||||
|
||||
fn send(&mut self, message: &str, args: Option<Vec<String>>) -> Result<String, TransportError> {
|
||||
fn send(
|
||||
&mut self,
|
||||
message: TransportMessage,
|
||||
args: Option<Vec<String>>,
|
||||
) -> Result<TransportResponse, TransportError> {
|
||||
self.health_check()?;
|
||||
self.send_impl(message, args)
|
||||
}
|
||||
|
@ -91,13 +115,16 @@ impl TransportProtocol for RawTransport {
|
|||
}
|
||||
|
||||
fn health_check(&mut self) -> Result<(), TransportError> {
|
||||
self.send_impl("health", None)
|
||||
.and_then(|response| match response.as_str() {
|
||||
"ok" => Ok(()),
|
||||
other => Err(TransportError::Process(format!(
|
||||
self.send_impl(TransportMessage::Raw("health".to_string()), None)
|
||||
.and_then(|response| match response {
|
||||
TransportResponse::Raw(s) if s == "ok" => Ok(()),
|
||||
TransportResponse::Raw(other) => Err(TransportError::Process(format!(
|
||||
"Health check failed: {}",
|
||||
other
|
||||
))),
|
||||
_ => Err(TransportError::Process(
|
||||
"Unexpected response type".to_string(),
|
||||
)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -110,16 +137,24 @@ impl TransportProtocol for RawTransport {
|
|||
|
||||
fn send_impl(
|
||||
&mut self,
|
||||
message: &str,
|
||||
message: TransportMessage,
|
||||
args: Option<Vec<String>>,
|
||||
) -> Result<String, TransportError> {
|
||||
) -> Result<TransportResponse, TransportError> {
|
||||
let mut writer = self.writer.lock().unwrap();
|
||||
|
||||
if let Some(args) = args {
|
||||
// Join command and args with spaces
|
||||
writeln!(writer, "{} {}", message, args.join(" ")).map_err(TransportError::Io)?;
|
||||
} else {
|
||||
writeln!(writer, "{}", message).map_err(TransportError::Io)?;
|
||||
match message {
|
||||
TransportMessage::Raw(msg) => {
|
||||
if let Some(args) = args {
|
||||
writeln!(writer, "{} {}", msg, args.join(" ")).map_err(TransportError::Io)?;
|
||||
} else {
|
||||
writeln!(writer, "{}", msg).map_err(TransportError::Io)?;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(TransportError::Process(
|
||||
"Raw transport only accepts raw messages".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
writer.flush().map_err(TransportError::Io)?;
|
||||
|
@ -127,7 +162,7 @@ impl TransportProtocol for RawTransport {
|
|||
let mut reader = self.reader.lock().unwrap();
|
||||
let mut line = String::new();
|
||||
reader.read_line(&mut line).map_err(TransportError::Io)?;
|
||||
Ok(line.trim().to_string())
|
||||
Ok(TransportResponse::Raw(line.trim().to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,15 +200,21 @@ impl TransportProtocol for JsonTransport {
|
|||
}
|
||||
|
||||
fn health_check(&mut self) -> Result<(), TransportError> {
|
||||
self.send_impl("health", None).and_then(|response| {
|
||||
let json: JsonResponse = serde_json::from_str(&response)?;
|
||||
match json.status.as_str() {
|
||||
"ok" => Ok(()),
|
||||
self.send_impl(TransportMessage::Json("health".to_string()), None)
|
||||
.and_then(|response| match response {
|
||||
TransportResponse::Json(json) => {
|
||||
let resp: JsonResponse = serde_json::from_str(&json)?;
|
||||
match resp.status.as_str() {
|
||||
"ok" => Ok(()),
|
||||
_ => Err(TransportError::Process(
|
||||
resp.error.unwrap_or_else(|| "Unknown error".to_string()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
_ => Err(TransportError::Process(
|
||||
json.error.unwrap_or_else(|| "Unknown error".to_string()),
|
||||
"Unexpected response type".to_string(),
|
||||
)),
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn TransportProtocol> {
|
||||
|
@ -185,23 +226,110 @@ impl TransportProtocol for JsonTransport {
|
|||
|
||||
fn send_impl(
|
||||
&mut self,
|
||||
message: &str,
|
||||
message: TransportMessage,
|
||||
args: Option<Vec<String>>,
|
||||
) -> Result<String, TransportError> {
|
||||
let command = JsonCommand {
|
||||
command: message.to_string(),
|
||||
args,
|
||||
};
|
||||
|
||||
) -> Result<TransportResponse, TransportError> {
|
||||
let mut writer = self.writer.lock().unwrap();
|
||||
serde_json::to_writer(&mut *writer, &command)?;
|
||||
writeln!(writer).map_err(TransportError::Io)?;
|
||||
|
||||
match message {
|
||||
TransportMessage::Json(msg) => {
|
||||
let command = JsonCommand { command: msg, args };
|
||||
serde_json::to_writer(&mut *writer, &command)?;
|
||||
writeln!(writer).map_err(TransportError::Io)?;
|
||||
}
|
||||
_ => {
|
||||
return Err(TransportError::Process(
|
||||
"JSON transport only accepts JSON messages".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
writer.flush().map_err(TransportError::Io)?;
|
||||
|
||||
let mut reader = self.reader.lock().unwrap();
|
||||
let mut line = String::new();
|
||||
reader.read_line(&mut line).map_err(TransportError::Io)?;
|
||||
Ok(line.trim().to_string())
|
||||
Ok(TransportResponse::Json(line.trim().to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProtobufTransport {
|
||||
reader: Arc<Mutex<BufReader<ChildStdout>>>,
|
||||
writer: Arc<Mutex<BufWriter<ChildStdin>>>,
|
||||
}
|
||||
|
||||
impl TransportProtocol for ProtobufTransport {
|
||||
fn new(stdin: ChildStdin, stdout: ChildStdout) -> Result<Self, TransportError> {
|
||||
Ok(Self {
|
||||
reader: Arc::new(Mutex::new(BufReader::new(stdout))),
|
||||
writer: Arc::new(Mutex::new(BufWriter::new(stdin))),
|
||||
})
|
||||
}
|
||||
|
||||
fn health_check(&mut self) -> Result<(), TransportError> {
|
||||
let request = ToAgent {
|
||||
command: Some(to_agent::Command::HealthCheck(HealthCheck {})),
|
||||
};
|
||||
|
||||
match self.send_impl(TransportMessage::Protobuf(request), None)? {
|
||||
TransportResponse::Protobuf(FromAgent {
|
||||
message: Some(from_agent::Message::Error(e)),
|
||||
}) => Err(TransportError::Process(e.message)),
|
||||
TransportResponse::Protobuf(FromAgent {
|
||||
message: Some(from_agent::Message::HealthCheck(_)),
|
||||
}) => Ok(()),
|
||||
_ => Err(TransportError::Process("Unexpected response".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn TransportProtocol> {
|
||||
Box::new(ProtobufTransport {
|
||||
reader: self.reader.clone(),
|
||||
writer: self.writer.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn send_impl(
|
||||
&mut self,
|
||||
message: TransportMessage,
|
||||
_args: Option<Vec<String>>,
|
||||
) -> Result<TransportResponse, TransportError> {
|
||||
let mut writer = self.writer.lock().unwrap();
|
||||
|
||||
match message {
|
||||
TransportMessage::Protobuf(msg) => {
|
||||
let buf = msg.encode_to_vec();
|
||||
writer
|
||||
.write_all(&(buf.len() as u32).to_be_bytes())
|
||||
.map_err(TransportError::Io)?;
|
||||
writer.write_all(&buf).map_err(TransportError::Io)?;
|
||||
}
|
||||
_ => {
|
||||
return Err(TransportError::Process(
|
||||
"Protobuf transport only accepts protobuf messages".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
writer.flush().map_err(TransportError::Io)?;
|
||||
|
||||
let mut reader = self.reader.lock().unwrap();
|
||||
let mut length_bytes = [0u8; 4];
|
||||
reader
|
||||
.read_exact(&mut length_bytes)
|
||||
.map_err(TransportError::Io)?;
|
||||
let length = u32::from_be_bytes(length_bytes);
|
||||
|
||||
let mut message_bytes = vec![0u8; length as usize];
|
||||
reader
|
||||
.read_exact(&mut message_bytes)
|
||||
.map_err(TransportError::Io)?;
|
||||
|
||||
let response = FromAgent::decode(message_bytes.as_slice())
|
||||
.map_err(|e| TransportError::Process(e.to_string()))?;
|
||||
|
||||
Ok(TransportResponse::Protobuf(response))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use djls_ipc::{parse_json_response, JsonResponse, PythonProcess, TransportError};
|
||||
use djls_ipc::{JsonResponse, PythonProcess, TransportError, TransportMessage, TransportResponse};
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
@ -78,10 +78,18 @@ impl ImportCheck {
|
|||
python: &mut PythonProcess,
|
||||
modules: Option<Vec<String>>,
|
||||
) -> Result<bool, PackagingError> {
|
||||
let response = python.send("has_import", modules)?;
|
||||
let response = parse_json_response(response)?;
|
||||
let check = Self::try_from(response)?;
|
||||
Ok(check.can_import)
|
||||
let message = TransportMessage::Json("has_import".to_string());
|
||||
let response = python.send(message, modules)?;
|
||||
match response {
|
||||
TransportResponse::Json(json_str) => {
|
||||
let json_response: JsonResponse = serde_json::from_str(&json_str)?;
|
||||
let check = Self::try_from(json_response)?;
|
||||
Ok(check.can_import)
|
||||
}
|
||||
_ => Err(PackagingError::Transport(TransportError::Process(
|
||||
"Unexpected response type".to_string(),
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::packaging::{Packages, PackagingError};
|
||||
use djls_ipc::{parse_json_response, JsonResponse, PythonProcess, TransportError};
|
||||
use djls_ipc::{JsonResponse, PythonProcess, TransportError, TransportMessage, TransportResponse};
|
||||
use serde::Deserialize;
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
|
@ -72,9 +72,17 @@ impl TryFrom<JsonResponse> for Python {
|
|||
|
||||
impl Python {
|
||||
pub fn setup(python: &mut PythonProcess) -> Result<Self, PythonError> {
|
||||
let response = python.send("python_setup", None)?;
|
||||
let response = parse_json_response(response)?;
|
||||
Ok(Self::try_from(response)?)
|
||||
let message = TransportMessage::Json("python_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(Self::try_from(json_response)?)
|
||||
}
|
||||
_ => Err(PythonError::Transport(TransportError::Process(
|
||||
"Unexpected response type".to_string(),
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
11
crates/djls-types/Cargo.toml
Normal file
11
crates/djls-types/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "djls-types"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
prost = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
prost-build = "0.13"
|
24
crates/djls-types/build.rs
Normal file
24
crates/djls-types/build.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
let workspace_root = manifest_dir.parent().unwrap().parent().unwrap();
|
||||
let proto_dir = workspace_root.join("proto");
|
||||
|
||||
let protos: Vec<_> = fs::read_dir(&proto_dir)
|
||||
.unwrap()
|
||||
.filter_map(Result::ok)
|
||||
.filter(|entry| entry.path().extension().and_then(|s| s.to_str()) == Some("proto"))
|
||||
.map(|entry| entry.path())
|
||||
.collect();
|
||||
|
||||
prost_build::compile_protos(
|
||||
&protos
|
||||
.iter()
|
||||
.map(|p| p.to_str().unwrap())
|
||||
.collect::<Vec<_>>(),
|
||||
&[proto_dir],
|
||||
)
|
||||
.unwrap();
|
||||
}
|
5
crates/djls-types/src/lib.rs
Normal file
5
crates/djls-types/src/lib.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
pub mod proto {
|
||||
include!(concat!(env!("OUT_DIR"), "/djls.rs"));
|
||||
}
|
||||
|
||||
use proto::*;
|
29
proto/messages.proto
Normal file
29
proto/messages.proto
Normal file
|
@ -0,0 +1,29 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package djls;
|
||||
|
||||
// Commands we send to Python
|
||||
message ToAgent {
|
||||
oneof command {
|
||||
HealthCheck health_check = 1;
|
||||
Shutdown shutdown = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message HealthCheck {}
|
||||
message Shutdown {}
|
||||
|
||||
// Responses we get back
|
||||
message FromAgent {
|
||||
oneof message {
|
||||
HealthCheckResponse health_check = 1;
|
||||
Error error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message HealthCheckResponse {}
|
||||
|
||||
message Error {
|
||||
string message = 1;
|
||||
string traceback = 2; // Optional stack trace from Python
|
||||
}
|
|
@ -13,6 +13,7 @@ authors = [
|
|||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"django>=4.2",
|
||||
"protobuf>=5.29.1",
|
||||
]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
|
|
46
python/djls/messages_pb2.py
Normal file
46
python/djls/messages_pb2.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# NO CHECKED-IN PROTOBUF GENCODE
|
||||
# source: messages.proto
|
||||
# Protobuf Python Version: 5.29.1
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import runtime_version as _runtime_version
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
_runtime_version.ValidateProtobufRuntimeVersion(
|
||||
_runtime_version.Domain.PUBLIC,
|
||||
5,
|
||||
29,
|
||||
1,
|
||||
'',
|
||||
'messages.proto'
|
||||
)
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0emessages.proto\x12\x04\x64jls\"c\n\x07ToAgent\x12)\n\x0chealth_check\x18\x01 \x01(\x0b\x32\x11.djls.HealthCheckH\x00\x12\"\n\x08shutdown\x18\x02 \x01(\x0b\x32\x0e.djls.ShutdownH\x00\x42\t\n\x07\x63ommand\"\r\n\x0bHealthCheck\"\n\n\x08Shutdown\"g\n\tFromAgent\x12\x31\n\x0chealth_check\x18\x01 \x01(\x0b\x32\x19.djls.HealthCheckResponseH\x00\x12\x1c\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x0b.djls.ErrorH\x00\x42\t\n\x07message\"\x15\n\x13HealthCheckResponse\"+\n\x05\x45rror\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x11\n\ttraceback\x18\x02 \x01(\tb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'messages_pb2', _globals)
|
||||
if not _descriptor._USE_C_DESCRIPTORS:
|
||||
DESCRIPTOR._loaded_options = None
|
||||
_globals['_TOAGENT']._serialized_start=24
|
||||
_globals['_TOAGENT']._serialized_end=123
|
||||
_globals['_HEALTHCHECK']._serialized_start=125
|
||||
_globals['_HEALTHCHECK']._serialized_end=138
|
||||
_globals['_SHUTDOWN']._serialized_start=140
|
||||
_globals['_SHUTDOWN']._serialized_end=150
|
||||
_globals['_FROMAGENT']._serialized_start=152
|
||||
_globals['_FROMAGENT']._serialized_end=255
|
||||
_globals['_HEALTHCHECKRESPONSE']._serialized_start=257
|
||||
_globals['_HEALTHCHECKRESPONSE']._serialized_end=278
|
||||
_globals['_ERROR']._serialized_start=280
|
||||
_globals['_ERROR']._serialized_end=323
|
||||
# @@protoc_insertion_point(module_scope)
|
22
uv.lock
generated
22
uv.lock
generated
|
@ -63,6 +63,7 @@ version = "0.1.0"
|
|||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
{ name = "protobuf" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
|
@ -72,7 +73,10 @@ dev = [
|
|||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "django", specifier = ">=4.2" }]
|
||||
requires-dist = [
|
||||
{ name = "django", specifier = ">=4.2" },
|
||||
{ name = "protobuf", specifier = ">=5.29.1" },
|
||||
]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
|
@ -80,6 +84,22 @@ dev = [
|
|||
{ name = "ruff", specifier = ">=0.8.2" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "5.29.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d2/4f/1639b7b1633d8fd55f216ba01e21bf2c43384ab25ef3ddb35d85a52033e8/protobuf-5.29.1.tar.gz", hash = "sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb", size = 424965 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/50/c7/28669b04691a376cf7d0617d612f126aa0fff763d57df0142f9bf474c5b8/protobuf-5.29.1-cp310-abi3-win32.whl", hash = "sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110", size = 422706 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/33/dc7a7712f457456b7e0b16420ab8ba1cc8686751d3f28392eb43d0029ab9/protobuf-5.29.1-cp310-abi3-win_amd64.whl", hash = "sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34", size = 434505 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/39/44239fb1c6ec557e1731d996a5de89a9eb1ada7a92491fcf9c5d714052ed/protobuf-5.29.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18", size = 417822 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/4a/ec56f101d38d4bef2959a9750209809242d86cf8b897db00f2f98bfa360e/protobuf-5.29.1-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155", size = 319572 },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/52/c97c58a33b3d6c89a8138788576d372a90a6556f354799971c6b4d16d871/protobuf-5.29.1-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d", size = 319671 },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/19/5a3957e08de18578131810563ccfeebc7d2aad31ee52e367a61f56cc3cab/protobuf-5.29.1-cp39-cp39-win32.whl", hash = "sha256:5a41deccfa5e745cef5c65a560c76ec0ed8e70908a67cc8f4da5fce588b50d57", size = 422671 },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/67/8bc07bb755c8badf08db4a8bc2eb542a4e733135a6d584d1922b701d7751/protobuf-5.29.1-cp39-cp39-win_amd64.whl", hash = "sha256:012ce28d862ff417fd629285aca5d9772807f15ceb1a0dbd15b88f58c776c98c", size = 434591 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/24/c8c49df8f6587719e1d400109b16c10c6902d0c9adddc8fff82840146f99/protobuf-5.29.1-py3-none-any.whl", hash = "sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0", size = 172547 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.8.2"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue