Skip to content

Commit 8a2f8db

Browse files
authored
Merge pull request #1 from nanato12/develop
Release v0.1.0
2 parents 19a8328 + 71062ae commit 8a2f8db

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+3540
-2
lines changed

.github/workflows/rust.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: Rust
2+
3+
on: [pull_request, push]
4+
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v1
10+
- name: Build
11+
run: cargo build --verbose
12+
- name: Run tests
13+
run: cargo test --verbose --tests

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ Cargo.lock
88

99
# These are backup files generated by rustfmt
1010
**/*.rs.bk
11+
12+
# enviroment value
13+
.env

Cargo.toml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
[package]
2+
name = "line-bot-sdk-rust"
3+
version = "0.1.0"
4+
authors = ["nanato12 <admin@nanato12.info>"]
5+
edition = "2018"
6+
description = "LINE Messaging API SDK for Rust"
7+
readme = "README.md"
8+
repository = "https://github.com/nanato12/line-bot-sdk-rust/"
9+
license = "Apache-2.0"
10+
license-file = "LICENSE"
11+
keywords = ["line", "linebot", "line-bot-sdk", "line-messaging-api"]
12+
categories = ["api-bindings"]
13+
14+
[features]
15+
default = []
16+
rocket_support = ["rocket"]
17+
18+
[dependencies]
19+
rocket = { version = "0.4", optional = true }
20+
reqwest = { version = "0.11.0", features = ["blocking", "json"] }
21+
serde = { version = "1.0", features = ["derive"] }
22+
serde_json = "1.0"
23+
serde_derive = "1.0.97"
24+
chrono = "0.4"
25+
bytes = "0.4"
26+
base64 = "0.9.2"
27+
hmac = "0.6.2"
28+
sha2 = "0.7.1"
29+
30+
[dev-dependencies]
31+
dotenv = "0.15.0"
32+
actix-web = "3.3"
33+
actix-rt = "1.0"

README.md

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,66 @@
1-
# line-bot-sdk-rust
2-
rust製 linebot sdk
1+
# LINE Messaging API SDK for Rust
2+
## Introduction
3+
The LINE Messaging API SDK for Rust makes it easy to develop bots using LINE Messaging API, and you can create a sample bot within minutes.
4+
## Documentation
5+
See the official API documentation for more information.
6+
- English: <https://developers.line.biz/en/docs/messaging-api/overview/>
7+
- Japanese: <https://developers.line.biz/ja/docs/messaging-api/overview/>
8+
## Requirements
9+
This library requires Rust nightly.
10+
## Installation
11+
```
12+
[dependencies]
13+
line-bot-sdk-rust = "0.1"
14+
```
15+
If you use `rocket support`.
16+
```
17+
[dependencies]
18+
line-bot-sdk-rust = { version = "0.1", features = ["rocket_support"] }
19+
```
20+
## Configuration
21+
```
22+
extern crate line_bot_sdk_rust as line;
23+
use line::bot::LineBot;
24+
25+
fn main() {
26+
let bot = LineBot::new("<channel secret>", "<channel access token>");
27+
}
28+
```
29+
## How to use
30+
The LINE Messaging API uses the JSON data format.
31+
parse_event_request() will help you to parse the HttpRequest content and return a Result<[Events](`events::Events`) , &'static str> Object.
32+
```
33+
let result: Result<Events, &'static str> =
34+
bot.parse_event_request(signature, body);
35+
```
36+
37+
```
38+
match result {
39+
Ok(events) => {
40+
for event in events.events {
41+
...
42+
}
43+
}
44+
Err(msg) => {}
45+
}
46+
```
47+
48+
## Contributing
49+
Please make a contribution 😆
50+
51+
## License
52+
```
53+
Copyright 2021 nanato12
54+
55+
Licensed under the Apache License, Version 2.0 (the "License");
56+
you may not use this file except in compliance with the License.
57+
You may obtain a copy of the License at
58+
59+
http://www.apache.org/licenses/LICENSE-2.0
60+
61+
Unless required by applicable law or agreed to in writing, software
62+
distributed under the License is distributed on an "AS IS" BASIS,
63+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
64+
See the License for the specific language governing permissions and
65+
limitations under the License.
66+
```

examples/create_signature.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
extern crate line_bot_sdk_rust as line;
2+
3+
use line::webhook::validate_signature;
4+
5+
use base64::encode;
6+
use hmac::{Hmac, Mac};
7+
use sha2::Sha256;
8+
9+
// Signature confirmation
10+
pub fn create_signature(channel_secret: &str, body: &str) -> String {
11+
type HmacSha256 = Hmac<Sha256>;
12+
13+
let mut mac =
14+
HmacSha256::new_varkey(channel_secret.as_bytes()).expect("HMAC can take key of any size");
15+
mac.input(body.as_bytes());
16+
return encode(&mac.result().code().to_vec());
17+
}
18+
19+
fn main() {
20+
let channel_secret: &str = "channel_secret";
21+
let request_body: &str = r#"
22+
{
23+
"destination": "xxxxxxxxxx",
24+
"events": [
25+
{
26+
"replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
27+
"type": "message",
28+
"mode": "active",
29+
"timestamp": 1462629479859,
30+
"source": {
31+
"type": "user",
32+
"userId": "U4af4980629..."
33+
},
34+
"message": {
35+
"id": "325708",
36+
"type": "text",
37+
"text": "@example Hello, world! (love)",
38+
"emojis": [
39+
{
40+
"index": 14,
41+
"length": 6,
42+
"productId": "5ac1bfd5040ab15980c9b435",
43+
"emojiId": "001"
44+
}
45+
],
46+
"mention": {
47+
"mentionees": [
48+
{
49+
"index": 0,
50+
"length": 8,
51+
"userId": "U850014438e..."
52+
}
53+
]
54+
}
55+
}
56+
}
57+
]
58+
}
59+
"#;
60+
let signature: String = create_signature(channel_secret, request_body);
61+
62+
if validate_signature(channel_secret, &signature, request_body) {
63+
println!("Success: {}", signature);
64+
} else {
65+
println!("NG");
66+
}
67+
}

examples/echobot_actix_web.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
extern crate line_bot_sdk_rust as line;
2+
3+
use dotenv::dotenv;
4+
use std::env;
5+
6+
use line::bot::LineBot;
7+
use line::events::messages::MessageType as EventMessageType;
8+
use line::events::{EventType, Events};
9+
use line::messages::{SendMessageType, TextMessage};
10+
11+
use actix_web::web::Bytes;
12+
use actix_web::{post, App, HttpRequest, HttpResponse, HttpServer, Responder};
13+
14+
#[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+
24+
// Get channel secret and access token by environment variable
25+
let channel_secret: &str =
26+
&env::var("LINE_CHANNEL_RECRET").expect("Failed getting LINE_CHANNEL_RECRET");
27+
let access_token: &str =
28+
&env::var("LINE_CHANNEL_ACCESS_TOKEN").expect("Failed getting LINE_CHANNEL_ACCESS_TOKEN");
29+
30+
// LineBot
31+
let bot = LineBot::new(channel_secret, access_token);
32+
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+
}
51+
}
52+
}
53+
return HttpResponse::Ok().body("OK");
54+
}
55+
// Failed parsing
56+
else if let Err(msg) = result {
57+
return HttpResponse::BadRequest().body(msg);
58+
}
59+
HttpResponse::BadRequest().body("Internal Server Error")
60+
}
61+
62+
#[actix_rt::main]
63+
async fn main() -> std::io::Result<()> {
64+
dotenv().ok();
65+
HttpServer::new(|| App::new().service(callback))
66+
.bind("127.0.0.1:8000")?
67+
.run()
68+
.await
69+
}

examples/echobot_rocket.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#![feature(proc_macro_hygiene, decl_macro)]
2+
3+
#[macro_use]
4+
extern crate rocket;
5+
6+
extern crate line_bot_sdk_rust as line;
7+
8+
use dotenv::dotenv;
9+
use std::env;
10+
11+
use rocket::http::Status;
12+
13+
use line::bot::LineBot;
14+
use line::events::messages::MessageType as EventMessageType;
15+
use line::events::{EventType, Events};
16+
use line::messages::{SendMessageType, TextMessage};
17+
use line::support::rocket_support::{Body, Signature};
18+
19+
#[post("/callback", data = "<body>")]
20+
fn callback(signature: Signature, body: Body) -> Status {
21+
// Get channel secret and access token by environment variable
22+
let channel_secret: &str =
23+
&env::var("LINE_CHANNEL_RECRET").expect("Failed getting LINE_CHANNEL_RECRET");
24+
let access_token: &str =
25+
&env::var("LINE_CHANNEL_ACCESS_TOKEN").expect("Failed getting LINE_CHANNEL_ACCESS_TOKEN");
26+
27+
// LineBot
28+
let bot = LineBot::new(channel_secret, access_token);
29+
30+
// Request body parse
31+
let result: Result<Events, &'static str> =
32+
bot.parse_event_request(&signature.key, &body.string);
33+
34+
// Success parsing
35+
if let Ok(res) = result {
36+
for event in res.events {
37+
// MessageEvent only
38+
if let EventType::MessageEvent(message_event) = event.r#type {
39+
// TextMessageEvent only
40+
if let EventMessageType::TextMessage(text_message) = message_event.message.r#type {
41+
// Create TextMessage
42+
let message = SendMessageType::TextMessage(TextMessage {
43+
text: text_message.text,
44+
emojis: None,
45+
});
46+
// Reply message with reply_token
47+
let _res = bot.reply_message(&message_event.reply_token, vec![message]);
48+
}
49+
}
50+
}
51+
return Status::new(200, "OK");
52+
}
53+
// Failed parsing
54+
else if let Err(msg) = result {
55+
return Status::new(500, msg);
56+
}
57+
Status::new(500, "Internal Server Error")
58+
}
59+
60+
fn main() {
61+
dotenv().ok();
62+
rocket::ignite().mount("/", routes![callback]).launch();
63+
}

0 commit comments

Comments
 (0)