Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ notifier:
enabled: false # Set to true to enable Lark notifications
webhook_url: "${LARK_WEBHOOK_URL}" # Your Lark webhook URL (recommended: store in .env)

# OneBot-11 notifier - sends messages to OneBot v11 servers (supports QQ, Discord, Lark, etc.)
# See: https://github.com/botuniverse/onebot-11
onebot-11:
enabled: false # Set to true to enable OneBot-11 notifications
url: "http://127.0.0.1:5700" # OneBot HTTP API server URL
access_token: "${ONEBOT_ACCESS_TOKEN}" # Access token for authentication (recommended: store in .env)
to_group_ids: [] # List of group IDs to send notifications to, e.g., ["1016792818", "1234567890"]
to_friend_ids: [] # List of friend/user IDs to send notifications to, e.g., ["2014709936", "9876543210"]

# Watchers configuration
watchers:
# IMAP Email Watcher
Expand Down
43 changes: 43 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ AWA supports multiple notification backends:

**Console Notifier** - Rich markdown rendering in your terminal
**Ntfy Notifier** - Push notifications to [ntfy.sh](https://ntfy.sh) (self-hosted or public)
**Lark Notifier** - Send messages to Lark (Feishu) via webhook
**OneBot-11 Notifier** - Send messages to OneBot-11 servers (supports QQ, Discord, Lark via adapters)

More notifiers can be added by extending `BaseNotifier`.

Expand Down Expand Up @@ -144,6 +146,47 @@ notifier:
Authorization: "Bearer your-token"
```

### OneBot-11 Notifier

The OneBot-11 notifier allows AWA to send messages to OneBot-11 compatible servers, which provides indirect support for multiple platforms including QQ, Discord, Lark, and more through protocol adapters.

**Features:**
- Send messages to multiple groups simultaneously
- Send private messages to multiple users
- Authentication via access token
- Configurable server URL
- Automatic error handling and retry

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation at line 158 claims "Automatic error handling and retry" but the implementation only includes error handling (logging errors) without any retry logic. Either implement retry functionality or update the documentation to remove the "and retry" claim.

Suggested change
- Automatic error handling and retry
- Automatic error handling

Copilot uses AI. Check for mistakes.

**Configuration in `config.yaml`:**

```yaml
notifier:
onebot-11:
enabled: true
url: "http://127.0.0.1:5700" # OneBot HTTP API server URL
access_token: "${ONEBOT_ACCESS_TOKEN}" # Use environment variable for security
to_group_ids: # List of group IDs to send notifications to
- "1016792818"
- "1234567890"
to_friend_ids: # List of friend/user IDs to send private messages to
- "2014709936"
- "9876543210"
```

**Setup Steps:**

1. Deploy an OneBot-11 compatible server (e.g., [go-cqhttp](https://github.com/Mrs4s/go-cqhttp), [OpenShamrock](https://github.com/whitechi73/OpenShamrock))
2. Configure the server to listen on HTTP (default: `http://127.0.0.1:5700`)
3. (Optional) Set an access token in the OneBot server for authentication
4. Add the OneBot-11 configuration to your `config.yaml`
5. Store your access token in `.env` file: `ONEBOT_ACCESS_TOKEN=your-secret-token`

**Relevant Documentation:**
- [OneBot-11 Protocol](https://github.com/botuniverse/onebot-11)
- [OneBot-11 HTTP Communication](https://github.com/botuniverse/onebot-11/blob/master/communication/http.md)
- [OneBot-11 API Reference](https://github.com/botuniverse/onebot-11/blob/master/api/public.md)


## Built-in Watchers

### IMAP Email Watcher
Expand Down
102 changes: 102 additions & 0 deletions notifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,103 @@ async def close(self) -> None:
self.session = None


class OneBotNotifier(BaseNotifier):
"""OneBot-11 notifier that sends messages to OneBot-11 servers via HTTP"""

def __init__(self, config: dict):
super().__init__(config)
self.url = config.get("url", "http://127.0.0.1:5700")
self.access_token = config.get("access_token", "")
self.to_group_ids = config.get("to_group_ids", [])
self.to_friend_ids = config.get("to_friend_ids", [])

if not self.to_group_ids and not self.to_friend_ids:
logger.warning(
"OneBotNotifier: No group or friend IDs configured, notifications will not be sent"
)

# Prepare headers once during initialization
self.headers = {}
if self.access_token:
self.headers["Authorization"] = f"Bearer {self.access_token}"

self.session = None
logger.info(
f"OneBot-11 notifier initialized: {self.url} "
f"(groups: {len(self.to_group_ids)}, friends: {len(self.to_friend_ids)})"
)

async def send(self, markdown_content: str) -> None:
"""
Send notification to OneBot-11 server.

Args:
markdown_content: The notification content in markdown format
"""
if not self.enabled:
return

if not self.to_group_ids and not self.to_friend_ids:
return

# Check if session is initialized
if self.session is None:
# Import here to avoid dependency if not using OneBotNotifier
import aiohttp

# Create session with timeout configuration
timeout = aiohttp.ClientTimeout(total=30)
self.session = aiohttp.ClientSession(timeout=timeout)

# Send to all configured groups
for group_id in self.to_group_ids:
payload = {"group_id": group_id, "message": markdown_content}
try:
async with self.session.post(
f"{self.url}/send_group_msg", json=payload, headers=self.headers
) as response:
if response.status != 200:
text = await response.text()
logger.error(
f"Failed to send OneBot group message to {group_id}: {response.status}, {text}"
)
else:
logger.debug(f"OneBot group notification sent to {group_id}")
except Exception as e:
logger.error(
f"Error sending OneBot group notification to {group_id}: {e}",
exc_info=True,
)

# Send to all configured friends
for friend_id in self.to_friend_ids:
payload = {"user_id": friend_id, "message": markdown_content}
try:
async with self.session.post(
f"{self.url}/send_private_msg", json=payload, headers=self.headers
) as response:
if response.status != 200:
text = await response.text()
logger.error(
f"Failed to send OneBot private message to {friend_id}: {response.status}, {text}"
)
else:
logger.debug(
f"OneBot private notification sent to {friend_id}"
)
except Exception as e:
logger.error(
f"Error sending OneBot private notification to {friend_id}: {e}",
exc_info=True,
)
Comment on lines +222 to +261

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description claims the notifier "Sends to multiple group_ids and user_ids concurrently" but the implementation sends messages sequentially using for loops. To match the description and improve performance, consider using asyncio.gather() to send all messages concurrently.

Copilot uses AI. Check for mistakes.

async def close(self) -> None:
"""Close the aiohttp session"""
if self.session is not None:
await self.session.close()
self.session = None


class Notifier:
"""Main notifier class that manages multiple notification providers. This class handles the configuration file and initializes the appropriate notifier instances based on the provided settings."""

Expand Down Expand Up @@ -197,6 +294,11 @@ def __init__(self, config: dict):
if lark_config.get("enabled", False):
self.notifiers.append(LarkNotifier(lark_config))

# Initialize onebot-11 notifier if configured
onebot_config = config.get("onebot-11", {})
if onebot_config.get("enabled", False):
self.notifiers.append(OneBotNotifier(onebot_config))

logger.info(
f"Notifier system initialized with {len(self.notifiers)} provider(s)"
)
Expand Down
Loading