1use serde::Serialize;
2use serde_json::{Map, Value};
3
4use crate::{CCCCClient, Error, MessageMode, Result};
5
6#[derive(Clone, Debug, Serialize)]
8pub struct ConnectCatalogOptions {
9 pub group_id: String,
10 #[serde(skip_serializing_if = "Option::is_none")]
11 pub instance_id: Option<String>,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub target_group_id: Option<String>,
14 #[serde(skip_serializing_if = "Option::is_none")]
15 pub by: Option<String>,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub after: Option<String>,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub limit: Option<u32>,
20}
21
22#[derive(Clone, Debug, Serialize)]
24pub struct ConnectSendOptions {
25 pub group_id: String,
26 pub instance_id: String,
27 pub target_group_id: String,
28 pub client_id: String,
29 pub text: String,
30 pub message_mode: MessageMode,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 pub by: Option<String>,
33 #[serde(skip_serializing_if = "Option::is_none")]
34 pub to: Option<Vec<String>>,
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub format: Option<String>,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub insight: Option<String>,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub attachments: Option<Vec<Value>>,
41}
42
43impl ConnectSendOptions {
44 fn arguments(&self) -> Result<Map<String, Value>> {
45 if self.client_id.trim().is_empty() || self.client_id.len() > 128 {
46 return Err(Error::InvalidArgument(
47 "client_id must be non-empty and at most 128 UTF-8 bytes".into(),
48 ));
49 }
50 Ok(serde_json::from_value(serde_json::to_value(self)?)?)
51 }
52}
53
54impl CCCCClient {
55 pub fn connect_catalog(&self, options: &ConnectCatalogOptions) -> Result<Map<String, Value>> {
56 self.call(
57 "connect_catalog",
58 serde_json::from_value(serde_json::to_value(options)?)?,
59 )
60 }
61
62 pub fn connect_send(&self, options: &ConnectSendOptions) -> Result<Map<String, Value>> {
63 self.call("connect_send", options.arguments()?)
64 }
65
66 pub fn connect_send_files(
68 &self,
69 options: &ConnectSendOptions,
70 paths: &[String],
71 ) -> Result<Map<String, Value>> {
72 if paths.is_empty() || paths.iter().any(|path| path.trim().is_empty()) {
73 return Err(Error::InvalidArgument(
74 "paths must contain one or more non-empty paths".into(),
75 ));
76 }
77 if options.attachments.is_some() {
78 return Err(Error::InvalidArgument(
79 "connect_send_files takes paths, not attachments".into(),
80 ));
81 }
82 let mut args = options.arguments()?;
83 args.insert("paths".into(), serde_json::to_value(paths)?);
84 self.call("connect_send_files", args)
85 }
86}