├── .gitignore
├── Cargo.toml
├── README.md
├── docs
└── images
│ ├── rust-wechaty-logo.png
│ └── rust-wechaty-logo.svg
├── examples
└── ding_dong_bot.rs
├── file-box
├── Cargo.toml
└── src
│ └── lib.rs
├── rustfmt.toml
├── wechaty-puppet-mock
├── Cargo.toml
└── src
│ ├── lib.rs
│ └── puppet_mock.rs
├── wechaty-puppet-service
├── Cargo.toml
└── src
│ ├── from_payload_response.rs
│ ├── lib.rs
│ ├── puppet_service.rs
│ └── service_endpoint.rs
├── wechaty-puppet
├── Cargo.toml
└── src
│ ├── error.rs
│ ├── events.rs
│ ├── lib.rs
│ ├── puppet.rs
│ ├── schemas
│ ├── contact.rs
│ ├── event.rs
│ ├── friendship.rs
│ ├── image.rs
│ ├── message.rs
│ ├── mini_program.rs
│ ├── mod.rs
│ ├── payload.rs
│ ├── puppet.rs
│ ├── room.rs
│ ├── room_invitation.rs
│ └── url_link.rs
│ └── types.rs
└── wechaty
├── Cargo.toml
└── src
├── context.rs
├── error.rs
├── lib.rs
├── payload.rs
├── traits
├── contact.rs
├── event_listener.rs
├── mod.rs
└── talkable.rs
├── user
├── contact.rs
├── contact_self.rs
├── entity.rs
├── favorite.rs
├── friendship.rs
├── image.rs
├── location.rs
├── message.rs
├── mini_program.rs
├── mod.rs
├── moment.rs
├── money.rs
├── room.rs
├── room_invitation.rs
├── tag.rs
└── url_link.rs
└── wechaty.rs
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/macos,windows,linux,rust
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=macos,windows,linux,rust
3 |
4 | ### Linux ###
5 | *~
6 |
7 | # temporary files which can be created if a process still has a handle open of a deleted file
8 | .fuse_hidden*
9 |
10 | # KDE directory preferences
11 | .directory
12 |
13 | # Linux trash folder which might appear on any partition or disk
14 | .Trash-*
15 |
16 | # .nfs files are created when an open file is removed but is still being accessed
17 | .nfs*
18 |
19 | ### macOS ###
20 | # General
21 | .DS_Store
22 | .AppleDouble
23 | .LSOverride
24 |
25 | # Icon must end with two \r
26 | Icon
27 |
28 |
29 | # Thumbnails
30 | ._*
31 |
32 | # Files that might appear in the root of a volume
33 | .DocumentRevisions-V100
34 | .fseventsd
35 | .Spotlight-V100
36 | .TemporaryItems
37 | .Trashes
38 | .VolumeIcon.icns
39 | .com.apple.timemachine.donotpresent
40 |
41 | # Directories potentially created on remote AFP share
42 | .AppleDB
43 | .AppleDesktop
44 | Network Trash Folder
45 | Temporary Items
46 | .apdisk
47 |
48 | ### Rust ###
49 | # Generated by Cargo
50 | # will have compiled files and executables
51 | /target/
52 |
53 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
54 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
55 | Cargo.lock
56 |
57 | ### Windows ###
58 | # Windows thumbnail cache files
59 | Thumbs.db
60 | Thumbs.db:encryptable
61 | ehthumbs.db
62 | ehthumbs_vista.db
63 |
64 | # Dump file
65 | *.stackdump
66 |
67 | # Folder config file
68 | [Dd]esktop.ini
69 |
70 | # Recycle Bin used on file shares
71 | $RECYCLE.BIN/
72 |
73 | # Windows Installer files
74 | *.cab
75 | *.msi
76 | *.msix
77 | *.msm
78 | *.msp
79 |
80 | # Windows shortcuts
81 | *.lnk
82 |
83 | # End of https://www.toptal.com/developers/gitignore/api/macos,windows,linux,rust
84 |
85 | # IDE
86 | .idea
87 | .vscode
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 |
3 | members = [
4 | "file-box",
5 | "wechaty",
6 | "wechaty-puppet",
7 | "wechaty-puppet-service",
8 | "wechaty-puppet-mock",
9 | ]
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # rust-wechaty
2 |
3 | 
4 |
5 | ## Connecting Chatbots
6 |
7 | [](https://github.com/Wechaty/wechaty)
8 |
9 | Wechaty is a Conversational RPA SDK for Chatbot Makers that can help you create a bot in Rust quickly.
10 |
11 | ## Voice of the Developers
12 |
13 | > "Wechaty is a great solution, I believe there would be much more users recognize it." [link](https://github.com/Wechaty/wechaty/pull/310#issuecomment-285574472)
14 | > — @Gcaufy, Tencent Engineer, Author of [WePY](https://github.com/Tencent/wepy)
15 | >
16 | > "太好用,好用的想哭"
17 | > — @xinbenlv, Google Engineer, Founder of HaoShiYou.org
18 | >
19 | > "最好的微信开发库" [link](http://weibo.com/3296245513/Ec4iNp9Ld?type=comment)
20 | > — @Jarvis, Baidu Engineer
21 | >
22 | > "Wechaty让运营人员更多的时间思考如何进行活动策划、留存用户,商业变现" [link](http://mp.weixin.qq.com/s/dWHAj8XtiKG-1fIS5Og79g)
23 | > — @lijiarui, Founder & CEO of Juzi.BOT.
24 | >
25 | > "If you know js ... try Wechaty, it's easy to use."
26 | > — @Urinx Uri Lee, Author of [WeixinBot(Python)](https://github.com/Urinx/WeixinBot)
27 |
28 | See more at [Wiki:Voice Of Developer](https://github.com/Wechaty/wechaty/wiki/Voice%20Of%20Developer)
29 |
30 | ## Join Us
31 |
32 | Wechaty is used in many ChatBot projects by thousands of developers. If you want to talk with other developers, just scan the following QR Code in WeChat with secret code _rust wechaty_, join our **Wechaty Rust Developers' Home**.
33 |
34 | 
35 |
36 | Scan now, because other Wechaty Rust developers want to talk to you too! (secret code: _rust wechaty_)
37 |
38 | ## Examples
39 |
40 | ### Ding-dong bot
41 |
42 | ```shell
43 | export WECHATY_PUPPET_SERVICE_TOKEN=
44 | export RUST_LOG=
45 | cargo run --example ding-dong-bot
46 | ```
47 |
48 | ## Related Projects
49 |
50 | - [Wechaty](https://github.com/wechaty/wechaty) - Conversatioanl AI Chatot SDK for Wechaty Individual Accounts (TypeScript)
51 | - [Rust Wechaty](https://github.com/wechaty/rust-wechaty) - Rust WeChaty Conversational AI Chatbot SDK for Wechat Individual Accounts (Rust)
52 | - [Python Wechaty](https://github.com/wechaty/python-wechaty) - Python WeChaty Conversational AI Chatbot SDK for Wechat Individual Accounts (Python)
53 | - [Go Wechaty](https://github.com/wechaty/go-wechaty) - Go WeChaty Conversational AI Chatbot SDK for Wechat Individual Accounts (Go)
54 | - [Java Wechaty](https://github.com/wechaty/java-wechaty) - Java WeChaty Conversational AI Chatbot SDK for Wechat Individual Accounts (Java)
55 | - [Scala Wechaty](https://github.com/wechaty/scala-wechaty) - Scala WeChaty Conversational AI Chatbot SDK for WechatyIndividual Accounts (Scala)
56 |
57 | ## Badge
58 |
59 | [](https://github.com/wechaty/rust-wechaty)
60 |
61 | ```md
62 | [](https://github.com/wechaty/rust-wechaty)
63 | ```
64 |
65 | ## Stargazers over time
66 |
67 | [](https://starchart.cc/wechaty/rust-wechaty)
68 |
69 | ## Creators
70 |
71 | - [@lucifer1004](https://github.com/lucifer1004) - (吴自华) wuzihua@pku.edu.cn
72 | - [@huan](https://github.com/huan) - ([李卓桓](http://linkedin.com/in/zixia)) zixia@zixia.net
73 |
74 | ## Copyright & License
75 |
76 | - Code & Docs © 2021--Now Wechaty Contributors
77 | - Code released under the Apache-2.0 License
78 | - Docs released under Creative Commons
79 |
--------------------------------------------------------------------------------
/docs/images/rust-wechaty-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechaty/rust-wechaty/2cf5545fb677a9da2e983892b8320ef0294dc62d/docs/images/rust-wechaty-logo.png
--------------------------------------------------------------------------------
/docs/images/rust-wechaty-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
58 |
--------------------------------------------------------------------------------
/examples/ding_dong_bot.rs:
--------------------------------------------------------------------------------
1 | #![feature(async_closure)]
2 | use std::env;
3 |
4 | use wechaty::prelude::*;
5 | use wechaty_puppet_service::PuppetService;
6 |
7 | #[wechaty_rt::main]
8 | async fn main() {
9 | env_logger::init();
10 | let options = PuppetOptions {
11 | endpoint: match env::var("WECHATY_PUPPET_SERVICE_ENDPOINT") {
12 | Ok(endpoint) => Some(endpoint),
13 | Err(_) => None,
14 | },
15 | timeout: None,
16 | token: match env::var("WECHATY_PUPPET_SERVICE_TOKEN") {
17 | Ok(endpoint) => Some(endpoint),
18 | Err(_) => None,
19 | },
20 | };
21 | let mut bot = Wechaty::new(PuppetService::new(options).await.unwrap());
22 |
23 | bot.on_scan(async move |payload: ScanPayload, _ctx| {
24 | if let Some(qrcode) = payload.qrcode {
25 | println!(
26 | "Visit {} to log in",
27 | format!("https://wechaty.js.org/qrcode/{}", qrcode)
28 | );
29 | }
30 | })
31 | .on_login(
32 | async move |payload: LoginPayload, ctx: WechatyContext| {
33 | println!("User {} has logged in", payload.contact);
34 | println!("Contact list: {:?}", ctx.contact_find_all(None).await);
35 | },
36 | )
37 | .on_logout(async move |payload: LogoutPayload, _ctx| {
38 | println!("User {} has logged out", payload.contact);
39 | })
40 | .on_message(
41 | async move |payload: MessagePayload, ctx: WechatyContext| {
42 | let mut message = payload.message;
43 | let mentioned = message.mention_list().await;
44 | println!(
45 | "Got message: {}, mentioned: {:?}, age: {}",
46 | message,
47 | mentioned,
48 | message.age()
49 | );
50 | if message.is_self() {
51 | println!("Message discarded because it's outgoing");
52 | return;
53 | }
54 | if message.is_in_room() {
55 | println!("Message discarded because it's from a room");
56 | return;
57 | }
58 | if let Some(message_type) = message.message_type() {
59 | if message_type != MessageType::Text {
60 | println!("Message discarded because it is not a text");
61 | } else {
62 | let text = message.text().unwrap_or_default();
63 | if text == "bye" {
64 | println!("Good bye!");
65 | ctx.logout().await.unwrap_or_default();
66 | return;
67 | }
68 | if text == "ding" {
69 | if let Err(e) = message.reply_text("dong".to_owned()).await {
70 | println!("Failed to send message, reason: {}", e);
71 | } else {
72 | println!("REPLY: dong");
73 | }
74 | return;
75 | }
76 | println!("Message discarded because it does not match any keyword");
77 | }
78 | }
79 | },
80 | )
81 | .start()
82 | .await;
83 | }
84 |
--------------------------------------------------------------------------------
/file-box/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "file-box"
3 | version = "0.1.0-beta.0"
4 | authors = ["Gabriel Wu "]
5 | edition = "2018"
6 | license = "Apache-2.0"
7 | description = "Unified file (local, remote url, or cloud storage) box for easy easier management and manipulation."
8 | keywords = ["file", "cloud-storage", "wechaty"]
9 |
10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
11 |
12 | [dependencies]
13 |
--------------------------------------------------------------------------------
/file-box/src/lib.rs:
--------------------------------------------------------------------------------
1 | use std::fmt;
2 |
3 | // TODO: FileBox Implementation
4 | pub struct FileBox {}
5 |
6 | impl fmt::Display for FileBox {
7 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
8 | write!(fmt, "")
9 | }
10 | }
11 |
12 | impl From for FileBox {
13 | fn from(_: String) -> Self {
14 | Self {}
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/rustfmt.toml:
--------------------------------------------------------------------------------
1 | group_imports = "StdExternalCrate"
2 | max_width = 120
3 | reorder_imports = true
4 | reorder_impl_items = true
--------------------------------------------------------------------------------
/wechaty-puppet-mock/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "wechaty-puppet-mock"
3 | version = "0.1.0-beta.1"
4 | authors = ["Gabriel Wu "]
5 | edition = "2018"
6 | license = "Apache-2.0"
7 | description = "Rust implementation of wechaty-puppet-mock"
8 | keywords = ["chatbot", "wechaty"]
9 |
10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
11 |
12 | [dependencies]
13 | actix = "0.12"
14 | async-trait = "0.1"
15 | wechaty_puppet = { version = "0.1.0-beta.1", path = "../wechaty-puppet" }
--------------------------------------------------------------------------------
/wechaty-puppet-mock/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod puppet_mock;
2 |
3 | pub use puppet_mock::PuppetMock;
4 |
--------------------------------------------------------------------------------
/wechaty-puppet-mock/src/puppet_mock.rs:
--------------------------------------------------------------------------------
1 | use async_trait::async_trait;
2 | use wechaty_puppet::*;
3 |
4 | #[derive(Debug)]
5 | pub struct PuppetMock {}
6 |
7 | #[allow(dead_code)]
8 | #[allow(unused_variables)]
9 | #[async_trait]
10 | impl PuppetImpl for PuppetMock {
11 | async fn contact_self_name_set(&self, name: String) -> Result<(), PuppetError> {
12 | unimplemented!()
13 | }
14 |
15 | async fn contact_self_qr_code(&self) -> Result {
16 | unimplemented!()
17 | }
18 |
19 | async fn contact_self_signature_set(&self, signature: String) -> Result<(), PuppetError> {
20 | unimplemented!()
21 | }
22 |
23 | async fn tag_contact_add(&self, tag_id: String, contact_id: String) -> Result<(), PuppetError> {
24 | unimplemented!()
25 | }
26 |
27 | async fn tag_contact_remove(&self, tag_id: String, contact_id: String) -> Result<(), PuppetError> {
28 | unimplemented!()
29 | }
30 |
31 | async fn tag_contact_delete(&self, tag_id: String) -> Result<(), PuppetError> {
32 | unimplemented!()
33 | }
34 |
35 | async fn tag_contact_list(&self, contact_id: String) -> Result, PuppetError> {
36 | unimplemented!()
37 | }
38 |
39 | async fn tag_list(&self) -> Result, PuppetError> {
40 | unimplemented!()
41 | }
42 |
43 | async fn contact_alias(&self, contact_id: String) -> Result {
44 | unimplemented!()
45 | }
46 |
47 | async fn contact_alias_set(&self, contact_id: String, alias: String) -> Result<(), PuppetError> {
48 | unimplemented!()
49 | }
50 |
51 | async fn contact_avatar(&self, contact_id: String) -> Result {
52 | unimplemented!()
53 | }
54 |
55 | async fn contact_avatar_set(&self, contact_id: String, file: FileBox) -> Result<(), PuppetError> {
56 | unimplemented!()
57 | }
58 |
59 | async fn contact_phone_set(&self, contact_id: String, phone_list: Vec) -> Result<(), PuppetError> {
60 | unimplemented!()
61 | }
62 |
63 | async fn contact_corporation_remark_set(
64 | &self,
65 | contact_id: String,
66 | corporation_remark: Option,
67 | ) -> Result<(), PuppetError> {
68 | unimplemented!()
69 | }
70 |
71 | async fn contact_description_set(
72 | &self,
73 | contact_id: String,
74 | description: Option,
75 | ) -> Result<(), PuppetError> {
76 | unimplemented!()
77 | }
78 |
79 | async fn contact_list(&self) -> Result, PuppetError> {
80 | unimplemented!()
81 | }
82 |
83 | async fn contact_raw_payload(&self, contact_id: String) -> Result {
84 | unimplemented!()
85 | }
86 |
87 | async fn message_contact(&self, message_id: String) -> Result {
88 | unimplemented!()
89 | }
90 |
91 | async fn message_file(&self, message_id: String) -> Result {
92 | unimplemented!()
93 | }
94 |
95 | async fn message_image(&self, message_id: String, image_type: ImageType) -> Result {
96 | unimplemented!()
97 | }
98 |
99 | async fn message_mini_program(&self, message_id: String) -> Result {
100 | unimplemented!()
101 | }
102 |
103 | async fn message_url(&self, message_id: String) -> Result {
104 | unimplemented!()
105 | }
106 |
107 | async fn message_send_contact(
108 | &self,
109 | conversation_id: String,
110 | contact_id: String,
111 | ) -> Result