Skip to content

Commit 4099b30

Browse files
authored
Merge pull request #24 from fill9120/master
Add Actix-web support
2 parents 8a2f8db + ead95bf commit 4099b30

File tree

4 files changed

+67
-43
lines changed

4 files changed

+67
-43
lines changed

Cargo.toml

+8-6
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,19 @@ categories = ["api-bindings"]
1414
[features]
1515
default = []
1616
rocket_support = ["rocket"]
17+
actix_support = ["actix-web"]
1718

1819
[dependencies]
19-
rocket = { version = "0.4", optional = true }
20+
actix-web = { version = "3", optional = true, default-features = false }
21+
base64 = "0.9.2"
22+
bytes = "0.4"
23+
chrono = "0.4"
24+
hmac = "0.6.2"
2025
reqwest = { version = "0.11.0", features = ["blocking", "json"] }
26+
rocket = { version = "0.4", optional = true }
2127
serde = { version = "1.0", features = ["derive"] }
22-
serde_json = "1.0"
2328
serde_derive = "1.0.97"
24-
chrono = "0.4"
25-
bytes = "0.4"
26-
base64 = "0.9.2"
27-
hmac = "0.6.2"
29+
serde_json = "1.0"
2830
sha2 = "0.7.1"
2931

3032
[dev-dependencies]

examples/echobot_actix_web.rs

+27-37
Original file line numberDiff line numberDiff line change
@@ -4,59 +4,49 @@ use dotenv::dotenv;
44
use std::env;
55

66
use line::bot::LineBot;
7-
use line::events::messages::MessageType as EventMessageType;
7+
use line::events::messages::MessageType;
88
use line::events::{EventType, Events};
99
use line::messages::{SendMessageType, TextMessage};
10+
use line::support::actix_support::Signature;
11+
use line::webhook::validate_signature;
1012

11-
use actix_web::web::Bytes;
12-
use actix_web::{post, App, HttpRequest, HttpResponse, HttpServer, Responder};
13+
use actix_web::{post, web, App, HttpServer, Responder};
1314

1415
#[post("/callback")]
15-
async fn callback(req: HttpRequest, bytes: Bytes) -> impl Responder {
16-
let body: &str = &String::from_utf8(bytes.to_vec()).unwrap();
17-
let signature: &str = req
18-
.headers()
19-
.get("x-line-signature")
20-
.unwrap()
21-
.to_str()
22-
.unwrap();
23-
16+
async fn callback(
17+
signature: Signature,
18+
data: web::Json<Events>,
19+
bytes: web::Bytes,
20+
) -> impl Responder {
2421
// Get channel secret and access token by environment variable
2522
let channel_secret: &str =
26-
&env::var("LINE_CHANNEL_RECRET").expect("Failed getting LINE_CHANNEL_RECRET");
23+
&env::var("LINE_CHANNEL_SECRET").expect("Failed getting LINE_CHANNEL_SECRET");
2724
let access_token: &str =
2825
&env::var("LINE_CHANNEL_ACCESS_TOKEN").expect("Failed getting LINE_CHANNEL_ACCESS_TOKEN");
2926

3027
// LineBot
3128
let bot = LineBot::new(channel_secret, access_token);
3229

33-
// Request body parse
34-
let result: Result<Events, &'static str> = bot.parse_event_request(signature, body);
35-
36-
// Success parsing
37-
if let Ok(res) = result {
38-
for event in res.events {
39-
// MessageEvent only
40-
if let EventType::MessageEvent(message_event) = event.r#type {
41-
// TextMessageEvent only
42-
if let EventMessageType::TextMessage(text_message) = message_event.message.r#type {
43-
// Create TextMessage
44-
let message = SendMessageType::TextMessage(TextMessage {
45-
text: text_message.text,
46-
emojis: None,
47-
});
48-
// Reply message with reply_token
49-
let _res = bot.reply_message(&message_event.reply_token, vec![message]);
50-
}
30+
let body: &str = &String::from_utf8(bytes.to_vec()).unwrap();
31+
validate_signature(&bot.channel_secret, &signature.key, &body);
32+
33+
for event in &data.events {
34+
// MessageEvent only
35+
if let EventType::MessageEvent(message_event) = &event.r#type {
36+
// TextMessageEvent only
37+
if let MessageType::TextMessage(text_message) = &message_event.message.r#type {
38+
// Create TextMessage
39+
let message = SendMessageType::TextMessage(TextMessage {
40+
text: text_message.text.to_string(),
41+
emojis: None,
42+
});
43+
// Reply message with reply_token
44+
let _res = bot.reply_message(&message_event.reply_token, vec![message]);
5145
}
5246
}
53-
return HttpResponse::Ok().body("OK");
54-
}
55-
// Failed parsing
56-
else if let Err(msg) = result {
57-
return HttpResponse::BadRequest().body(msg);
5847
}
59-
HttpResponse::BadRequest().body("Internal Server Error")
48+
49+
"OK"
6050
}
6151

6252
#[actix_rt::main]

src/support/actix_support.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use actix_web::dev::Payload;
2+
use actix_web::{error::ErrorBadRequest, Error, FromRequest, HttpRequest};
3+
use std::{future::Future, pin::Pin};
4+
5+
#[derive(Debug)]
6+
pub struct Signature {
7+
pub key: String,
8+
}
9+
10+
impl FromRequest for Signature {
11+
type Error = Error;
12+
type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
13+
type Config = ();
14+
15+
fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
16+
let res = if let Some(x_line_signature) = req.headers().get("x-line-signature") {
17+
if let Ok(key) = x_line_signature.to_str() {
18+
Ok(Signature {
19+
key: key.to_string(),
20+
})
21+
} else {
22+
Err(ErrorBadRequest("x-line-signature is missing"))
23+
}
24+
} else {
25+
Err(ErrorBadRequest("x-line-signature is missing"))
26+
};
27+
Box::pin(async move { res })
28+
}
29+
}

src/support/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
33
#[cfg(feature = "rocket_support")]
44
pub mod rocket_support;
5+
6+
#[cfg(feature = "actix_support")]
7+
pub mod actix_support;

0 commit comments

Comments
 (0)