wx-cli/src/ipc.rs

165 lines
5.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_json::Value;
/// CLI 向 daemon 发送的请求(换行符分隔 JSON与 Python 版兼容)
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "cmd", rename_all = "snake_case")]
pub enum Request {
Ping,
Sessions {
#[serde(default = "default_limit_20")]
limit: usize,
},
History {
chat: String,
#[serde(default = "default_limit_50")]
limit: usize,
#[serde(default)]
offset: usize,
#[serde(skip_serializing_if = "Option::is_none")]
since: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
until: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
msg_type: Option<i64>,
},
Search {
keyword: String,
#[serde(skip_serializing_if = "Option::is_none")]
chats: Option<Vec<String>>,
#[serde(default = "default_limit_20")]
limit: usize,
#[serde(skip_serializing_if = "Option::is_none")]
since: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
until: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
msg_type: Option<i64>,
},
Contacts {
#[serde(skip_serializing_if = "Option::is_none")]
query: Option<String>,
#[serde(default = "default_limit_50")]
limit: usize,
},
Unread {
#[serde(default = "default_limit_20")]
limit: usize,
/// 按会话类型过滤private / group / official / folded / all支持多选
#[serde(default, skip_serializing_if = "Option::is_none")]
filter: Option<Vec<String>>,
},
Members {
chat: String,
},
NewMessages {
/// 上次检查时各会话的 last_timestamp 快照username -> ts
/// None 表示首次运行,会返回 new_state 供下次使用
#[serde(skip_serializing_if = "Option::is_none")]
state: Option<HashMap<String, i64>>,
#[serde(default = "default_limit_200")]
limit: usize,
},
Stats {
chat: String,
#[serde(skip_serializing_if = "Option::is_none")]
since: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
until: Option<i64>,
},
Favorites {
#[serde(default = "default_limit_50")]
limit: usize,
/// 类型过滤1=文本,2=图片,5=文章,19=名片,20=视频
#[serde(skip_serializing_if = "Option::is_none")]
fav_type: Option<i64>,
/// 内容关键词搜索
#[serde(skip_serializing_if = "Option::is_none")]
query: Option<String>,
},
/// 朋友圈互动通知(点赞 + 评论)
SnsNotifications {
#[serde(default = "default_limit_50")]
limit: usize,
#[serde(skip_serializing_if = "Option::is_none")]
since: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
until: Option<i64>,
/// 包含已读通知(默认仅未读)
#[serde(default)]
include_read: bool,
},
/// 朋友圈时间线(按时间 / 作者筛选帖子)
SnsFeed {
#[serde(default = "default_limit_20")]
limit: usize,
#[serde(skip_serializing_if = "Option::is_none")]
since: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
until: Option<i64>,
/// 作者昵称 / 备注名 / 微信 username模糊匹配
#[serde(skip_serializing_if = "Option::is_none")]
user: Option<String>,
},
/// 查询公众号文章推送biz_message_0.db
BizArticles {
#[serde(default = "default_limit_50")]
limit: usize,
/// 公众号名称过滤(模糊匹配 display nameNone = 全部)
#[serde(skip_serializing_if = "Option::is_none")]
account: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
since: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
until: Option<i64>,
/// 只看有未读消息的公众号,每个公众号取最新 1 篇
#[serde(default)]
unread: bool,
},
/// 朋友圈全文搜索(匹配 contentDesc
SnsSearch {
keyword: String,
#[serde(default = "default_limit_20")]
limit: usize,
#[serde(skip_serializing_if = "Option::is_none")]
since: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
until: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
user: Option<String>,
},
/// 重新加载配置和密钥init --force 后 daemon 不会自动重读)
ReloadConfig,
}
/// daemon 的响应
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Response {
pub ok: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
#[serde(flatten)]
pub data: Value,
}
impl Response {
pub fn ok(data: Value) -> Self {
Self { ok: true, error: None, data }
}
pub fn err(msg: impl Into<String>) -> Self {
Self { ok: false, error: Some(msg.into()), data: Value::Null }
}
pub fn to_json_line(&self) -> anyhow::Result<String> {
let s = serde_json::to_string(self)?;
Ok(s + "\n")
}
}
fn default_limit_20() -> usize { 20 }
fn default_limit_50() -> usize { 50 }
fn default_limit_200() -> usize { 200 }