Changes
diff --git a/design.md b/design.md
index 23d0eb7..2004ac6 100644
--- a/design.md
+++ b/design.md
@@ -37,13 +37,17 @@ Configuration is handled via Command Line Arguments:
```json
{
"chat_id": 123456789,
+ "username": "some_user",
"text": "Hello World"
}
```
+* `text` (Required): The message content.
+* `chat_id` (Optional): The target chat ID.
+* `username` (Optional): If `chat_id` is not provided, the bot will look up the most recent `chat_id` associated with this username.
**Response:**
* `200 OK`: Message sent successfully.
-* `400 Bad Request`: Invalid JSON or missing fields.
+* `400 Bad Request`: Missing `text`, or neither `chat_id` nor `username` provided, or username not found.
* `500 Internal Error`: Upstream Telegram error.
### 4.2. Subscribe
diff --git a/src/main.cpp b/src/main.cpp
index a28b3d6..a69389d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -6,6 +6,7 @@
#include <thread>
#include <chrono>
#include <expected>
+#include <optional>
#include <cxxopts.hpp>
#include <nlohmann/json.hpp>
@@ -85,6 +86,30 @@ private:
std::map<int64_t, std::vector<std::string>> subscribers_;
};
+class UsernameResolver
+{
+public:
+ void update(const std::string& username, int64_t chat_id)
+ {
+ std::lock_guard lock(mutex_);
+ username_map_[username] = chat_id;
+ }
+
+ std::optional<int64_t> resolve(const std::string& username)
+ {
+ std::lock_guard lock(mutex_);
+ if(auto it = username_map_.find(username); it != username_map_.end())
+ {
+ return it->second;
+ }
+ return std::nullopt;
+ }
+
+private:
+ std::mutex mutex_;
+ std::map<std::string, int64_t> username_map_;
+};
+
class App : public mw::HTTPServer
{
public:
@@ -100,15 +125,40 @@ public:
try
{
auto body = json::parse(req.body);
- if(!body.contains("chat_id") || !body.contains("text"))
+ if(!body.contains("text"))
{
res.status = 400;
- res.set_content("Missing chat_id or text", "text/plain");
+ res.set_content("Missing text", "text/plain");
+ return;
+ }
+
+ int64_t chat_id = 0;
+ if(body.contains("chat_id"))
+ {
+ chat_id = body["chat_id"];
+ }
+ else if(body.contains("username"))
+ {
+ auto username = body["username"].get<std::string>();
+ auto resolved = username_resolver_.resolve(username);
+ if(!resolved.has_value())
+ {
+ res.status = 404;
+ res.set_content("Username not found", "text/plain");
+ return;
+ }
+ chat_id = *resolved;
+ }
+ else
+ {
+ res.status = 400;
+ res.set_content("Missing chat_id or username",
+ "text/plain");
return;
}
ASSIGN_OR_RESPOND_ERROR(auto result,
- tg_client_.sendMessage(body["chat_id"],
+ tg_client_.sendMessage(chat_id,
body["text"]),
res);
res.status = 200;
@@ -184,6 +234,13 @@ private:
void dispatchMessage(const json& message)
{
int64_t chat_id = message["chat"]["id"];
+
+ if(message.contains("from") && message["from"].contains("username"))
+ {
+ std::string username = message["from"]["username"];
+ username_resolver_.update(username, chat_id);
+ }
+
auto callbacks = sub_manager_.getSubscribers(chat_id);
for(const auto& url : callbacks)
@@ -206,6 +263,7 @@ private:
TelegramClient tg_client_;
SubscriptionManager sub_manager_;
+ UsernameResolver username_resolver_;
bool running_ = true;
};
@@ -277,4 +335,4 @@ int main(int argc, char** argv)
}
return 0;
-}
\ No newline at end of file
+}
diff --git a/test_api.sh b/test_api.sh
index b3bef1d..b79bd00 100644
--- a/test_api.sh
+++ b/test_api.sh
@@ -11,8 +11,8 @@ curl -X POST "$API_URL/subscribe" \
-d '{"chat_id": 12345, "callback_url": "http://localhost:9090/webhook"}'
echo -e "\n"
-echo "Testing /send (should fail if token is invalid, but test API structure)..."
+echo "Testing /send with username (requires prior message from user)..."
curl -X POST "$API_URL/send" \
-H "Content-Type: application/json" \
- -d '{"chat_id": 12345, "text": "Test message"}'
+ -d '{"username": "some_user", "text": "Test message to username"}'
echo -e "\n"