feat: some fixes, features, and README

This commit is contained in:
Noa Himesaka
2026-01-29 01:58:09 +09:00
parent fe6ce755d1
commit 591d25c0c0
5 changed files with 90 additions and 5 deletions
+1
View File
@@ -1,3 +1,4 @@
MATRIX_HOMESERVER=https://matrix.org
MATRIX_USERNAME=your_username
MATRIX_PASSWORD=your_password
IGNORE_BRIDGE_USERS=false
+42
View File
@@ -0,0 +1,42 @@
# Matrix Wiki Link Bot
A simple Matrix bot that listens for commands starting with `.wiki` and responds with links from a configured JSON store.
## Configuration
The bot is configured via environment variables.
| Variable | Description | Default |
|----------|-------------|---------|
| `MATRIX_HOMESERVER` | The URL of your Matrix homeserver (e.g., `https://matrix.org`). | |
| `MATRIX_USERNAME` | The bot's Matrix username. | |
| `MATRIX_PASSWORD` | The bot's Matrix password. | |
| `IGNORE_BRIDGE_USERS`| If set to `true`, the bot will ignore messages from senders whose MXID starts with `@discord_`. | `false` |
## Usage
### Docker
1. Copy `docker-compose.example.yml` to `docker-compose.yml` and `links.json` to a local file.
2. Update the environment variables in `docker-compose.yml`.
3. Populate `links.json` with your key-value pairs.
4. Run the bot:
```bash
docker-compose up -d
```
### Local Development
1. Copy `.env.example` to `.env`.
2. Update `.env` with your credentials.
3. Run the bot:
```bash
cargo run
```
## Commands
- `.wiki list`: Lists all available wiki keys.
- `.wiki <term>`: Fetches the link associated with `<term>` from the `links.json` file.
+1
View File
@@ -5,6 +5,7 @@ services:
- MATRIX_HOMESERVER=https://matrix.org
- MATRIX_USERNAME=your_username
- MATRIX_PASSWORD=your_password
- IGNORE_BRIDGE_USERS=false
volumes:
- ./links.json:/usr/local/bin/links.json
restart: unless-stopped
+6
View File
@@ -17,6 +17,12 @@ impl LinkStore {
pub fn get(&self, key: &str) -> Option<&String> {
self.links.get(key)
}
pub fn list_keys(&self) -> Vec<String> {
let mut keys: Vec<String> = self.links.keys().cloned().collect();
keys.sort();
keys
}
}
#[cfg(test)]
+40 -5
View File
@@ -37,20 +37,55 @@ async fn main() -> Result<()> {
client.matrix_auth().login_username(&username, &password).await?;
let ignore_bridge_users = env::var("IGNORE_BRIDGE_USERS")
.map(|v| v.to_lowercase() == "true")
.unwrap_or(false);
let start_time = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("Time went backwards")
.as_millis() as u64;
// Share link_store with event handler
let store_clone = link_store.clone();
client.add_event_handler(move |event: OriginalSyncRoomMessageEvent, room: Room| {
let store = store_clone.clone();
async move {
let sender = event.sender.as_str();
if ignore_bridge_users && sender.starts_with("@discord_") {
return;
}
if u64::from(event.origin_server_ts.get()) < start_time {
return;
}
let RoomMessageEventContent { msgtype, .. } = event.content;
if let MessageType::Text(text_content) = msgtype {
let body = text_content.body;
if body.starts_with(".wiki ") {
let argument = body.trim_start_matches(".wiki ").trim();
if let Some(link) = store.get(argument) {
let response = format!("Link for {}: {}", argument, link);
if body == ".wiki" || body.starts_with(".wiki ") {
let argument = body.trim_start_matches(".wiki").trim();
if argument.is_empty() {
let response = "Use .wiki list to print all available links";
let content = RoomMessageEventContent::text_plain(response);
if let Err(e) = room.send(content).await {
eprintln!("Failed to send message: {}", e);
}
} else if argument == "list" {
let keys = store.list_keys();
let response = if keys.is_empty() {
"No wiki links available.".to_string()
} else {
format!("Available wiki links: {}", keys.join(", "))
};
let content = RoomMessageEventContent::text_plain(response);
if let Err(e) = room.send(content).await {
eprintln!("Failed to send message: {}", e);
}
} else if let Some(link) = store.get(argument) {
let response = format!("Link for {}: {}\n(Use .wiki list to print all available links)", argument, link);
// Send response
let content = RoomMessageEventContent::text_plain(response);
if let Err(e) = room.send(content).await {
@@ -58,7 +93,7 @@ async fn main() -> Result<()> {
}
} else {
// Optional: reply not found, or just ignore
let response = format!("No wiki link found for '{}'", argument);
let response = format!("No wiki link found for '{}'\n(Use .wiki list to print all available links)", argument);
let content = RoomMessageEventContent::text_plain(response);
if let Err(e) = room.send(content).await {
eprintln!("Failed to send message: {}", e);