mirror of
https://github.com/System-End/slack-morphism-rust.git
synced 2026-04-19 19:45:13 +00:00
Slack client module
This commit is contained in:
parent
ebbe7714c7
commit
c16d33c0a9
10 changed files with 241 additions and 41 deletions
|
|
@ -2,5 +2,6 @@
|
|||
|
||||
members = [
|
||||
"src/models",
|
||||
"src/client",
|
||||
"src/examples"
|
||||
]
|
||||
22
src/client/Cargo.toml
Normal file
22
src/client/Cargo.toml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
name = "slack-morphism-client"
|
||||
version = "0.1.0"
|
||||
authors = ["Abdulla Abdurakhmanov <abdulla@latestbit.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "slack_morphism_client"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
slack-morphism-models = { path = "../models", version = "0.1.0" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_with = "1.4"
|
||||
rvs_derive = "0.1"
|
||||
rsb_derive = "0.2"
|
||||
hyper = "0.13"
|
||||
tokio = { version = "0.2", features = ["full"] }
|
||||
url = "2.1"
|
||||
futures = "0.3"
|
||||
bytes = "0.5"
|
||||
1
src/client/src/chat/mod.rs
Normal file
1
src/client/src/chat/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
160
src/client/src/lib.rs
Normal file
160
src/client/src/lib.rs
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
pub mod chat;
|
||||
|
||||
use bytes::buf::BufExt as _;
|
||||
use hyper::client::*;
|
||||
use hyper::{Body, Request, Uri};
|
||||
use rsb_derive::Builder;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Builder)]
|
||||
pub struct SlackApiToken {
|
||||
value: String,
|
||||
workspace_id: Option<String>,
|
||||
scope: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SlackClient {
|
||||
connector: Client<HttpConnector>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SlackClientSession<'a> {
|
||||
client: &'a SlackClient,
|
||||
token: SlackApiToken,
|
||||
}
|
||||
|
||||
pub type ClientResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
impl SlackClient {
|
||||
const SLACK_API_URI_STR: &'static str = "https://slack.com/api";
|
||||
|
||||
fn create_method_uri_path(method_relative_uri: &str) -> String {
|
||||
format!("{}/{}", SlackClient::SLACK_API_URI_STR, method_relative_uri)
|
||||
}
|
||||
|
||||
fn create_url(url_str: &String) -> Uri {
|
||||
url_str.parse().unwrap()
|
||||
}
|
||||
|
||||
fn create_url_with_params<PT, TS>(url_str: &String, params: PT) -> Uri
|
||||
where
|
||||
PT: std::iter::IntoIterator<Item = (TS, Option<TS>)>,
|
||||
TS: std::string::ToString,
|
||||
{
|
||||
let url_query_params: Vec<(String, String)> = params
|
||||
.into_iter()
|
||||
.map(|(k, vo)| vo.map(|v| (k.to_string(), v.to_string())))
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
Url::parse_with_params(url_str.as_str(), url_query_params)
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.parse()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
SlackClient {
|
||||
connector: Client::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_webapi_request<RS>(&self, request: Request<Body>) -> ClientResult<RS>
|
||||
where
|
||||
RS: for<'de> serde::de::Deserialize<'de>,
|
||||
{
|
||||
let http_res = self.connector.request(request).await?;
|
||||
//let http_status = http_res.status();
|
||||
let http_body = hyper::body::aggregate(http_res).await?;
|
||||
let http_reader = http_body.reader();
|
||||
let decoded_body = serde_json::from_reader(http_reader)?;
|
||||
Ok(decoded_body)
|
||||
}
|
||||
|
||||
pub fn open_session(&self, token: &SlackApiToken) -> SlackClientSession {
|
||||
SlackClientSession {
|
||||
client: &self,
|
||||
token: token.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get<RS, PT, TS>(&self, method_relative_uri: &str, params: PT) -> ClientResult<RS>
|
||||
where
|
||||
RS: for<'de> serde::de::Deserialize<'de>,
|
||||
PT: std::iter::IntoIterator<Item = (TS, Option<TS>)>,
|
||||
TS: std::string::ToString,
|
||||
{
|
||||
let full_uri = SlackClient::create_url_with_params(
|
||||
&SlackClient::create_method_uri_path(&method_relative_uri),
|
||||
params,
|
||||
);
|
||||
|
||||
let body = self
|
||||
.send_webapi_request(Request::get(full_uri).body(Body::empty())?)
|
||||
.await?;
|
||||
|
||||
Ok(body)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SlackClientSession<'_> {
|
||||
fn setup_token_auth_header(
|
||||
&self,
|
||||
request_builder: hyper::http::request::Builder,
|
||||
) -> hyper::http::request::Builder {
|
||||
let token_header_value = format!("Bearer {}", self.token.value);
|
||||
request_builder.header("Authorization", token_header_value)
|
||||
}
|
||||
|
||||
pub async fn get<RS, PT, TS>(&self, method_relative_uri: &str, params: PT) -> ClientResult<RS>
|
||||
where
|
||||
RS: for<'de> serde::de::Deserialize<'de>,
|
||||
PT: std::iter::IntoIterator<Item = (TS, Option<TS>)>,
|
||||
TS: std::string::ToString,
|
||||
{
|
||||
let full_uri = SlackClient::create_url_with_params(
|
||||
&SlackClient::create_method_uri_path(&method_relative_uri),
|
||||
params,
|
||||
);
|
||||
|
||||
let body = self
|
||||
.client
|
||||
.send_webapi_request(
|
||||
self.setup_token_auth_header(Request::get(full_uri))
|
||||
.body(Body::empty())?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(body)
|
||||
}
|
||||
|
||||
pub async fn post<RQ, RS, PT, TS>(
|
||||
&self,
|
||||
method_relative_uri: &str,
|
||||
request: RQ,
|
||||
) -> ClientResult<RS>
|
||||
where
|
||||
RQ: serde::ser::Serialize,
|
||||
RS: for<'de> serde::de::Deserialize<'de>,
|
||||
PT: std::iter::IntoIterator<Item = (TS, Option<TS>)>,
|
||||
TS: std::string::ToString,
|
||||
{
|
||||
let full_uri =
|
||||
SlackClient::create_url(&SlackClient::create_method_uri_path(&method_relative_uri));
|
||||
|
||||
let post_json = serde_json::to_string(&request)?;
|
||||
|
||||
let response_body = self
|
||||
.client
|
||||
.send_webapi_request(
|
||||
self.setup_token_auth_header(Request::get(full_uri))
|
||||
.header("content-type", "application/json")
|
||||
.body(Body::from(post_json))?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(response_body)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,8 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
slack-morphism-models = { path = "../models", version = "0.1.0" }
|
||||
slack-morphism-client = { path = "../client", version = "0.1.0" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_with = "1.4"
|
||||
futures = "0.3"
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
use slack::blocks::kit::*;
|
||||
use slack::*;
|
||||
use slack_morphism_models as slack;
|
||||
use slack_morphism_client as slack_client;
|
||||
use slack_morphism_models as slack_models;
|
||||
|
||||
use futures::executor::block_on;
|
||||
use slack_client::*;
|
||||
use slack_models::blocks::kit::*;
|
||||
use slack_models::*;
|
||||
|
||||
fn main() {
|
||||
let sb: SlackSectionBlock = SlackSectionBlock::new().with_block_id("test".into());
|
||||
|
|
@ -23,18 +27,29 @@ fn main() {
|
|||
.into(),
|
||||
);
|
||||
|
||||
let context_block: SlackContextBlock = SlackContextBlock::new(
|
||||
slack_blocks! [
|
||||
some(SlackBlockImageElement::new("http://example.net/img1".into(), "text 1".into())),
|
||||
some(SlackBlockImageElement::new("http://example.net/img2".into(), "text 2".into()))
|
||||
]
|
||||
);
|
||||
let context_block: SlackContextBlock = SlackContextBlock::new(slack_blocks![
|
||||
some(SlackBlockImageElement::new(
|
||||
"http://example.net/img1".into(),
|
||||
"text 1".into()
|
||||
)),
|
||||
some(SlackBlockImageElement::new(
|
||||
"http://example.net/img2".into(),
|
||||
"text 2".into()
|
||||
))
|
||||
]);
|
||||
|
||||
let blocks: Vec<SlackBlock> =
|
||||
slack_blocks! [
|
||||
some ( section_block ),
|
||||
optionally( !sb_ser.is_empty() => context_block)
|
||||
];
|
||||
let blocks: Vec<SlackBlock> = slack_blocks! [
|
||||
some ( section_block ),
|
||||
optionally( !sb_ser.is_empty() => context_block)
|
||||
];
|
||||
|
||||
println!("{:#?}", blocks);
|
||||
|
||||
let client = SlackClient::new();
|
||||
let token: SlackApiToken = SlackApiToken::new("test".into());
|
||||
let session = client.open_session(&token);
|
||||
println!("{:#?}", session);
|
||||
|
||||
let test: slack_client::ClientResult<String> =
|
||||
block_on(session.get("", vec![].into_iter())).unwrap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
use chrono::serde::ts_milliseconds;
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
use rvs_derive::ValueStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{DateTime, Utc, TimeZone};
|
||||
use chrono::serde::ts_milliseconds;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, ValueStruct)]
|
||||
pub struct SlackTs(pub String);
|
||||
|
||||
impl SlackTs {
|
||||
pub fn to_date_time(&self) -> Result<DateTime<Utc>,std::num::ParseIntError> {
|
||||
let parts : Vec<&str> = self.value().split('.').collect();
|
||||
let ts_int : i64 = parts[0].parse()?;
|
||||
pub fn to_date_time(&self) -> Result<DateTime<Utc>, std::num::ParseIntError> {
|
||||
let parts: Vec<&str> = self.value().split('.').collect();
|
||||
let ts_int: i64 = parts[0].parse()?;
|
||||
Ok(Utc.timestamp_millis(ts_int))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ pub enum SlackPushEvent {
|
|||
#[serde(rename = "event_callback")]
|
||||
EventCallback(SlackEventCallback),
|
||||
#[serde(rename = "app_rate_limited")]
|
||||
AppRateLimited(SlackAppRateLimitedEvent)
|
||||
AppRateLimited(SlackAppRateLimitedEvent),
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
|
||||
pub struct SlackUrlVerificationEvent {
|
||||
pub challenge: String
|
||||
pub challenge: String,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
|
|
@ -27,7 +27,7 @@ pub struct SlackUrlVerificationEvent {
|
|||
pub struct SlackAppRateLimitedEvent {
|
||||
pub team_id: String,
|
||||
pub minute_rate_limited: SlackDateTime,
|
||||
pub api_app_id: String
|
||||
pub api_app_id: String,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
|
|
@ -38,44 +38,43 @@ pub struct SlackEventCallback {
|
|||
pub event: SlackEventCallbackBody,
|
||||
pub event_id: SlackEventId,
|
||||
pub event_time: SlackDateTime,
|
||||
pub authed_users: Option<Vec<SlackUserId>>
|
||||
pub authed_users: Option<Vec<SlackUserId>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum SlackEventCallbackBody {
|
||||
#[serde(rename = "message")]
|
||||
Message(SlackMessageEvent)
|
||||
Message(SlackMessageEvent),
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
|
||||
pub struct SlackMessageEvent {
|
||||
#[serde(flatten)]
|
||||
pub origin : SlackMessageOrigin,
|
||||
pub origin: SlackMessageOrigin,
|
||||
#[serde(flatten)]
|
||||
pub content : SlackMessageContent,
|
||||
pub subtype : Option<SlackMessageEventType>,
|
||||
pub hidden: Option<bool>
|
||||
pub content: SlackMessageContent,
|
||||
pub subtype: Option<SlackMessageEventType>,
|
||||
pub hidden: Option<bool>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub enum SlackMessageEventType {
|
||||
#[serde(rename="bot_message")]
|
||||
#[serde(rename = "bot_message")]
|
||||
BotMessage,
|
||||
#[serde(rename="me_message")]
|
||||
#[serde(rename = "me_message")]
|
||||
MeMessage,
|
||||
#[serde(rename="channel_join")]
|
||||
#[serde(rename = "channel_join")]
|
||||
ChannelJoin,
|
||||
#[serde(rename="bot_add")]
|
||||
#[serde(rename = "bot_add")]
|
||||
BotAdd,
|
||||
#[serde(rename="bot_remove")]
|
||||
#[serde(rename = "bot_remove")]
|
||||
BotRemove,
|
||||
#[serde(rename="channel_topic")]
|
||||
#[serde(rename = "channel_topic")]
|
||||
ChannelTopic,
|
||||
#[serde(rename="channel_purpose")]
|
||||
#[serde(rename = "channel_purpose")]
|
||||
ChannelPurpose,
|
||||
#[serde(rename="channel_name")]
|
||||
ChannelName
|
||||
}
|
||||
#[serde(rename = "channel_name")]
|
||||
ChannelName,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
pub mod blocks;
|
||||
pub mod common;
|
||||
pub mod events;
|
||||
pub mod messages;
|
||||
pub mod events;
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
use crate::blocks::kit::*;
|
||||
use crate::common::*;
|
||||
use rsb_derive::Builder;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
use rsb_derive::Builder;
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue