diff --git a/Cargo.toml b/Cargo.toml index 99c0759..bc62b20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dingtalk" -version = "0.1.2" +version = "0.2.0" authors = ["Hatter Jiang "] edition = "2018" description = "DingTalk Util" diff --git a/src/lib.rs b/src/lib.rs index b3f8e80..d34051a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,9 @@ #[macro_use] extern crate json; +use std::fs; +use std::env; +use std::path::PathBuf; use std::time::SystemTime; use std::io::{ Error, @@ -15,6 +18,8 @@ use crypto::{ sha2::Sha256, }; +pub type XResult = Result>; + const CONTENT_TYPE: &str = "Content-Type"; const APPLICATION_JSON_UTF8: &str = "application/json; charset=utf-8"; @@ -134,8 +139,48 @@ impl <'a> DingTalkMessage<'a> { } } +#[test] +fn my_simple_test() { + let dt = DingTalk::from_file("~/.dingtalk-token.json").unwrap(); + dt.send_text("test").ok(); +} + impl <'a> DingTalk<'a> { + /// Create `DingTalk` from file + /// + /// Format: + /// ```json + /// { + /// "default_webhook_url": "", // option + /// "access_token": "", + /// "sec_token": "" // option + /// } + /// ``` + pub fn from_file(f: &str) -> XResult { + let f_path_buf = if f.starts_with("~/") { + let home = PathBuf::from(env::var("HOME")?); + home.join(f.chars().skip(2).collect::()) + } else { + PathBuf::from(f) + }; + let f_content = fs::read_to_string(f_path_buf)?; + let f_json_value = json::parse(&f_content)?; + if !f_json_value.is_object() { + return Err(Box::new(Error::new(ErrorKind::Other, format!("JSON format erorr: {}", f_content)))); + } + + let default_webhook_url: &'a str = Self::string_to_a_str(f_json_value["default_webhook_url"].as_str().unwrap_or(DEFAULT_DINGTALK_ROBOT_URL).to_owned()); + let access_token: &'a str = Self::string_to_a_str(f_json_value["access_token"].as_str().unwrap_or_default().to_owned()); + let sec_token: &'a str = Self::string_to_a_str(f_json_value["sec_token"].as_str().unwrap_or_default().to_owned()); + + Ok(DingTalk { + default_webhook_url: default_webhook_url, + access_token: access_token, + sec_token: sec_token, + }) + } + /// Create `DingTalk` /// `access_token` is access token, `sec_token` can be empty `""` pub fn new(access_token: &'a str, sec_token: &'a str) -> Self { @@ -152,7 +197,7 @@ impl <'a> DingTalk<'a> { } /// Send DingTalk message - pub fn send_message(&self, dingtalk_message: &DingTalkMessage) -> Result<(), Box> { + pub fn send_message(&self, dingtalk_message: &DingTalkMessage) -> XResult<()> { let mut message_json = match dingtalk_message.message_type { DingTalkMessageType::TEXT => object!{ "msgtype" => "text", @@ -191,22 +236,22 @@ impl <'a> DingTalk<'a> { } /// Send text message - pub fn send_text(&self, text_message: &str) -> Result<(), Box> { + pub fn send_text(&self, text_message: &str) -> XResult<()> { self.send_message(&DingTalkMessage::new_text(text_message)) } /// Send markdown message - pub fn send_markdown(&self, title: &str, text: &str) -> Result<(), Box> { + pub fn send_markdown(&self, title: &str, text: &str) -> XResult<()> { self.send_message(&DingTalkMessage::new_markdown(title, text)) } /// Send link message - pub fn send_link(&self, link_title: &'a str, link_text: &'a str, link_pic_url: &'a str, link_message_url: &'a str) -> Result<(), Box> { + pub fn send_link(&self, link_title: &'a str, link_text: &'a str, link_pic_url: &'a str, link_message_url: &'a str) -> XResult<()> { self.send_message(&DingTalkMessage::new_link(link_title, link_text, link_pic_url, link_message_url)) } /// Direct send JSON message - pub fn send(&self, json_message: &str) -> Result<(), Box> { + pub fn send(&self, json_message: &str) -> XResult<()> { let client = reqwest::Client::new(); let response = client.post(&self.generate_signed_url()) .header(CONTENT_TYPE, APPLICATION_JSON_UTF8) @@ -238,6 +283,11 @@ impl <'a> DingTalk<'a> { signed_url } + + // SAFE? cause memory leak? + fn string_to_a_str(s: String) -> &'a str { + Box::leak(s.into_boxed_str()) + } } /// calc hma_sha256 digest