{"id":31058321,"url":"https://github.com/niuhuan/runbot","last_synced_at":"2025-09-15T07:44:57.117Z","repository":{"id":311775791,"uuid":"1044823839","full_name":"niuhuan/runbot","owner":"niuhuan","description":"Rust one bot v11 lib","archived":false,"fork":false,"pushed_at":"2025-09-13T14:23:41.000Z","size":293,"stargazers_count":11,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-13T16:27:59.940Z","etag":null,"topics":["bot","mirai","mirai-bot","oicq","qq","qq-protocol","qqbot","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/niuhuan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-26T09:06:43.000Z","updated_at":"2025-09-13T14:23:45.000Z","dependencies_parsed_at":"2025-08-26T18:27:45.193Z","dependency_job_id":"c41756a2-42e3-4373-9a3b-c4197449e625","html_url":"https://github.com/niuhuan/runbot","commit_stats":null,"previous_names":["niuhuan/runbot"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/niuhuan/runbot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niuhuan%2Frunbot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niuhuan%2Frunbot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niuhuan%2Frunbot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niuhuan%2Frunbot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/niuhuan","download_url":"https://codeload.github.com/niuhuan/runbot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niuhuan%2Frunbot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275225866,"owners_count":25427000,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-15T02:00:09.272Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot","mirai","mirai-bot","oicq","qq","qq-protocol","qqbot","rust"],"created_at":"2025-09-15T07:44:53.058Z","updated_at":"2025-09-15T07:44:57.097Z","avatar_url":"https://github.com/niuhuan.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"RUNBOT\n======\n\nRust one bot v11 协议 （ 正向ws / 反向ws ）实现。\n\n- 开箱即用, 使用过程宏定义功能和模块, 轻松实现机器人。\n- 具有极高的自由度, 支持模块多层嵌套。\n\n## 开始\n\n以下代码来自 [runbot/examples/client.rs](runbot/examples/client.rs) , 您可以直接跟踪查看。\n\n- 您可以clone项目并运行 `cargo run --example client`  运行正向WS事例\n- 您可以clone项目并运行 `cargo run --example server`  运行反向WS事例\n\n#### 0. 引入依赖\n\n```toml\n# 使用crates.io版本\nrunbot = \"0\"\n# 使用github版本\nrunbot = { git = \"https://github.com/niuhuan/runbot.git\" }\n```\n\n#### 1. 定义事件处理器\n\n```rust\nuse std::sync::Arc;\nuse anyhow::Result;\nuse runbot::prelude::*;\n\n// 声明一个处理器, 当收到消息后被调用\n// 参数固定为 Arc\u003cBotContext\u003e，\u0026对应事件类型,  （事件类型包括 Message 消息、Notice 通知、Request 请求、Post 以上三种的枚举）\n// 返回值为 Result\u003cbool\u003e, 当有一个处理器返回Ok(true)或Err()时将会停止递归\n//\n// 此demo为收到好友消息，消息为`hello`时，自动回复`world`\n#[processor]\npub async fn demo_processor_fn(bot_ctx: Arc\u003cBotContext\u003e, message: \u0026Message) -\u003e Result\u003cbool\u003e {\n    if message.raw_message.eq(\"hello\") {\n        if let MessageSubType::Friend = message.sub_type {\n            bot_ctx.send_private_message(message.user_id, \"world\".to_string()).await?;\n        }\n    }\n    Ok(true)\n}\n```\n\n#### 2. 连接bot\n\n`add_processor`的功能或模块会依次调用, 直至返回true或者返回Error, 会停止链路.\n\n```rust\n#[tokio::main]\nasync fn main() {\n    // 打印日志\n    tracing_subscriber::fmt()\n        .with_max_level(tracing::Level::DEBUG)\n        .init();\n    // 生成一个bot上下文\n    let bot_ctx = BotContextBuilder::new()\n        // 声明链接地址\n        .url(\"ws://localhost:3001\")\n        // 注册事件处理器 (方法名的UPPER_SNAKE)\n        .add_processor(DEMO_PROCESSOR_FN)\n        .build()\n        .unwrap();\n    // loop_client 或者 spawn loop_client （方便定时任务等）\n    loop_client(bot_ctx).await;\n}\n```\n\n![hello](images/hello.png)\n\n## 指南\n\n#### 发送消息以及消息链 (文字以及图片)\n\n```rust\nlet mut chain = vec![];\nchain.push(MessageText::new(\"this\").into());\nchain.push(\"is face\".into());\nchain.push(\n    MessageFace {\n        id: \"187\".to_string(),\n        sub_type: 1,\n    }\n    .into(),\n);\nbot_ctx.send_private_message(message.user_id, chain).await?;\nlet exec_path = std::env::current_dir().unwrap().join(\"target/test.png\");\nbot_ctx.send_private_message(message.user_id, vec![\n    MessageImage::new(exec_path.to_str().unwrap()).into(),\n]).await?;\n```\n\n#### 确保消息发送成功、获取消息ID、撤回消息\n\n```rust\nbot_ctx.send_private_message(12345, \"hello\").await?;\nlet async_response = bot_ctx.send_private_message(message.user_id, chain).await?;\nlet msg_id = async_response.wait_response().await?.message_id;\nbot_ctx.delete_msg(msg_id).await?;\n```\n\n#### 反向WS\n\n```rust\nasync fn main() {\n    tracing_subscriber::fmt()\n        .with_max_level(tracing::Level::DEBUG)\n        .init();\n    let server = BotServerBuilder::new()\n        .bind(\"0.0.0.0:3131\")\n        .add_message_processor(DEMO_PROCESSOR_FN)\n        .build()\n        .unwrap();\n    loop_server(server).await.unwrap();\n}\n```\n\n#### 机器人命令\n\n\n```rust\n#[processor(command = \"[-|/|~]ban {time:n}[unit:s|m|h]? {user:n}+\")]\npub async fn demo_command_ban(\n    bot_ctx: Arc\u003cBotContext\u003e,\n    message: \u0026Message,\n    time: i64,\n    unit: Option\u003cString\u003e,\n    user: Vec\u003ci64\u003e,\n) -\u003e Result\u003cbool\u003e {\n    let unit = match unit {\n        Some(unit) =\u003e match unit.as_str() {\n            \"s\" =\u003e 1,\n            \"m\" =\u003e 60,\n            \"h\" =\u003e 3600,\n            _ =\u003e unreachable!(),\n        },\n        None =\u003e 1,\n    };\n    let time = time * unit;\n    let msg = format!(\"禁用用户 {:?} {time}秒\", user);\n    match message.message_type {\n        MessageType::Group =\u003e {\n            bot_ctx.send_group_message(message.group_id, msg).await?;\n        }\n        MessageType::Private =\u003e {\n            bot_ctx.send_private_message(message.user_id, msg).await?;\n        }\n        _ =\u003e {}\n    }\n    Ok(true)\n}\n```\n- 使用 `#[processor(command = \"...\")]` 定义命令\n- 必须以 bot_ctx: Arc\u003cBotContext\u003e, message: \u0026Message 开头\n- 中括号匹配结尾需要为冒号和英文字符\n- {:n} 会截从文本开始截取文字 规则为 \\d+(\\.\\d+)? , 截取下的文本以及剩余文本会被trim_space\n- {:s} 开始截取文字 规则为 \\W+ , 截取下的文本以及剩余文本会被trim_space\n- {:e} impl take [\\W\\w]+  , 截取下的文本以及剩余文本会被trim_space\n- 如果需要赋值给变量, 那么在冒号前加入变量名 {name:s} , 最后应用 let some = From::str(截取到的内容), 若成功转换则 赋值name给\n- {}? {}+ {}* : 括号结束的后一位特殊符号分别代表: 可选,至少重复1次,重复0或者多次\n- ?结尾要使用Option类型当参数, +和*需要使用Vec当作参数 同样会应用FromStr\n- [] 表示文字枚举, 使用 | 分割, 同样在前面加入变量名 [name:] 可以赋值给变量, 支持 + 和 * 和 ?\n- Tips:\n  - 如果@不是全体成员可以映射成数字类型\n  - {:s}+ 会一直匹配到结束, 因为数字型属于字符串\n\n## 模块\n\n- 声明模块无需定义struct直接定义一个impl。\n- name / help / processors 对应着模块的 名称 / 帮助文本 / 模块功能。\n  - 以上参数可以从module宏中省略, name 和 help 会默认为Struct的名称, processors会默认空数组。\n  - 可以在impl模块中函数实现trait中的方法, 对函数进行覆盖。\n  - 模块也是一个功能(processor), 可以嵌套。\n  - ExampleMod代表直接使用字符串, help()代表调用help方法获取, 多个功能用`+`连接\n- 机器人不包含菜单功能, 您可以直接使用 BotContext.processors() 获得所有功能, 自由实现您的菜单, 无论是打印还是绘制图片。\n\n```rust\n// .add_processor(EXAMPLE_MOD)\n\n#[module(\n    name = \"ExampleMod\",\n    help = \"help()\",\n    processors = \"mod_process_a+mod_process_b_instance()\"\n)]\nimpl Module for ExampleMod {}\n\n// processors = \"mod_process_a\"\nfn help() -\u003e \u0026'static str {\n    \"我是帮助\"\n}\n\n#[processor]\nasync fn mod_process_a(_bot_ctx: Arc\u003cBotContext\u003e, _messgae: \u0026Message) -\u003e Result\u003cbool\u003e {\n    Ok(false)\n}\n\n#[processor]\nasync fn mod_process_b(_bot_ctx: Arc\u003cBotContext\u003e, _messgae: \u0026Message) -\u003e Result\u003cbool\u003e {\n    Ok(false)\n}\n\nfn mod_process_b_instance() -\u003e Processor {\n    MOD_PROCESS_B.into()\n}\n```\n\n## 特性\n\n引用:\n- https://napcat.apifox.cn/\n- https://llonebot.apifox.cn/\n- https://github.com/botuniverse/onebot-11/blob/master/api/public.md\n\n- [x] 事件\n  - [x] 监听元事件\n  - [x] 监听私聊、组群消息\n  - [x] 监听通知（群增减员、拍一拍、手气最佳等）\n  - [x] 监听请求（好友请求、进群请求）\n- [x] 操作\n  - [x] 消息\n    - [x] 发送文本、图片、自定义onebot11JSON消息 到 私聊、组群 (并异步取得发送结果以及消息ID)\n    - [x] 撤回消息、根据消息ID获取消息、获取合并转发消息\n    - [x] 获取语音、获取图片、检查是否可以发送图片、检查是否可以发送语音\n    - [x] 转发单条私聊、组群消息\n    - [x] 标记消息已读、图片OCR\n  - [x] 群操作\n    - [x] 群组踢人、禁言、全体禁言、设置管理员、修改群名片、修改群名称、退出（解散）组群、设置群头衔\n    - [x] 获取组群信息、获取组群成员信息、获取组群成员列表\n    - [x] 群戳一戳、设置群备注、群签到\n    - [x] 同意进群请求\n    - [ ] 群组匿名用户禁言、群组匿名\n    - [ ] 获取群荣誉信息\n  - [x] 好友\n    - [x] 同意好友请求\n    - [x] 获取好友列表\n    - [x] 删除好友 (llonebot napcat 接口略有不同, llonebot不支持第2、3个参数将会直接忽略)\n    - [x] 戳一戳\n    - [ ] 发送好友赞\n  - [x] 文件\n    - [x] 获取私聊文件链接、上传群文件、删除群文件、列出群文件根目录、重命名群文件夹、删除群文件夹、获取群文件链接\n  - [x] 认证\n    - [ ] 获取 Cookies、获取 CSRF Token、获取 QQ 相关接口凭证\n  - [ ] 系统\n    - [ ] 获取运行状态、获取版本信息、重启 OneBot 实现、清理缓存\n- [x] 类型\n  - [x] 消息：文本、表情、图片、语音、短视频、@某人、回复、合并转发、合并转发自定义节点、XML 消息、JSON 消息\n  - [ ] 消息: 猜拳魔法表情、掷骰子魔法表情、戳一戳、窗口抖动（戳一戳）、匿名发消息、链接分享、推荐好友、推荐群、位置、音乐分享、音乐自定义分享、合并转发节点\n- [x] 拓展\n  - [x] 机器人命令匹配\n  - [x] 模块\n\n- [x] 快捷回复组群或个人消息, 请参考 [runbot/examples/client.rs](runbot/examples/client.rs) 中的 `pub trait Reply`\n\n## 环境\n\n#### 需要一个支持onebot v11协议的机器人, 推荐:\n\n- https://llonebot.com/guide/getting-started (Windows)\n- https://napneko.github.io/ (Windows/Linux/MacOS)\n- https://github.com/NapNeko/NapCat-Docker (docker)\n\nTips:\n  1. windows推荐llonebot一键启动，安装QQ后直接双击启动运行即可。\n  2. linux 推荐 NapCat-Docker, 创建/opt/napcat/，chown到自己的用户，按照项目给的docker命令运行, 并且增加以下volumn挂载, 容器删除再次创建时数据得以保留\n  - /opt/napcat/.config/QQ/:/app/.config/QQ/         (存放QQ数据，用于自动登录)\n  - /opt/napcat/napcat/config/:/app/napcat/config/   (存放napcat配置文件)\n  - /opt/napcat/disk/:/opt/napcat/disk/              (存放图片等数据，用于和其他容器文件交互)\n  docker容器启动后运行 docker logs -f 扫码登录，并且使用napcat作为密码登录管理后台，设置自动登录的QQ号，下次启动容器时将会自动登录。然后增加一个ws服务端口（例如3001），用于本框架的正向连接。\n\n\n## 贡献\n\n**Ru**stO**n**e**Bot** 欢迎您的参与！\n\n欢迎提交PR, 以及提出issue。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniuhuan%2Frunbot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniuhuan%2Frunbot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniuhuan%2Frunbot/lists"}