First half-working version of IRC transport for Slack
This commit is contained in:
parent
3df6d53f23
commit
05bf03704a
12 changed files with 162 additions and 35 deletions
|
@ -84,6 +84,12 @@ std::string SlackAPI::getChannelId(HTTPRequest *req, bool ok, rapidjson::Documen
|
|||
return id.GetString();
|
||||
}
|
||||
|
||||
void SlackAPI::channelsCreate(const std::string &name, HTTPRequest::Callback callback) {
|
||||
std::string url = "https://slack.com/api/channels.create?name=" + Util::urlencode(name) + "&token=" + Util::urlencode(m_token);
|
||||
HTTPRequest *req = new HTTPRequest(THREAD_POOL(m_component), HTTPRequest::Get, url, callback);
|
||||
queueRequest(req);
|
||||
}
|
||||
|
||||
void SlackAPI::imOpen(const std::string &uid, HTTPRequest::Callback callback) {
|
||||
std::string url = "https://slack.com/api/im.open?user=" + Util::urlencode(uid) + "&token=" + Util::urlencode(m_token);
|
||||
HTTPRequest *req = new HTTPRequest(THREAD_POOL(m_component), HTTPRequest::Get, url, callback);
|
||||
|
@ -183,7 +189,7 @@ void SlackAPI::getSlackChannelInfo(HTTPRequest *req, bool ok, rapidjson::Documen
|
|||
info.members.push_back(members[i].GetString());
|
||||
}
|
||||
|
||||
ret[info.id] = info;
|
||||
ret[info.name] = info;
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
@ -75,6 +75,7 @@ class SlackAPI : public HTTPRequestQueue {
|
|||
void usersList(HTTPRequest::Callback callback);
|
||||
std::string getOwnerId(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
|
||||
|
||||
void channelsCreate(const std::string &name, HTTPRequest::Callback callback);
|
||||
void imOpen(const std::string &uid, HTTPRequest::Callback callback);
|
||||
std::string getChannelId(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ void SlackFrontend::sendRosterRequest(Swift::RosterPayload::ref payload, Swift::
|
|||
}
|
||||
|
||||
void SlackFrontend::sendMessage(boost::shared_ptr<Swift::Message> message) {
|
||||
return static_cast<SlackUserManager *>(m_userManager)->sendMessage(message);
|
||||
}
|
||||
|
||||
void SlackFrontend::sendIQ(boost::shared_ptr<Swift::IQ> iq) {
|
||||
|
|
|
@ -26,9 +26,15 @@
|
|||
#include "transport/Transport.h"
|
||||
#include "transport/HTTPRequest.h"
|
||||
#include "transport/Util.h"
|
||||
#include "transport/Buddy.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "Swiften/Elements/MUCPayload.h"
|
||||
|
||||
#include <map>
|
||||
#include <iterator>
|
||||
|
||||
|
@ -43,15 +49,85 @@ SlackInstallation::SlackInstallation(Component *component, StorageBackend *stora
|
|||
m_rtm = new SlackRTM(component, storageBackend, uinfo);
|
||||
m_rtm->onRTMStarted.connect(boost::bind(&SlackInstallation::handleRTMStarted, this));
|
||||
m_rtm->onMessageReceived.connect(boost::bind(&SlackInstallation::handleMessageReceived, this, _1, _2, _3));
|
||||
|
||||
// m_api = new SlackAPI(component, m_uinfo.encoding);
|
||||
}
|
||||
|
||||
SlackInstallation::~SlackInstallation() {
|
||||
delete m_rtm;
|
||||
// delete m_api;
|
||||
}
|
||||
|
||||
void SlackInstallation::sendMessage(boost::shared_ptr<Swift::Message> message) {
|
||||
LOG4CXX_INFO(logger, "SEND MESSAGE");
|
||||
if (message->getFrom().getResource() == "myfavouritebot") {
|
||||
return;
|
||||
}
|
||||
m_rtm->getAPI()->sendMessage(message->getFrom().getResource(), m_jid2channel[message->getFrom().toBare().toString()], message->getBody());
|
||||
}
|
||||
|
||||
void SlackInstallation::handleMessageReceived(const std::string &channel, const std::string &user, const std::string &message) {
|
||||
if (m_ownerChannel == channel) {
|
||||
LOG4CXX_INFO(logger, "Owner message received " << channel << " " << user << " " << message);
|
||||
if (m_ownerChannel != channel) {
|
||||
std::string to = m_channel2jid[channel];
|
||||
if (!to.empty()) {
|
||||
boost::shared_ptr<Swift::Message> msg(new Swift::Message());
|
||||
msg->setType(Swift::Message::Groupchat);
|
||||
msg->setTo(to);
|
||||
msg->setFrom(Swift::JID("", "spectrum2", "default"));
|
||||
msg->setBody("<" + user + "> " + message);
|
||||
m_component->getFrontend()->onMessageReceived(msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> args;
|
||||
boost::split(args, message, boost::is_any_of(" "));
|
||||
|
||||
if (args.size() < 2 || args[0] != ".spectrum2") {
|
||||
m_rtm->sendMessage(m_ownerChannel, "Unknown command. Use \".spectrum2 help\" for help.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args[1] == "join") {
|
||||
// .spectrum2 join BotName #room irc.freenode.net channel
|
||||
LOG4CXX_INFO(logger, "Received JOIN request" << args.size());
|
||||
if (args.size() == 6) {
|
||||
LOG4CXX_INFO(logger, "Received JOIN request");
|
||||
if (args[4][0] == '<') {
|
||||
args[4] = args[4].substr(1, args[4].size() - 2);
|
||||
args[4] = args[4].substr(args[4].find("|") + 1);
|
||||
LOG4CXX_INFO(logger, args[4]);
|
||||
}
|
||||
|
||||
if (args[5][0] == '<') {
|
||||
args[5] = args[5].substr(2, args[5].size() - 3);
|
||||
}
|
||||
|
||||
|
||||
m_uinfo.uin = args[2];
|
||||
m_storageBackend->setUser(m_uinfo);
|
||||
|
||||
|
||||
std::string to = args[3] + "%" + args[4] + "@localhost";
|
||||
m_jid2channel[to] = args[5];
|
||||
m_channel2jid[args[5]] = to;
|
||||
LOG4CXX_INFO(logger, "Setting transport between " << to << " and " << args[5]);
|
||||
// int type = (int) TYPE_STRING;
|
||||
// m_storageBackend->getUserSetting(user.id, "room", type, to);
|
||||
|
||||
Swift::Presence::ref presence = Swift::Presence::create();
|
||||
presence->setFrom(Swift::JID("", "spectrum2", "default"));
|
||||
presence->setTo(Swift::JID(to + "/" + args[2]));
|
||||
presence->setType(Swift::Presence::Available);
|
||||
presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::MUCPayload()));
|
||||
m_component->getFrontend()->onPresenceReceived(presence);
|
||||
}
|
||||
}
|
||||
else if (args[1] == "help") {
|
||||
|
||||
}
|
||||
else {
|
||||
m_rtm->sendMessage(m_ownerChannel, "Unknown command. Use \".spectrum2 help\" for help.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include "Swiften/Elements/Message.h"
|
||||
|
||||
#include <boost/signal.hpp>
|
||||
|
||||
namespace Transport {
|
||||
|
@ -35,6 +37,7 @@ class Component;
|
|||
class StorageBackend;
|
||||
class HTTPRequest;
|
||||
class SlackRTM;
|
||||
class SlackAPI;
|
||||
|
||||
class SlackInstallation {
|
||||
public:
|
||||
|
@ -44,6 +47,8 @@ class SlackInstallation {
|
|||
|
||||
boost::signal<void (const std::string &user)> onInstallationDone;
|
||||
|
||||
void sendMessage(boost::shared_ptr<Swift::Message> message);
|
||||
|
||||
private:
|
||||
void handleRTMStarted();
|
||||
void handleMessageReceived(const std::string &channel, const std::string &user, const std::string &message);
|
||||
|
@ -56,6 +61,9 @@ class SlackInstallation {
|
|||
std::string m_ownerName;
|
||||
SlackRTM *m_rtm;
|
||||
std::string m_ownerChannel;
|
||||
SlackAPI *m_api;
|
||||
std::map<std::string, std::string> m_jid2channel;
|
||||
std::map<std::string, std::string> m_channel2jid;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -72,6 +72,10 @@ class SlackRTM {
|
|||
return m_users;
|
||||
}
|
||||
|
||||
std::map<std::string, SlackChannelInfo> &getChannels() {
|
||||
return m_channels;
|
||||
}
|
||||
|
||||
SlackAPI *getAPI() {
|
||||
return m_api;
|
||||
}
|
||||
|
|
|
@ -49,27 +49,32 @@ void SlackUserManager::reconnectUser(const std::string &user) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!uinfo.uin.empty()) {
|
||||
LOG4CXX_INFO(logger, "Reconnecting user " << user);
|
||||
Swift::Presence::ref response = Swift::Presence::create();
|
||||
response->setTo(m_component->getJID());
|
||||
response->setFrom(user + "@" + m_component->getJID().toString());
|
||||
response->setType(Swift::Presence::Available);
|
||||
}
|
||||
else {
|
||||
// if (!uinfo.uin.empty()) {
|
||||
// LOG4CXX_INFO(logger, "Reconnecting user " << user);
|
||||
// Swift::Presence::ref response = Swift::Presence::create();
|
||||
// response->setTo(m_component->getJID());
|
||||
// response->setFrom(user + "@" + m_component->getJID().toString());
|
||||
// response->setType(Swift::Presence::Available);
|
||||
// }
|
||||
// else {
|
||||
LOG4CXX_INFO(logger, "Cannot reconnect user " << user << ","
|
||||
"because he does not have legacy network configured. "
|
||||
"Continuing in Installation mode for this user until "
|
||||
"he configures the legacy network.");
|
||||
m_installations[user] = new SlackInstallation(m_component, m_storageBackend, uinfo);
|
||||
m_installations[user]->onInstallationDone.connect(boost::bind(&SlackUserManager::reconnectUser, this, _1));
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
void SlackUserManager::sendVCard(unsigned int id, Swift::VCard::ref vcard) {
|
||||
|
||||
}
|
||||
|
||||
void SlackUserManager::sendMessage(boost::shared_ptr<Swift::Message> message) {
|
||||
LOG4CXX_INFO(logger, message->getTo().toBare().toString());
|
||||
m_installations[message->getTo().toBare().toString()]->sendMessage(message);
|
||||
}
|
||||
|
||||
|
||||
UserRegistration *SlackUserManager::getUserRegistration() {
|
||||
return m_userRegistration;
|
||||
|
|
|
@ -57,6 +57,8 @@ class SlackUserManager : public UserManager {
|
|||
|
||||
std::string getOAuth2URL(const std::vector<std::string> &args);
|
||||
|
||||
void sendMessage(boost::shared_ptr<Swift::Message> message);
|
||||
|
||||
private:
|
||||
Component *m_component;
|
||||
UserRegistration *m_userRegistration;
|
||||
|
|
|
@ -104,19 +104,26 @@ std::string SlackUserRegistration::getTeamDomain(const std::string &token) {
|
|||
|
||||
std::string SlackUserRegistration::handleOAuth2Code(const std::string &code, const std::string &state) {
|
||||
OAuth2 *oauth2 = NULL;
|
||||
std::string token;
|
||||
std::vector<std::string> data;
|
||||
if (m_auths.find(state) != m_auths.end()) {
|
||||
oauth2 = m_auths[state];
|
||||
data = m_authsData[state];
|
||||
|
||||
if (state == "use_bot_token") {
|
||||
token = code;
|
||||
}
|
||||
else {
|
||||
return "Received state code '" + state + "' not found in state codes list.";
|
||||
}
|
||||
if (m_auths.find(state) != m_auths.end()) {
|
||||
oauth2 = m_auths[state];
|
||||
data = m_authsData[state];
|
||||
}
|
||||
else {
|
||||
return "Received state code '" + state + "' not found in state codes list.";
|
||||
}
|
||||
|
||||
std::string token;
|
||||
std::string error = oauth2->requestToken(code, token);
|
||||
if (!error.empty()) {
|
||||
return error;
|
||||
std::string token;
|
||||
std::string error = oauth2->requestToken(code, token);
|
||||
if (!error.empty()) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
UserInfo user;
|
||||
|
@ -131,16 +138,25 @@ std::string SlackUserRegistration::handleOAuth2Code(const std::string &code, con
|
|||
|
||||
m_storageBackend->getUser(user.jid, user);
|
||||
|
||||
std::string value = data[2];
|
||||
int type = (int) TYPE_STRING;
|
||||
m_storageBackend->getUserSetting(user.id, "bot_token", type, value);
|
||||
if (oauth2) {
|
||||
std::string value = data[2];
|
||||
int type = (int) TYPE_STRING;
|
||||
m_storageBackend->getUserSetting(user.id, "bot_token", type, value);
|
||||
}
|
||||
else {
|
||||
std::string value = token;
|
||||
int type = (int) TYPE_STRING;
|
||||
m_storageBackend->getUserSetting(user.id, "bot_token", type, value);
|
||||
}
|
||||
|
||||
LOG4CXX_INFO(logger, "Registered Slack user " << user.jid);
|
||||
|
||||
m_auths.erase(state);
|
||||
delete oauth2;
|
||||
if (oauth2) {
|
||||
m_auths.erase(state);
|
||||
delete oauth2;
|
||||
|
||||
m_authsData.erase(state);
|
||||
m_authsData.erase(state);
|
||||
}
|
||||
|
||||
m_component->getFrontend()->reconnectUser(user.jid);
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "transport/RosterManager.h"
|
||||
#include "transport/Frontend.h"
|
||||
#include "transport/Config.h"
|
||||
#include "transport/Logging.h"
|
||||
|
||||
#include "Swiften/Elements/MUCItem.h"
|
||||
#include "Swiften/Elements/MUCOccupant.h"
|
||||
|
@ -35,6 +36,8 @@
|
|||
#include "Swiften/Elements/MUCPayload.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
DEFINE_LOGGER(logger, "Conversation");
|
||||
|
||||
Conversation::Conversation(ConversationManager *conversationManager, const std::string &legacyName, bool isMUC) : m_conversationManager(conversationManager) {
|
||||
m_legacyName = legacyName;
|
||||
|
@ -195,6 +198,7 @@ void Conversation::handleMessage(boost::shared_ptr<Swift::Message> &message, con
|
|||
}
|
||||
|
||||
message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), n));
|
||||
LOG4CXX_INFO(logger, "MSG FROM " << message->getFrom().toString());
|
||||
}
|
||||
|
||||
handleRawMessage(message);
|
||||
|
|
|
@ -661,8 +661,10 @@ void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool
|
|||
}
|
||||
|
||||
User *user = m_userManager->getUser(payload.username());
|
||||
if (!user)
|
||||
if (!user) {
|
||||
LOG4CXX_ERROR(logger, "handleConvMessagePayload: unknown username " << payload.username());
|
||||
return;
|
||||
}
|
||||
|
||||
// Message from legacy network triggers network acticity
|
||||
user->updateLastActivity();
|
||||
|
@ -697,6 +699,7 @@ void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool
|
|||
// We can't create Conversation for payload with nickname, because this means the message is from room,
|
||||
// but this user is not in any room, so it's OK to just reject this message
|
||||
if (!conv && !payload.nickname().empty()) {
|
||||
LOG4CXX_WARN(logger, "handleConvMessagePayload: No conversation with name " << payload.buddyname());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ bool SQLite3Backend::connect() {
|
|||
if (createDatabase() == false)
|
||||
return false;
|
||||
|
||||
PREP_STMT(m_setUser, "INSERT OR REPLACE INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES (?, ?, ?, ?, ?, DATETIME('NOW'), ?)");
|
||||
PREP_STMT(m_setUser, "INSERT OR REPLACE INTO " + m_prefix + "users (id, jid, uin, password, language, encoding, last_login, vip) VALUES (?, ?, ?, ?, ?, ?, DATETIME('NOW'), ?)");
|
||||
PREP_STMT(m_getUser, "SELECT id, jid, uin, password, encoding, language, vip FROM " + m_prefix + "users WHERE jid=?");
|
||||
|
||||
PREP_STMT(m_removeUser, "DELETE FROM " + m_prefix + "users WHERE id=?");
|
||||
|
@ -223,12 +223,13 @@ bool SQLite3Backend::exec(const std::string &query) {
|
|||
|
||||
void SQLite3Backend::setUser(const UserInfo &user) {
|
||||
sqlite3_reset(m_setUser);
|
||||
sqlite3_bind_text(m_setUser, 1, user.jid.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(m_setUser, 2, user.uin.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(m_setUser, 3, user.password.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(m_setUser, 4, user.language.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(m_setUser, 5, user.encoding.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int (m_setUser, 6, user.vip);
|
||||
sqlite3_bind_int(m_setUser, 1, user.id);
|
||||
sqlite3_bind_text(m_setUser, 2, user.jid.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(m_setUser, 3, user.uin.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(m_setUser, 4, user.password.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(m_setUser, 5, user.language.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(m_setUser, 6, user.encoding.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int (m_setUser, 7, user.vip);
|
||||
|
||||
if(sqlite3_step(m_setUser) != SQLITE_DONE) {
|
||||
LOG4CXX_ERROR(logger, "setUser query"<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db)));
|
||||
|
|
Loading…
Add table
Reference in a new issue