Skip to content

Commit

Permalink
[QQ] Don't launch lagrange sub-process, just connect it
Browse files Browse the repository at this point in the history
  • Loading branch information
SpriteOvO committed Jul 7, 2024
1 parent d4b00f0 commit 9043bf8
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 205 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ image = "0.25.1"
itertools = "0.12.1"
once_cell = "1.19.0"
paste = "1.0.14"
rand = "0.8.5"
reqwest = { version = "0.11.23", features = ["json", "gzip", "multipart"] }
serde = { version = "1.0.195", features = ["derive", "rc"] }
serde_json = "1.0.111"
Expand Down
23 changes: 3 additions & 20 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use serde::{
},
Deserialize,
};
use spdlog::prelude::*;

use crate::{
notify,
Expand Down Expand Up @@ -137,19 +136,10 @@ pub struct PlatformGlobal {

impl PlatformGlobal {
async fn init(&self) -> anyhow::Result<()> {
#[cfg(feature = "qq")]
if let Some(qq) = &self.qq {
info!("Initializing QQ...");
qq.init().await?;
}
Ok(())
}

fn validate(&self) -> anyhow::Result<()> {
#[cfg(feature = "qq")]
if let Some(qq) = &self.qq {
qq.login.validate()?;
}
if let Some(telegram) = &self.telegram {
telegram.token.as_secret_ref().validate()?;
}
Expand Down Expand Up @@ -380,8 +370,6 @@ const fn default_false() -> bool {

#[cfg(test)]
mod tests {
use std::path::PathBuf;

use super::*;
use crate::reporter::{
ConfigHeartbeat, ConfigHeartbeatHttpGet, ConfigHeartbeatKind, ConfigReporterLog,
Expand All @@ -396,8 +384,7 @@ interval = '1min'
reporter = { log = { notify = ["meow"] }, heartbeat = { type = "HttpGet", url = "https://example.com/", interval = '1min' } }
[platform.QQ]
login = { account = 123456, password = "xyz" }
lagrange = { binary_path = "/tmp/lagrange", http_port = 8000, sign_server = "https://example.com/" }
lagrange = { http_host = "localhost", http_port = 8000 }
[platform.Telegram]
token = "ttt"
Expand Down Expand Up @@ -439,14 +426,10 @@ notify = ["meow", "woof", { ref = "woof", id = 123 }]
}),
platform: Some(PlatformGlobal {
qq: Some(notify::qq::ConfigGlobal {
login: notify::qq::ConfigLogin {
account: notify::qq::ConfigAccount::Account(123456),
password: notify::qq::ConfigPassword::Password("xyz".into())
},
lagrange: notify::qq::lagrange::ConfigLagrange {
binary_path: PathBuf::from("/tmp/lagrange"),
http_host: "localhost".into(),
http_port: 8000,
sign_server: "https://example.com/".into(),
access_token: None,
}
}),
telegram: Some(notify::telegram::ConfigGlobal {
Expand Down
141 changes: 31 additions & 110 deletions src/notify/qq/lagrange.rs
Original file line number Diff line number Diff line change
@@ -1,114 +1,36 @@
use std::{
fmt::Debug,
path::PathBuf,
process::{Child, Command, Stdio},
time::Duration,
};
use std::{fmt::Debug, time::Duration};

use anyhow::{anyhow, ensure};
use rand::distributions::{Alphanumeric, DistString};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::{self as json, json};
use spdlog::prelude::*;
use tokio::{fs, time::timeout};
use tokio::time::timeout;

use super::{ConfigChat, ConfigLogin};
use crate::{cli_args, config::AsSecretRef};
use super::ConfigChat;

#[derive(Clone, Debug, PartialEq, Deserialize)]
pub struct ConfigLagrange {
pub binary_path: PathBuf,
pub http_host: String,
pub http_port: u16,
pub sign_server: String,
pub access_token: Option<String>,
}

pub struct LograngeOnebot {
child: Child,
http_port: u16,
access_token: String,
pub struct LagrangeOnebot<'a> {
config: &'a ConfigLagrange,
}

impl LograngeOnebot {
pub async fn launch(login: &ConfigLogin, lagrange: &ConfigLagrange) -> anyhow::Result<Self> {
let access_token = Alphanumeric.sample_string(&mut rand::thread_rng(), 32);

let appsettings = json!(
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"SignServerUrl": lagrange.sign_server,
"Account": {
"Uin": login.account.as_secret_ref().get_parse_copy()?,
"Password": login.password.as_secret_ref().get_str()?,
"Protocol": "Linux",
"AutoReconnect": true,
"GetOptimumServer": true
},
"Message": {
"IgnoreSelf": true,
"StringPost": false
},
"QrCode": {
"ConsoleCompatibilityMode": false
},
"Implementations": [
{
"Type": "Http",
"Host": "localhost",
"Port": lagrange.http_port,
"AccessToken": access_token
}
]
}
);

#[cfg(debug_assertions)]
info!("logrange access token: {access_token}");

let working_dir = lagrange
.binary_path
.parent()
.ok_or_else(|| anyhow!("binary path of logrange has no parent"))?;
fs::write(
working_dir.join("appsettings.json"),
json::to_string_pretty(&appsettings)?,
)
.await?;

let mut command = Command::new(&lagrange.binary_path);

if let Some(log_dir) = &cli_args().log_dir {
let log_dir = PathBuf::from(log_dir).join("lagrange");
std::fs::create_dir_all(&log_dir)
.map_err(|err| anyhow!("failed to create directories for lagrange logs: {err}"))?;

let mut open_options = std::fs::OpenOptions::new();
open_options.create(true).append(true);

let stdfile = |stream| {
open_options
.open(log_dir.join(format!("lagrange.{stream}")))
.map_err(|err| anyhow!("failed to open {stream} log file for lagrange: {err}"))
};
command
.stdout(stdfile("stdout")?)
.stderr(stdfile("stderr")?);
} else {
command.stdout(Stdio::inherit()).stderr(Stdio::inherit());
};

let child = command.current_dir(working_dir).spawn()?;

Ok(Self {
child,
http_port: lagrange.http_port,
access_token,
})
impl<'a> LagrangeOnebot<'a> {
pub fn new(config: &'a ConfigLagrange) -> Self {
Self { config }
// instance
// .version_info_retry_timeout(Duration::from_secs(5))
// .await
// .map_err(|_| {
// anyhow!(
// "failed to connect Lagrange on '{}:{}'",
// config.http_host,
// config.http_port
// )
// })?;
}

async fn request<T: DeserializeOwned + Debug>(
Expand All @@ -117,12 +39,17 @@ impl LograngeOnebot {
arguments: Option<json::Value>,
) -> anyhow::Result<Response<T>> {
async {
let resp = reqwest::Client::new()
.post(format!("http://localhost:{}/{method}", self.http_port))
.json(&arguments.unwrap_or(json::Value::Null))
.bearer_auth(&self.access_token)
.send()
.await?;
let mut resp = reqwest::Client::new()
.post(format!(
"http://{}:{}/{method}",
self.config.http_host, self.config.http_port
))
.json(&arguments.unwrap_or(json::Value::Null));
if let Some(access_token) = self.config.access_token.as_ref() {
resp = resp.bearer_auth(access_token);
}
let resp = resp.send().await?;

let status = resp.status();
ensure!(
status.is_success(),
Expand Down Expand Up @@ -187,12 +114,6 @@ impl LograngeOnebot {
}
}

impl Drop for LograngeOnebot {
fn drop(&mut self) {
_ = self.child.kill();
}
}

#[derive(Clone, Debug, PartialEq, Deserialize)]
pub struct Response<T> {
pub status: String,
Expand Down
Loading

0 comments on commit 9043bf8

Please sign in to comment.