slack-morphism-rust/examples/events_api_server.rs
Natsuki Ikeguchi 7d1cf6d271
feat: Upgrade http / hyper to 1.0 with axum 0.7 (#232)
Signed-off-by: Natsuki Ikeguchi <n_ikeguchi@yumemi.co.jp>
2024-01-14 14:19:55 +01:00

190 lines
6.2 KiB
Rust

use slack_morphism::prelude::*;
use bytes::Bytes;
use http_body_util::combinators::BoxBody;
use http_body_util::{BodyExt, Full};
use hyper::body::Incoming;
use hyper::service::service_fn;
use hyper::{Request, Response};
use hyper_util::rt::TokioIo;
use tokio::net::TcpListener;
use tracing::*;
use std::convert::Infallible;
use std::sync::Arc;
async fn test_oauth_install_function(
resp: SlackOAuthV2AccessTokenResponse,
_client: Arc<SlackHyperClient>,
_states: SlackClientEventsUserState,
) {
println!("{:#?}", resp);
}
async fn test_push_events_function(
event: SlackPushEvent,
_client: Arc<SlackHyperClient>,
_states: SlackClientEventsUserState,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// Read state
let current_state = {
let states = _states.read().await;
println!("{:#?}", states.get_user_state::<UserStateExample>());
println!("{:#?}", states.len());
UserStateExample(states.get_user_state::<UserStateExample>().unwrap().0 + 1)
};
// Write state
{
let mut states = _states.write().await;
states.set_user_state::<UserStateExample>(current_state);
println!("{:#?}", states.get_user_state::<UserStateExample>());
}
println!("{:#?}", event);
Ok(())
}
async fn test_interaction_events_function(
event: SlackInteractionEvent,
_client: Arc<SlackHyperClient>,
_states: SlackClientEventsUserState,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
println!("{:#?}", event);
Ok(())
}
async fn test_command_events_function(
event: SlackCommandEvent,
_client: Arc<SlackHyperClient>,
_states: SlackClientEventsUserState,
) -> Result<SlackCommandEventResponse, Box<dyn std::error::Error + Send + Sync>> {
let token_value: SlackApiTokenValue = config_env_var("SLACK_TEST_TOKEN")?.into();
let token: SlackApiToken = SlackApiToken::new(token_value);
let session = _client.open_session(&token);
session
.api_test(&SlackApiTestRequest::new().with_foo("Test".into()))
.await?;
println!("{:#?}", event);
Ok(SlackCommandEventResponse::new(
SlackMessageContent::new().with_text("Working on it".into()),
))
}
fn test_error_handler(
err: Box<dyn std::error::Error + Send + Sync>,
_client: Arc<SlackHyperClient>,
_states: SlackClientEventsUserState,
) -> HttpStatusCode {
println!("{:#?}", err);
// Defines what we return Slack server
HttpStatusCode::BAD_REQUEST
}
#[derive(Debug)]
struct UserStateExample(u64);
async fn test_server() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let client: Arc<SlackHyperClient> =
Arc::new(SlackClient::new(SlackClientHyperConnector::new()?));
let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
info!("Loading server: {}", addr);
async fn your_others_routes(
_req: Request<Incoming>,
) -> Result<Response<BoxBody<Bytes, Infallible>>, Box<dyn std::error::Error + Send + Sync>>
{
Response::builder()
.body(Full::new("Hey, this is a default users route handler".into()).boxed())
.map_err(|e| e.into())
}
let oauth_listener_config = Arc::new(SlackOAuthListenerConfig::new(
config_env_var("SLACK_CLIENT_ID")?.into(),
config_env_var("SLACK_CLIENT_SECRET")?.into(),
config_env_var("SLACK_BOT_SCOPE")?,
config_env_var("SLACK_REDIRECT_HOST")?,
));
let push_events_config = Arc::new(SlackPushEventsListenerConfig::new(
config_env_var("SLACK_SIGNING_SECRET")?.into(),
));
let interactions_events_config = Arc::new(SlackInteractionEventsListenerConfig::new(
config_env_var("SLACK_SIGNING_SECRET")?.into(),
));
let command_events_config = Arc::new(SlackCommandEventsListenerConfig::new(
config_env_var("SLACK_SIGNING_SECRET")?.into(),
));
let listener_environment = Arc::new(
SlackClientEventsListenerEnvironment::new(client.clone())
.with_error_handler(test_error_handler)
.with_user_state(UserStateExample(0)),
);
let listener = TcpListener::bind(&addr).await?;
info!("Server is listening on {}", &addr);
loop {
let (tcp, _) = listener.accept().await?;
let io = TokioIo::new(tcp);
let thread_oauth_config = oauth_listener_config.clone();
let thread_push_events_config = push_events_config.clone();
let thread_interaction_events_config = interactions_events_config.clone();
let thread_command_events_config = command_events_config.clone();
let listener = SlackClientEventsHyperListener::new(listener_environment.clone());
let routes = chain_service_routes_fn(
listener.oauth_service_fn(thread_oauth_config, test_oauth_install_function),
chain_service_routes_fn(
listener
.push_events_service_fn(thread_push_events_config, test_push_events_function),
chain_service_routes_fn(
listener.interaction_events_service_fn(
thread_interaction_events_config,
test_interaction_events_function,
),
chain_service_routes_fn(
listener.command_events_service_fn(
thread_command_events_config,
test_command_events_function,
),
your_others_routes,
),
),
),
);
tokio::task::spawn(async move {
if let Err(err) = hyper::server::conn::http1::Builder::new()
.serve_connection(io, service_fn(routes))
.await
{
println!("Error serving connection: {:?}", err);
}
});
}
}
pub fn config_env_var(name: &str) -> Result<String, String> {
std::env::var(name).map_err(|e| format!("{}: {}", name, e))
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let subscriber = tracing_subscriber::fmt()
.with_env_filter("events_api_server=debug,slack_morphism=debug")
.finish();
tracing::subscriber::set_global_default(subscriber)?;
test_server().await?;
Ok(())
}