{"id":13832714,"url":"https://github.com/slaninas/nostr-bot","last_synced_at":"2025-07-09T19:31:12.030Z","repository":{"id":54450113,"uuid":"522239643","full_name":"slaninas/nostr-bot","owner":"slaninas","description":"Nostr bot library for Rust","archived":false,"fork":false,"pushed_at":"2023-06-03T20:50:05.000Z","size":148,"stargazers_count":41,"open_issues_count":3,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-05-14T13:02:37.592Z","etag":null,"topics":["bot","nostr","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/slaninas.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}},"created_at":"2022-08-07T14:45:17.000Z","updated_at":"2024-04-20T08:53:29.000Z","dependencies_parsed_at":"2024-01-13T16:28:31.814Z","dependency_job_id":"44235259-f071-4814-9d0d-c27af4fa28e4","html_url":"https://github.com/slaninas/nostr-bot","commit_stats":{"total_commits":111,"total_committers":2,"mean_commits":55.5,"dds":"0.018018018018018056","last_synced_commit":"309b9235ee40763ea3c733c7c21081abdee2ce1f"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slaninas%2Fnostr-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slaninas%2Fnostr-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slaninas%2Fnostr-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slaninas%2Fnostr-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/slaninas","download_url":"https://codeload.github.com/slaninas/nostr-bot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225581825,"owners_count":17491794,"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","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","nostr","rust"],"created_at":"2024-08-04T11:00:28.587Z","updated_at":"2024-11-20T15:31:02.702Z","avatar_url":"https://github.com/slaninas.png","language":"Rust","funding_links":[],"categories":["Install from Source","Libraries"],"sub_categories":["Nostr","Client reviews and/or comparisons"],"readme":"# Nostr Bot\n\n![workflow](https://github.com/slaninas/nostr-bot/actions/workflows/rust.yml/badge.svg)\n\nDo you want to run your own nostr bot? You've come to the right place.\nThis crate makes it easy to implement your own bot that reacts to [nostr](https://github.com/nostr-protocol/nostr) events, using [tokio](https://github.com/tokio-rs/tokio).\n\nThis crate is young and still being developed so there may be hiccups. If you find any issue, don't hesitate to create PR/issue on [GitHub](https://github.com/slaninas/nostr-bot).\n\nFull documentation is available [here](https://docs.rs/nostr-bot/latest/nostr_bot/).\n\n## Usage\n\nThis crate is on [crates.io](https://crates.io/crates/nostr-bot) and can be\nused by adding `nostr-bot` to your dependencies in your project's `Cargo.toml`.\n\n```toml\n[dependencies]\nnostr-bot = \"0.2\"\n\n```\n\nYou can also use GitHub [repository](https://github.com/slaninas/nostr-bot):\n```toml\n[dependencies]\nnostr-bot = { git = \"https://github.com/slaninas/nostr-bot\", rev = \"v0.2.3\" }\n```\n\nOr you can clone the [repository](https://github.com/slaninas/nostr-bot) and use it locally:\n```toml\n[dependency]\nnostr-bot = { path = \"your/path/to/nostr-bot\" }\n```\n\n\n\n## Example\n```rust\n// Bot that reacts to '!yes', '!no' and '!results' commands.\nuse nostr_bot::*;\n\n// Your struct that will be passed to the commands responses\nstruct Votes {\n    question: String,\n    yes: u64,\n    no: u64,\n}\n\ntype State = nostr_bot::State\u003cVotes\u003e;\n\nfn format_results(question: \u0026str, votes: \u0026Votes) -\u003e String {\n    format!(\n        \"{}\\n------------------\\nyes: {}\\nno:  {}\",\n        question, votes.yes, votes.no\n    )\n}\n\n// Following functions are command responses, you are getting nostr event\n// and shared state as arguments and you are supposed to return non-signed\n// event which is then signed using the bot's key and send to relays\nasync fn yes(event: Event, state: State) -\u003e EventNonSigned {\n    let mut votes = state.lock().await;\n    votes.yes += 1;\n\n    // Use formatted voting results to create new event\n    // that is a reply to the incoming command\n    get_reply(event, format_results(\u0026votes.question, \u0026votes))\n}\n\nasync fn no(event: Event, state: State) -\u003e EventNonSigned {\n    let mut votes = state.lock().await;\n    votes.no += 1;\n    get_reply(event, format_results(\u0026votes.question, \u0026votes))\n}\n\nasync fn results(event: Event, state: State) -\u003e EventNonSigned {\n    let votes = state.lock().await;\n    get_reply(event, format_results(\u0026votes.question, \u0026votes))\n}\n\n#[tokio::main]\nasync fn main() {\n    init_logger();\n\n    let relays = vec![\n        \"wss://nostr-pub.wellorder.net\",\n        \"wss://relay.damus.io\",\n        \"wss://relay.nostr.info\",\n    ];\n\n    let keypair = keypair_from_secret(\n        // Your secret goes here, can be hex or bech32 (nsec1...)\n        \"0000000000000000000000000000000000000000000000000000000000000001\",\n    );\n\n    let question = String::from(\"Do you think Pluto should be a planet?\");\n\n    // Wrap your object into Arc\u003cMutex\u003e so it can be shared among command handlers\n    let shared_state = wrap_state(Votes {\n        question: question.clone(),\n        yes: 0,\n        no: 0,\n    });\n\n    // And now the Bot\n    Bot::new(keypair, relays, shared_state)\n        // You don't have to set these but then the bot will have incomplete profile info :(\n        .name(\"poll_bot\")\n        .about(\"Just a bot.\")\n        .picture(\"https://i.imgur.com/ij4XprK.jpeg\")\n        .intro_message(\u0026question)\n        // You don't have to specify any command but then what will the bot do? Nothing.\n        .command(Command::new(\"!yes\", wrap!(yes)))\n        .command(Command::new(\"!no\", wrap!(no)))\n        .command(Command::new(\"!results\", wrap!(results)))\n        // And finally run it\n        .run()\n        .await;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslaninas%2Fnostr-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslaninas%2Fnostr-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslaninas%2Fnostr-bot/lists"}