Support for registering OAuth2 users using spectrum2_manager + lot of Slack improvements
This commit is contained in:
parent
ad127c5dd6
commit
5adb3d1f97
31 changed files with 959 additions and 51 deletions
|
@ -92,6 +92,7 @@ class Frontend {
|
||||||
virtual void addRoomToRoomList(const std::string &handle, const std::string &name) = 0;
|
virtual void addRoomToRoomList(const std::string &handle, const std::string &name) = 0;
|
||||||
|
|
||||||
virtual std::string setOAuth2Code(const std::string &code, const std::string &state) { return "OAuth2 code is not needed for this frontend."; }
|
virtual std::string setOAuth2Code(const std::string &code, const std::string &state) { return "OAuth2 code is not needed for this frontend."; }
|
||||||
|
virtual std::string getOAuth2URL(const std::vector<std::string> &args) { return ""; }
|
||||||
|
|
||||||
boost::signal<void (User *, const std::string &name, unsigned int id)> onVCardRequired;
|
boost::signal<void (User *, const std::string &name, unsigned int id)> onVCardRequired;
|
||||||
boost::signal<void (User *, boost::shared_ptr<Swift::VCard> vcard)> onVCardUpdated;
|
boost::signal<void (User *, boost::shared_ptr<Swift::VCard> vcard)> onVCardUpdated;
|
||||||
|
|
|
@ -1,20 +1,27 @@
|
||||||
#ifndef HTTPREQ_H
|
|
||||||
#define HTTPREQ_H
|
#pragma once
|
||||||
|
|
||||||
#include "curl/curl.h"
|
#include "curl/curl.h"
|
||||||
#include "transport/Logging.h"
|
#include "transport/Logging.h"
|
||||||
|
#include "transport/ThreadPool.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "rapidjson/document.h"
|
#include "rapidjson/document.h"
|
||||||
|
|
||||||
|
#include <boost/signal.hpp>
|
||||||
|
|
||||||
namespace Transport {
|
namespace Transport {
|
||||||
|
|
||||||
class HTTPRequest {
|
class HTTPRequest : public Thread {
|
||||||
public:
|
public:
|
||||||
HTTPRequest();
|
typedef enum { Get } Type;
|
||||||
|
typedef boost::function< void (HTTPRequest *, bool, rapidjson::Document &json, const std::string &data) > Callback;
|
||||||
|
|
||||||
~HTTPRequest() {
|
HTTPRequest(ThreadPool *tp, Type type, const std::string &url, Callback callback);
|
||||||
|
HTTPRequest(Type type, const std::string &url);
|
||||||
|
|
||||||
|
virtual ~HTTPRequest() {
|
||||||
if(curlhandle) {
|
if(curlhandle) {
|
||||||
curl_easy_cleanup(curlhandle);
|
curl_easy_cleanup(curlhandle);
|
||||||
curlhandle = NULL;
|
curlhandle = NULL;
|
||||||
|
@ -22,17 +29,32 @@ class HTTPRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setProxy(std::string, std::string, std::string, std::string);
|
void setProxy(std::string, std::string, std::string, std::string);
|
||||||
bool GET(std::string url, std::string &output);
|
bool execute();
|
||||||
bool GET(std::string url, rapidjson::Document &json);
|
bool execute(rapidjson::Document &json);
|
||||||
std::string getCurlError() {return std::string(curl_errorbuffer);}
|
std::string getError() {return std::string(curl_errorbuffer);}
|
||||||
|
|
||||||
|
void run();
|
||||||
|
void finalize();
|
||||||
|
|
||||||
|
boost::signal<void ()> onRequestFinished;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool init();
|
bool init();
|
||||||
|
bool GET(std::string url, std::string &output);
|
||||||
|
bool GET(std::string url, rapidjson::Document &json);
|
||||||
|
|
||||||
|
|
||||||
CURL *curlhandle;
|
CURL *curlhandle;
|
||||||
char curl_errorbuffer[1024];
|
char curl_errorbuffer[1024];
|
||||||
std::string error;
|
std::string error;
|
||||||
std::string callbackdata;
|
std::string callbackdata;
|
||||||
|
ThreadPool *m_tp;
|
||||||
|
std::string m_url;
|
||||||
|
bool m_ok;
|
||||||
|
rapidjson::Document m_json;
|
||||||
|
std::string m_data;
|
||||||
|
Callback m_callback;
|
||||||
|
Type m_type;
|
||||||
|
|
||||||
static int curlCallBack(char* data, size_t size, size_t nmemb, HTTPRequest *obj);
|
static int curlCallBack(char* data, size_t size, size_t nmemb, HTTPRequest *obj);
|
||||||
|
|
||||||
|
@ -40,4 +62,3 @@ class HTTPRequest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
33
include/transport/HTTPRequestQueue.h
Normal file
33
include/transport/HTTPRequestQueue.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "curl/curl.h"
|
||||||
|
#include "transport/Logging.h"
|
||||||
|
#include "transport/ThreadPool.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string.h>
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
|
||||||
|
namespace Transport {
|
||||||
|
|
||||||
|
class HTTPRequest;
|
||||||
|
|
||||||
|
class HTTPRequestQueue {
|
||||||
|
public:
|
||||||
|
HTTPRequestQueue(int delayBetweenRequests = 1);
|
||||||
|
|
||||||
|
virtual ~HTTPRequestQueue();
|
||||||
|
|
||||||
|
void queueRequest(HTTPRequest *req);
|
||||||
|
|
||||||
|
void sendNextRequest();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_delay;
|
||||||
|
std::queue<HTTPRequest *> m_queue;
|
||||||
|
bool m_processing;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -83,6 +83,8 @@ class MySQLBackend : public StorageBackend
|
||||||
|
|
||||||
bool getOnlineUsers(std::vector<std::string> &users);
|
bool getOnlineUsers(std::vector<std::string> &users);
|
||||||
|
|
||||||
|
bool getUsers(std::vector<std::string> &users);
|
||||||
|
|
||||||
long addBuddy(long userId, const BuddyInfo &buddyInfo);
|
long addBuddy(long userId, const BuddyInfo &buddyInfo);
|
||||||
|
|
||||||
void updateBuddy(long userId, const BuddyInfo &buddyInfo);
|
void updateBuddy(long userId, const BuddyInfo &buddyInfo);
|
||||||
|
@ -156,6 +158,7 @@ class MySQLBackend : public StorageBackend
|
||||||
Statement *m_getBuddiesSettings;
|
Statement *m_getBuddiesSettings;
|
||||||
Statement *m_setUserOnline;
|
Statement *m_setUserOnline;
|
||||||
Statement *m_getOnlineUsers;
|
Statement *m_getOnlineUsers;
|
||||||
|
Statement *m_getUsers;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,11 @@ class OAuth2 {
|
||||||
|
|
||||||
std::string generateAuthURL();
|
std::string generateAuthURL();
|
||||||
|
|
||||||
std::string handleOAuth2Code(const std::string &code, const std::string &state);
|
const std::string &getState() {
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string requestToken(const std::string &code, std::string &error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_clientId;
|
std::string m_clientId;
|
||||||
|
|
|
@ -83,6 +83,8 @@ class PQXXBackend : public StorageBackend
|
||||||
|
|
||||||
bool getOnlineUsers(std::vector<std::string> &users);
|
bool getOnlineUsers(std::vector<std::string> &users);
|
||||||
|
|
||||||
|
bool getUsers(std::vector<std::string> &users);
|
||||||
|
|
||||||
long addBuddy(long userId, const BuddyInfo &buddyInfo);
|
long addBuddy(long userId, const BuddyInfo &buddyInfo);
|
||||||
|
|
||||||
void updateBuddy(long userId, const BuddyInfo &buddyInfo);
|
void updateBuddy(long userId, const BuddyInfo &buddyInfo);
|
||||||
|
|
|
@ -72,6 +72,8 @@ class SQLite3Backend : public StorageBackend
|
||||||
|
|
||||||
bool getOnlineUsers(std::vector<std::string> &users);
|
bool getOnlineUsers(std::vector<std::string> &users);
|
||||||
|
|
||||||
|
bool getUsers(std::vector<std::string> &users);
|
||||||
|
|
||||||
/// Removes user and all connected data from database.
|
/// Removes user and all connected data from database.
|
||||||
/// \param id id of user - UserInfo.id
|
/// \param id id of user - UserInfo.id
|
||||||
/// \return true if user has been found in database and removed
|
/// \return true if user has been found in database and removed
|
||||||
|
@ -124,6 +126,7 @@ class SQLite3Backend : public StorageBackend
|
||||||
sqlite3_stmt *m_getBuddiesSettings;
|
sqlite3_stmt *m_getBuddiesSettings;
|
||||||
sqlite3_stmt *m_setUserOnline;
|
sqlite3_stmt *m_setUserOnline;
|
||||||
sqlite3_stmt *m_getOnlineUsers;
|
sqlite3_stmt *m_getOnlineUsers;
|
||||||
|
sqlite3_stmt *m_getUsers;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,8 @@ class StorageBackend
|
||||||
/// getOnlineUsers
|
/// getOnlineUsers
|
||||||
virtual bool getOnlineUsers(std::vector<std::string> &users) = 0;
|
virtual bool getOnlineUsers(std::vector<std::string> &users) = 0;
|
||||||
|
|
||||||
|
virtual bool getUsers(std::vector<std::string> &users) = 0;
|
||||||
|
|
||||||
virtual long addBuddy(long userId, const BuddyInfo &buddyInfo) = 0;
|
virtual long addBuddy(long userId, const BuddyInfo &buddyInfo) = 0;
|
||||||
virtual void updateBuddy(long userId, const BuddyInfo &buddyInfo) = 0;
|
virtual void updateBuddy(long userId, const BuddyInfo &buddyInfo) = 0;
|
||||||
virtual void removeBuddy(long id) = 0;
|
virtual void removeBuddy(long id) = 0;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#ifndef THREAD_POOL
|
#pragma once
|
||||||
#define THREAD_POOL
|
|
||||||
|
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
|
@ -8,6 +7,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Swiften/EventLoop/EventLoop.h"
|
#include "Swiften/EventLoop/EventLoop.h"
|
||||||
|
|
||||||
|
namespace Transport {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Thread serves as a base class for any code that has to be excuted as a thread
|
* Thread serves as a base class for any code that has to be excuted as a thread
|
||||||
|
@ -70,4 +70,4 @@ class ThreadPool
|
||||||
void releaseThread(int i);
|
void releaseThread(int i);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
}
|
||||||
|
|
133
spectrum/src/frontends/slack/SlackAPI.cpp
Normal file
133
spectrum/src/frontends/slack/SlackAPI.cpp
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/**
|
||||||
|
* XMPP - libpurple transport
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SlackAPI.h"
|
||||||
|
#include "SlackFrontend.h"
|
||||||
|
#include "SlackUser.h"
|
||||||
|
#include "SlackRTM.h"
|
||||||
|
|
||||||
|
#include "transport/Transport.h"
|
||||||
|
#include "transport/HTTPRequest.h"
|
||||||
|
#include "transport/Util.h"
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/make_shared.hpp>
|
||||||
|
#include <map>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace Transport {
|
||||||
|
|
||||||
|
DEFINE_LOGGER(logger, "SlackAPI");
|
||||||
|
|
||||||
|
SlackAPI::SlackAPI(Component *component, UserInfo uinfo) : m_uinfo(uinfo) {
|
||||||
|
m_component = component;
|
||||||
|
}
|
||||||
|
|
||||||
|
SlackAPI::~SlackAPI() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlackAPI::handleSendMessage(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data) {
|
||||||
|
LOG4CXX_INFO(logger, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlackAPI::sendMessage(const std::string &from, const std::string &to, const std::string &text) {
|
||||||
|
std::string url = "https://slack.com/api/chat.postMessage?";
|
||||||
|
url += "&username=" + Util::urlencode(from);
|
||||||
|
url += "&channel=" + Util::urlencode(to);
|
||||||
|
url += "&text=" + Util::urlencode(text);
|
||||||
|
url += "&token=" + Util::urlencode(m_uinfo.encoding);
|
||||||
|
|
||||||
|
HTTPRequest *req = new HTTPRequest(THREAD_POOL(m_component), HTTPRequest::Get, url,
|
||||||
|
boost::bind(&SlackAPI::handleSendMessage, this, _1, _2, _3, _4));
|
||||||
|
queueRequest(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SlackAPI::getChannelId(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data) {
|
||||||
|
if (!ok) {
|
||||||
|
LOG4CXX_ERROR(logger, req->getError());
|
||||||
|
LOG4CXX_ERROR(logger, data);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value &channel = resp["channel"];
|
||||||
|
if (!channel.IsObject()) {
|
||||||
|
LOG4CXX_ERROR(logger, "No 'channel' object in the reply.");
|
||||||
|
LOG4CXX_ERROR(logger, data);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value &id = channel["id"];
|
||||||
|
if (!id.IsString()) {
|
||||||
|
LOG4CXX_ERROR(logger, "No 'id' string in the reply.");
|
||||||
|
LOG4CXX_ERROR(logger, data);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return id.GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
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_uinfo.encoding);
|
||||||
|
HTTPRequest *req = new HTTPRequest(THREAD_POOL(m_component), HTTPRequest::Get, url, callback);
|
||||||
|
queueRequest(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SlackAPI::getOwnerId(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data) {
|
||||||
|
if (!ok) {
|
||||||
|
LOG4CXX_ERROR(logger, req->getError());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value &members = resp["members"];
|
||||||
|
if (!members.IsArray()) {
|
||||||
|
LOG4CXX_ERROR(logger, "No 'members' object in the reply.");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < members.Size(); i++) {
|
||||||
|
if (!members[i].IsObject()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value &is_primary_owner = members[i]["is_primary_owner"];
|
||||||
|
if (!is_primary_owner.IsBool()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_primary_owner.GetBool()) {
|
||||||
|
rapidjson::Value &name = members[i]["id"];
|
||||||
|
if (!name.IsString()) {
|
||||||
|
LOG4CXX_ERROR(logger, "No 'name' string in the reply.");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return name.GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlackAPI::usersList(HTTPRequest::Callback callback) {
|
||||||
|
std::string url = "https://slack.com/api/users.list?presence=0&token=" + Util::urlencode(m_uinfo.encoding);
|
||||||
|
HTTPRequest *req = new HTTPRequest(THREAD_POOL(m_component), HTTPRequest::Get, url, callback);
|
||||||
|
queueRequest(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
63
spectrum/src/frontends/slack/SlackAPI.h
Normal file
63
spectrum/src/frontends/slack/SlackAPI.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* Spectrum 2 Slack Frontend
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015, Jan Kaluza <hanzz.k@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "transport/HTTPRequestQueue.h"
|
||||||
|
#include "transport/HTTPRequest.h"
|
||||||
|
#include "transport/StorageBackend.h"
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <boost/signal.hpp>
|
||||||
|
|
||||||
|
namespace Transport {
|
||||||
|
|
||||||
|
class Component;
|
||||||
|
class StorageBackend;
|
||||||
|
class HTTPRequest;
|
||||||
|
class SlackRTM;
|
||||||
|
|
||||||
|
class SlackAPI : public HTTPRequestQueue {
|
||||||
|
public:
|
||||||
|
SlackAPI(Component *component, UserInfo uinfo);
|
||||||
|
|
||||||
|
virtual ~SlackAPI();
|
||||||
|
|
||||||
|
void usersList(HTTPRequest::Callback callback);
|
||||||
|
std::string getOwnerId(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
|
||||||
|
|
||||||
|
void imOpen(const std::string &uid, HTTPRequest::Callback callback);
|
||||||
|
std::string getChannelId(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
|
||||||
|
|
||||||
|
void sendMessage(const std::string &from, const std::string &to, const std::string &text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handleSendMessage(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Component *m_component;
|
||||||
|
UserInfo m_uinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -29,7 +29,7 @@
|
||||||
#include "transport/Logging.h"
|
#include "transport/Logging.h"
|
||||||
#include "transport/Config.h"
|
#include "transport/Config.h"
|
||||||
#include "transport/Transport.h"
|
#include "transport/Transport.h"
|
||||||
#include "transport/OAuth2.h"
|
#include "transport/ThreadPool.h"
|
||||||
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/smart_ptr/make_shared.hpp>
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
@ -53,18 +53,10 @@ void SlackFrontend::init(Component *transport, Swift::EventLoop *loop, Swift::Ne
|
||||||
m_transport = transport;
|
m_transport = transport;
|
||||||
m_config = transport->getConfig();
|
m_config = transport->getConfig();
|
||||||
m_jid = Swift::JID(CONFIG_STRING(m_config, "service.jid"));
|
m_jid = Swift::JID(CONFIG_STRING(m_config, "service.jid"));
|
||||||
|
m_tp = new ThreadPool(loop, 10);
|
||||||
std::string redirect_url = "http://spectrum.im/slackoauth2/" + CONFIG_STRING(m_config, "service.jid");
|
|
||||||
m_oauth2 = new OAuth2(CONFIG_STRING_DEFAULTED(m_config, "service.client_id",""),
|
|
||||||
CONFIG_STRING_DEFAULTED(m_config, "service.client_secret",""),
|
|
||||||
"https://slack.com/oauth/authorize",
|
|
||||||
"https://slack.com/api/oauth.access",
|
|
||||||
redirect_url,
|
|
||||||
"channels:read channels:write team:read");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SlackFrontend::~SlackFrontend() {
|
SlackFrontend::~SlackFrontend() {
|
||||||
delete m_oauth2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SlackFrontend::clearRoomList() {
|
void SlackFrontend::clearRoomList() {
|
||||||
|
@ -97,7 +89,7 @@ boost::shared_ptr<Swift::DiscoInfo> SlackFrontend::sendCapabilitiesRequest(Swift
|
||||||
}
|
}
|
||||||
|
|
||||||
void SlackFrontend::reconnectUser(const std::string &user) {
|
void SlackFrontend::reconnectUser(const std::string &user) {
|
||||||
|
return static_cast<SlackUserManager *>(m_userManager)->reconnectUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
RosterManager *SlackFrontend::createRosterManager(User *user, Component *component) {
|
RosterManager *SlackFrontend::createRosterManager(User *user, Component *component) {
|
||||||
|
@ -109,20 +101,22 @@ User *SlackFrontend::createUser(const Swift::JID &jid, UserInfo &userInfo, Compo
|
||||||
}
|
}
|
||||||
|
|
||||||
UserManager *SlackFrontend::createUserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend) {
|
UserManager *SlackFrontend::createUserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend) {
|
||||||
return new SlackUserManager(component, userRegistry, storageBackend);
|
m_userManager = new SlackUserManager(component, userRegistry, storageBackend);
|
||||||
|
return m_userManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SlackFrontend::connectToServer() {
|
void SlackFrontend::connectToServer() {
|
||||||
LOG4CXX_INFO(logger, "Connecting to Slack API server");
|
LOG4CXX_INFO(logger, "Started.");
|
||||||
|
m_transport->handleConnected();
|
||||||
std::string url = m_oauth2->generateAuthURL();
|
|
||||||
LOG4CXX_INFO(logger, url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SlackFrontend::setOAuth2Code(const std::string &code, const std::string &state) {
|
std::string SlackFrontend::setOAuth2Code(const std::string &code, const std::string &state) {
|
||||||
LOG4CXX_INFO(logger, "Using OAuth2 code " << code << " to get the authorization token");
|
return static_cast<SlackUserManager *>(m_userManager)->handleOAuth2Code(code, state);
|
||||||
return m_oauth2->handleOAuth2Code(code, state);
|
}
|
||||||
|
|
||||||
|
std::string SlackFrontend::getOAuth2URL(const std::vector<std::string> &args) {
|
||||||
|
return static_cast<SlackUserManager *>(m_userManager)->getOAuth2URL(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SlackFrontend::disconnectFromServer() {
|
void SlackFrontend::disconnectFromServer() {
|
||||||
|
|
|
@ -25,13 +25,15 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
#define THREAD_POOL(X) static_cast<SlackFrontend *>(X->getFrontend())->getThreadPool()
|
||||||
|
|
||||||
namespace Transport {
|
namespace Transport {
|
||||||
class UserRegistry;
|
class UserRegistry;
|
||||||
class Frontend;
|
class Frontend;
|
||||||
class Config;
|
class Config;
|
||||||
class DiscoItemsResponder;
|
class DiscoItemsResponder;
|
||||||
class VCardResponder;
|
class VCardResponder;
|
||||||
class OAuth2;
|
class ThreadPool;
|
||||||
|
|
||||||
class SlackFrontend : public Frontend {
|
class SlackFrontend : public Frontend {
|
||||||
public:
|
public:
|
||||||
|
@ -64,13 +66,19 @@ namespace Transport {
|
||||||
virtual void clearRoomList();
|
virtual void clearRoomList();
|
||||||
virtual void addRoomToRoomList(const std::string &handle, const std::string &name);
|
virtual void addRoomToRoomList(const std::string &handle, const std::string &name);
|
||||||
virtual std::string setOAuth2Code(const std::string &code, const std::string &state);
|
virtual std::string setOAuth2Code(const std::string &code, const std::string &state);
|
||||||
|
virtual std::string getOAuth2URL(const std::vector<std::string> &args);
|
||||||
|
|
||||||
void handleMessage(boost::shared_ptr<Swift::Message> message);
|
void handleMessage(boost::shared_ptr<Swift::Message> message);
|
||||||
|
|
||||||
|
ThreadPool *getThreadPool() {
|
||||||
|
return m_tp;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Config* m_config;
|
Config* m_config;
|
||||||
Swift::JID m_jid;
|
Swift::JID m_jid;
|
||||||
Component *m_transport;
|
Component *m_transport;
|
||||||
OAuth2 *m_oauth2;
|
UserManager *m_userManager;
|
||||||
|
ThreadPool *m_tp;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
80
spectrum/src/frontends/slack/SlackInstallation.cpp
Normal file
80
spectrum/src/frontends/slack/SlackInstallation.cpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/**
|
||||||
|
* XMPP - libpurple transport
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SlackInstallation.h"
|
||||||
|
#include "SlackFrontend.h"
|
||||||
|
#include "SlackUser.h"
|
||||||
|
#include "SlackRTM.h"
|
||||||
|
#include "SlackAPI.h"
|
||||||
|
|
||||||
|
#include "transport/Transport.h"
|
||||||
|
#include "transport/HTTPRequest.h"
|
||||||
|
#include "transport/Util.h"
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/make_shared.hpp>
|
||||||
|
#include <map>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace Transport {
|
||||||
|
|
||||||
|
DEFINE_LOGGER(logger, "SlackInstallation");
|
||||||
|
|
||||||
|
SlackInstallation::SlackInstallation(Component *component, StorageBackend *storageBackend, UserInfo uinfo) : m_uinfo(uinfo) {
|
||||||
|
m_component = component;
|
||||||
|
m_storageBackend = storageBackend;
|
||||||
|
m_api = new SlackAPI(component, uinfo);
|
||||||
|
|
||||||
|
|
||||||
|
m_api->usersList(boost::bind(&SlackInstallation::handleUsersList, this, _1, _2, _3, _4));
|
||||||
|
// m_rtm = new SlackRTM(component, storageBackend, uinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
SlackInstallation::~SlackInstallation() {
|
||||||
|
// delete m_rtm;
|
||||||
|
delete m_api;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlackInstallation::handleImOpen(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data) {
|
||||||
|
std::string channel = m_api->getChannelId(req, ok, resp, data);
|
||||||
|
LOG4CXX_INFO(logger, "Opened channel with team owner: " << channel);
|
||||||
|
|
||||||
|
std::string msg;
|
||||||
|
msg = "Hi, It seems you have authorized Spectrum 2 transport for your team. "
|
||||||
|
"As a team owner, you should now configure it. You should provide username and "
|
||||||
|
"password you want to use to connect your team to legacy network of your choice.";
|
||||||
|
m_api->sendMessage("Spectrum 2", channel, msg);
|
||||||
|
|
||||||
|
msg = "You can do it by typing \".spectrum2 register <username> <password>\". Password may be optional.";
|
||||||
|
m_api->sendMessage("Spectrum 2", channel, msg);
|
||||||
|
|
||||||
|
msg = "For example to connect the Freenode IRC network, just type \".spectrum2 register irc.freenode.net\".";
|
||||||
|
m_api->sendMessage("Spectrum 2", channel, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlackInstallation::handleUsersList(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data) {
|
||||||
|
std::string ownerId = m_api->getOwnerId(req, ok, resp, data);
|
||||||
|
LOG4CXX_INFO(logger, "Team owner ID is " << ownerId);
|
||||||
|
|
||||||
|
m_api->imOpen(ownerId, boost::bind(&SlackInstallation::handleImOpen, this, _1, _2, _3, _4));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
61
spectrum/src/frontends/slack/SlackInstallation.h
Normal file
61
spectrum/src/frontends/slack/SlackInstallation.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/**
|
||||||
|
* Spectrum 2 Slack Frontend
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015, Jan Kaluza <hanzz.k@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "transport/StorageBackend.h"
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <boost/signal.hpp>
|
||||||
|
|
||||||
|
namespace Transport {
|
||||||
|
|
||||||
|
class Component;
|
||||||
|
class StorageBackend;
|
||||||
|
class HTTPRequest;
|
||||||
|
class SlackRTM;
|
||||||
|
class SlackAPI;
|
||||||
|
|
||||||
|
class SlackInstallation {
|
||||||
|
public:
|
||||||
|
SlackInstallation(Component *component, StorageBackend *storageBackend, UserInfo uinfo);
|
||||||
|
|
||||||
|
virtual ~SlackInstallation();
|
||||||
|
|
||||||
|
boost::signal<void (const std::string &user)> onInstallationDone;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handleUsersList(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
|
||||||
|
void handleImOpen(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Component *m_component;
|
||||||
|
StorageBackend *m_storageBackend;
|
||||||
|
UserInfo m_uinfo;
|
||||||
|
std::string m_ownerName;
|
||||||
|
SlackRTM *m_rtm;
|
||||||
|
SlackAPI *m_api;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
120
spectrum/src/frontends/slack/SlackRTM.cpp
Normal file
120
spectrum/src/frontends/slack/SlackRTM.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
/**
|
||||||
|
* XMPP - libpurple transport
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SlackRTM.h"
|
||||||
|
#include "SlackFrontend.h"
|
||||||
|
#include "SlackUser.h"
|
||||||
|
|
||||||
|
#include "transport/Transport.h"
|
||||||
|
#include "transport/HTTPRequest.h"
|
||||||
|
#include "transport/Util.h"
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/make_shared.hpp>
|
||||||
|
#include <map>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace Transport {
|
||||||
|
|
||||||
|
DEFINE_LOGGER(logger, "SlackRTM");
|
||||||
|
|
||||||
|
SlackRTM::SlackRTM(Component *component, StorageBackend *storageBackend, UserInfo uinfo) : m_uinfo(uinfo) {
|
||||||
|
m_component = component;
|
||||||
|
m_storageBackend = storageBackend;
|
||||||
|
|
||||||
|
Swift::TLSOptions o;
|
||||||
|
Swift::PlatformTLSFactories *m_tlsFactory = new Swift::PlatformTLSFactories();
|
||||||
|
m_tlsConnectionFactory = new Swift::TLSConnectionFactory(m_tlsFactory->getTLSContextFactory(), component->getNetworkFactories()->getConnectionFactory(), o);
|
||||||
|
|
||||||
|
|
||||||
|
std::string url = "https://slack.com/api/rtm.start?";
|
||||||
|
url += "token=" + Util::urlencode(m_uinfo.encoding);
|
||||||
|
|
||||||
|
// HTTPRequest *req = new HTTPRequest();
|
||||||
|
// req->GET(THREAD_POOL(m_component), url,
|
||||||
|
// boost::bind(&SlackRTM::handleRTMStart, this, _1, _2, _3, _4));
|
||||||
|
}
|
||||||
|
|
||||||
|
SlackRTM::~SlackRTM() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlackRTM::handleRTMStart(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data) {
|
||||||
|
if (!ok) {
|
||||||
|
LOG4CXX_ERROR(logger, req->getError());
|
||||||
|
LOG4CXX_ERROR(logger, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value &url = resp["url"];
|
||||||
|
if (!url.IsString()) {
|
||||||
|
LOG4CXX_ERROR(logger, "No 'url' object in the reply.");
|
||||||
|
LOG4CXX_ERROR(logger, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string u = url.GetString();
|
||||||
|
LOG4CXX_INFO(logger, "Started RTM, WebSocket URL is " << u);
|
||||||
|
|
||||||
|
u = u.substr(6);
|
||||||
|
m_host = u.substr(0, u.find("/"));
|
||||||
|
m_path = u.substr(u.find("/"));
|
||||||
|
|
||||||
|
LOG4CXX_INFO(logger, "Starting DNS query for " << m_host << " " << m_path);
|
||||||
|
m_dnsQuery = m_component->getNetworkFactories()->getDomainNameResolver()->createAddressQuery(m_host);
|
||||||
|
m_dnsQuery->onResult.connect(boost::bind(&SlackRTM::handleDNSResult, this, _1, _2));
|
||||||
|
m_dnsQuery->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlackRTM::handleDataRead(boost::shared_ptr<Swift::SafeByteArray> data) {
|
||||||
|
LOG4CXX_INFO(logger, "data read");
|
||||||
|
std::string d = Swift::safeByteArrayToString(*data);
|
||||||
|
LOG4CXX_INFO(logger, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlackRTM::handleConnected(bool error) {
|
||||||
|
if (error) {
|
||||||
|
LOG4CXX_ERROR(logger, "Connection to " << m_host << " failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG4CXX_INFO(logger, "Connected to " << m_host);
|
||||||
|
|
||||||
|
std::string req = "";
|
||||||
|
req += "GET " + m_path + " HTTP/1.1\r\n";
|
||||||
|
req += "Host: " + m_host + ":443\r\n";
|
||||||
|
req += "Upgrade: websocket\r\n";
|
||||||
|
req += "Connection: Upgrade\r\n";
|
||||||
|
req += "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n";
|
||||||
|
req += "Sec-WebSocket-Version: 13\r\n";
|
||||||
|
req += "\r\n";
|
||||||
|
|
||||||
|
m_conn->write(Swift::createSafeByteArray(req));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlackRTM::handleDNSResult(const std::vector<Swift::HostAddress> &addrs, boost::optional<Swift::DomainNameResolveError>) {
|
||||||
|
m_conn = m_tlsConnectionFactory->createConnection();
|
||||||
|
m_conn->onDataRead.connect(boost::bind(&SlackRTM::handleDataRead, this, _1));
|
||||||
|
m_conn->onConnectFinished.connect(boost::bind(&SlackRTM::handleConnected, this, _1));
|
||||||
|
m_conn->connect(Swift::HostAddressPort(addrs[0], 443));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
71
spectrum/src/frontends/slack/SlackRTM.h
Normal file
71
spectrum/src/frontends/slack/SlackRTM.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* Spectrum 2 Slack Frontend
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015, Jan Kaluza <hanzz.k@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "transport/StorageBackend.h"
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
|
||||||
|
#include <Swiften/Network/TLSConnectionFactory.h>
|
||||||
|
#include <Swiften/Network/HostAddressPort.h>
|
||||||
|
#include <Swiften/TLS/PlatformTLSFactories.h>
|
||||||
|
#include <Swiften/TLS/TLSOptions.h>
|
||||||
|
#include <Swiften/Network/DomainNameResolveError.h>
|
||||||
|
#include <Swiften/Network/DomainNameAddressQuery.h>
|
||||||
|
#include <Swiften/Network/DomainNameResolver.h>
|
||||||
|
#include <Swiften/Network/HostAddress.h>
|
||||||
|
#include <Swiften/Base/SafeByteArray.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <boost/signal.hpp>
|
||||||
|
|
||||||
|
namespace Transport {
|
||||||
|
|
||||||
|
class Component;
|
||||||
|
class StorageBackend;
|
||||||
|
class HTTPRequest;
|
||||||
|
|
||||||
|
class SlackRTM {
|
||||||
|
public:
|
||||||
|
SlackRTM(Component *component, StorageBackend *storageBackend, UserInfo uinfo);
|
||||||
|
|
||||||
|
virtual ~SlackRTM();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handleDNSResult(const std::vector<Swift::HostAddress>&, boost::optional<Swift::DomainNameResolveError>);
|
||||||
|
void handleDataRead(boost::shared_ptr<Swift::SafeByteArray> data);
|
||||||
|
void handleConnected(bool error);
|
||||||
|
void handleRTMStart(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Component *m_component;
|
||||||
|
StorageBackend *m_storageBackend;
|
||||||
|
UserInfo m_uinfo;
|
||||||
|
boost::shared_ptr<Swift::DomainNameAddressQuery> m_dnsQuery;
|
||||||
|
boost::shared_ptr<Swift::Connection> m_conn;
|
||||||
|
Swift::TLSConnectionFactory *m_tlsConnectionFactory;
|
||||||
|
std::string m_host;
|
||||||
|
std::string m_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -21,6 +21,7 @@
|
||||||
#include "SlackUserManager.h"
|
#include "SlackUserManager.h"
|
||||||
#include "SlackUserRegistration.h"
|
#include "SlackUserRegistration.h"
|
||||||
#include "SlackFrontend.h"
|
#include "SlackFrontend.h"
|
||||||
|
#include "SlackInstallation.h"
|
||||||
|
|
||||||
#include "transport/User.h"
|
#include "transport/User.h"
|
||||||
#include "transport/Transport.h"
|
#include "transport/Transport.h"
|
||||||
|
@ -33,6 +34,7 @@ DEFINE_LOGGER(logger, "SlackUserManager");
|
||||||
|
|
||||||
SlackUserManager::SlackUserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend) : UserManager(component, userRegistry, storageBackend) {
|
SlackUserManager::SlackUserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend) : UserManager(component, userRegistry, storageBackend) {
|
||||||
m_component = component;
|
m_component = component;
|
||||||
|
m_storageBackend = storageBackend;
|
||||||
m_userRegistration = new SlackUserRegistration(component, this, storageBackend);
|
m_userRegistration = new SlackUserRegistration(component, this, storageBackend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +42,30 @@ SlackUserManager::~SlackUserManager() {
|
||||||
delete m_userRegistration;
|
delete m_userRegistration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SlackUserManager::reconnectUser(const std::string &user) {
|
||||||
|
UserInfo uinfo;
|
||||||
|
if (!m_storageBackend->getUser(user, uinfo)) {
|
||||||
|
LOG4CXX_ERROR(logger, "User " << user << " tried to reconnect, but he's not registered.");
|
||||||
|
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 {
|
||||||
|
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::sendVCard(unsigned int id, Swift::VCard::ref vcard) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -49,4 +75,13 @@ UserRegistration *SlackUserManager::getUserRegistration() {
|
||||||
return m_userRegistration;
|
return m_userRegistration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string SlackUserManager::handleOAuth2Code(const std::string &code, const std::string &state) {
|
||||||
|
return static_cast<SlackUserRegistration *>(m_userRegistration)->handleOAuth2Code(code, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SlackUserManager::getOAuth2URL(const std::vector<std::string> &args) {
|
||||||
|
return static_cast<SlackUserRegistration *>(m_userRegistration)->createOAuth2URL(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ class XMPPUserRegistration;
|
||||||
class GatewayResponder;
|
class GatewayResponder;
|
||||||
class AdHocManager;
|
class AdHocManager;
|
||||||
class SettingsAdHocCommandFactory;
|
class SettingsAdHocCommandFactory;
|
||||||
|
class SlackInstallation;
|
||||||
|
|
||||||
class SlackUserManager : public UserManager {
|
class SlackUserManager : public UserManager {
|
||||||
public:
|
public:
|
||||||
|
@ -46,13 +47,21 @@ class SlackUserManager : public UserManager {
|
||||||
|
|
||||||
virtual ~SlackUserManager();
|
virtual ~SlackUserManager();
|
||||||
|
|
||||||
|
void reconnectUser(const std::string &user);
|
||||||
|
|
||||||
virtual void sendVCard(unsigned int id, Swift::VCard::ref vcard);
|
virtual void sendVCard(unsigned int id, Swift::VCard::ref vcard);
|
||||||
|
|
||||||
UserRegistration *getUserRegistration();
|
UserRegistration *getUserRegistration();
|
||||||
|
|
||||||
|
std::string handleOAuth2Code(const std::string &code, const std::string &state);
|
||||||
|
|
||||||
|
std::string getOAuth2URL(const std::vector<std::string> &args);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Component *m_component;
|
Component *m_component;
|
||||||
UserRegistration *m_userRegistration;
|
UserRegistration *m_userRegistration;
|
||||||
|
StorageBackend *m_storageBackend;
|
||||||
|
std::map<std::string, SlackInstallation *> m_installations;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,11 @@
|
||||||
#include "transport/Logging.h"
|
#include "transport/Logging.h"
|
||||||
#include "transport/Buddy.h"
|
#include "transport/Buddy.h"
|
||||||
#include "transport/Config.h"
|
#include "transport/Config.h"
|
||||||
|
#include "transport/OAuth2.h"
|
||||||
|
#include "transport/Util.h"
|
||||||
|
#include "transport/HTTPRequest.h"
|
||||||
|
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
@ -49,9 +54,97 @@ SlackUserRegistration::SlackUserRegistration(Component *component, UserManager *
|
||||||
m_config = m_component->getConfig();
|
m_config = m_component->getConfig();
|
||||||
m_storageBackend = storageBackend;
|
m_storageBackend = storageBackend;
|
||||||
m_userManager = userManager;
|
m_userManager = userManager;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SlackUserRegistration::~SlackUserRegistration(){
|
SlackUserRegistration::~SlackUserRegistration(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SlackUserRegistration::createOAuth2URL(const std::vector<std::string> &args) {
|
||||||
|
std::string redirect_url = "http://slack.spectrum.im/auth/" + CONFIG_STRING(m_config, "service.jid");
|
||||||
|
OAuth2 *oauth2 = new OAuth2(CONFIG_STRING_DEFAULTED(m_config, "service.client_id",""),
|
||||||
|
CONFIG_STRING_DEFAULTED(m_config, "service.client_secret",""),
|
||||||
|
"https://slack.com/oauth/authorize",
|
||||||
|
"https://slack.com/api/oauth.access",
|
||||||
|
redirect_url,
|
||||||
|
"channels:read channels:write team:read im:read im:write chat:write:bot");
|
||||||
|
std::string url = oauth2->generateAuthURL();
|
||||||
|
|
||||||
|
m_auths[oauth2->getState()] = oauth2;
|
||||||
|
m_authsData[oauth2->getState()] = args;
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SlackUserRegistration::getTeamDomain(const std::string &token) {
|
||||||
|
std::string url = "https://slack.com/api/team.info?token=" + Util::urlencode(token);
|
||||||
|
|
||||||
|
rapidjson::Document resp;
|
||||||
|
HTTPRequest req(HTTPRequest::Get, url);
|
||||||
|
if (!req.execute(resp)) {
|
||||||
|
LOG4CXX_ERROR(logger, req.getError());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value &team = resp["team"];
|
||||||
|
if (!team.IsObject()) {
|
||||||
|
LOG4CXX_ERROR(logger, "No 'team' object in the reply.");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value &domain = team["domain"];
|
||||||
|
if (!domain.IsString()) {
|
||||||
|
LOG4CXX_ERROR(logger, "No 'domain' string in the reply.");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SlackUserRegistration::handleOAuth2Code(const std::string &code, const std::string &state) {
|
||||||
|
OAuth2 *oauth2 = NULL;
|
||||||
|
std::vector<std::string> data;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserInfo user;
|
||||||
|
user.jid = getTeamDomain(token);
|
||||||
|
user.uin = "";
|
||||||
|
user.password = "";
|
||||||
|
user.language = "en";
|
||||||
|
user.encoding = token; // Use encoding as a token handler... it's BAD, but easy...
|
||||||
|
user.vip = 0;
|
||||||
|
user.id = 0;
|
||||||
|
registerUser(user);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
LOG4CXX_INFO(logger, "Registered Slack user " << user.jid);
|
||||||
|
|
||||||
|
m_auths.erase(state);
|
||||||
|
delete oauth2;
|
||||||
|
|
||||||
|
m_authsData.erase(state);
|
||||||
|
|
||||||
|
m_component->getFrontend()->reconnectUser(user.jid);
|
||||||
|
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SlackUserRegistration::doUserRegistration(const UserInfo &row) {
|
bool SlackUserRegistration::doUserRegistration(const UserInfo &row) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ class Component;
|
||||||
class StorageBackend;
|
class StorageBackend;
|
||||||
class UserManager;
|
class UserManager;
|
||||||
class Config;
|
class Config;
|
||||||
|
class OAuth2;
|
||||||
|
|
||||||
class SlackUserRegistration : public UserRegistration {
|
class SlackUserRegistration : public UserRegistration {
|
||||||
public:
|
public:
|
||||||
|
@ -38,6 +39,12 @@ class SlackUserRegistration : public UserRegistration {
|
||||||
|
|
||||||
~SlackUserRegistration();
|
~SlackUserRegistration();
|
||||||
|
|
||||||
|
std::string createOAuth2URL(const std::vector<std::string> &args);
|
||||||
|
|
||||||
|
std::string getTeamDomain(const std::string &token);
|
||||||
|
|
||||||
|
std::string handleOAuth2Code(const std::string &code, const std::string &state);
|
||||||
|
|
||||||
virtual bool doUserRegistration(const UserInfo &userInfo);
|
virtual bool doUserRegistration(const UserInfo &userInfo);
|
||||||
|
|
||||||
virtual bool doUserUnregistration(const UserInfo &userInfo);
|
virtual bool doUserUnregistration(const UserInfo &userInfo);
|
||||||
|
@ -47,6 +54,8 @@ class SlackUserRegistration : public UserRegistration {
|
||||||
StorageBackend *m_storageBackend;
|
StorageBackend *m_storageBackend;
|
||||||
UserManager *m_userManager;
|
UserManager *m_userManager;
|
||||||
Config *m_config;
|
Config *m_config;
|
||||||
|
std::map<std::string, OAuth2 *> m_auths;
|
||||||
|
std::map<std::string, std::vector<std::string> > m_authsData;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -313,6 +313,18 @@ void AdminInterface::handleQuery(Swift::Message::ref message) {
|
||||||
message->setBody("Bad argument count. See 'help'.");
|
message->setBody("Bad argument count. See 'help'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (message->getBody().find("get_oauth2_url ") == 0) {
|
||||||
|
std::string body = message->getBody();
|
||||||
|
std::vector<std::string> args;
|
||||||
|
boost::split(args, body, boost::is_any_of(" "));
|
||||||
|
if (args.size() == 3) {
|
||||||
|
std::string url = m_component->getFrontend()->getOAuth2URL(args);
|
||||||
|
message->setBody(url);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message->setBody("Bad argument count. See 'help'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (message->getBody().find("help") == 0) {
|
else if (message->getBody().find("help") == 0) {
|
||||||
std::string help;
|
std::string help;
|
||||||
help += "General:\n";
|
help += "General:\n";
|
||||||
|
|
|
@ -103,6 +103,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
|
||||||
("service.jid_escaping", value<bool>()->default_value(true), "")
|
("service.jid_escaping", value<bool>()->default_value(true), "")
|
||||||
("service.vip_only", value<bool>()->default_value(false), "")
|
("service.vip_only", value<bool>()->default_value(false), "")
|
||||||
("service.vip_message", value<std::string>()->default_value(""), "")
|
("service.vip_message", value<std::string>()->default_value(""), "")
|
||||||
|
("service.reconnect_all_users", value<bool>()->default_value(false), "")
|
||||||
("vhosts.vhost", value<std::vector<std::string> >()->multitoken(), "")
|
("vhosts.vhost", value<std::vector<std::string> >()->multitoken(), "")
|
||||||
("identity.name", value<std::string>()->default_value("Spectrum 2 Transport"), "Name showed in service discovery.")
|
("identity.name", value<std::string>()->default_value("Spectrum 2 Transport"), "Name showed in service discovery.")
|
||||||
("identity.category", value<std::string>()->default_value("gateway"), "Disco#info identity category. 'gateway' by default.")
|
("identity.category", value<std::string>()->default_value("gateway"), "Disco#info identity category. 'gateway' by default.")
|
||||||
|
|
|
@ -4,7 +4,20 @@ namespace Transport {
|
||||||
|
|
||||||
DEFINE_LOGGER(logger, "HTTPRequest")
|
DEFINE_LOGGER(logger, "HTTPRequest")
|
||||||
|
|
||||||
HTTPRequest::HTTPRequest() : curlhandle(NULL) {
|
HTTPRequest::HTTPRequest(ThreadPool *tp, Type type, const std::string &url, Callback callback) {
|
||||||
|
m_type = type;
|
||||||
|
m_url = url;
|
||||||
|
m_tp = tp;
|
||||||
|
m_callback = callback;
|
||||||
|
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTPRequest::HTTPRequest(Type type, const std::string &url) {
|
||||||
|
m_type = type;
|
||||||
|
m_url = url;
|
||||||
|
m_tp = NULL;
|
||||||
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +73,7 @@ bool HTTPRequest::GET(std::string url, std::string &data) {
|
||||||
|
|
||||||
/* Set http request and url */
|
/* Set http request and url */
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_HTTPGET, 1);
|
curl_easy_setopt(curlhandle, CURLOPT_HTTPGET, 1);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1);
|
curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 0);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_URL, url.c_str());
|
curl_easy_setopt(curlhandle, CURLOPT_URL, url.c_str());
|
||||||
|
|
||||||
/* Send http request and return status*/
|
/* Send http request and return status*/
|
||||||
|
@ -76,18 +89,50 @@ bool HTTPRequest::GET(std::string url, std::string &data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPRequest::GET(std::string url, rapidjson::Document &json) {
|
bool HTTPRequest::GET(std::string url, rapidjson::Document &json) {
|
||||||
std::string data;
|
if (!GET(url, m_data)) {
|
||||||
if (!GET(url, data)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(json.Parse<0>(data.c_str()).HasParseError()) {
|
if(json.Parse<0>(m_data.c_str()).HasParseError()) {
|
||||||
LOG4CXX_ERROR(logger, "Error while parsing JSON")
|
LOG4CXX_ERROR(logger, "Error while parsing JSON");
|
||||||
LOG4CXX_ERROR(logger, data)
|
LOG4CXX_ERROR(logger, m_data);
|
||||||
|
strcpy(curl_errorbuffer, "Error while parsing JSON");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTTPRequest::run() {
|
||||||
|
switch (m_type) {
|
||||||
|
case Get:
|
||||||
|
m_ok = GET(m_url, m_json);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPRequest::finalize() {
|
||||||
|
m_callback(this, m_ok, m_json, m_data);
|
||||||
|
onRequestFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HTTPRequest::execute() {
|
||||||
|
if (!m_tp) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_tp->runAsThread(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HTTPRequest::execute(rapidjson::Document &json) {
|
||||||
|
switch (m_type) {
|
||||||
|
case Get:
|
||||||
|
m_ok = GET(m_url, json);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_ok;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
42
src/HTTPRequestQueue.cpp
Normal file
42
src/HTTPRequestQueue.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "transport/HTTPRequestQueue.h"
|
||||||
|
#include "transport/HTTPRequest.h"
|
||||||
|
|
||||||
|
namespace Transport {
|
||||||
|
|
||||||
|
DEFINE_LOGGER(logger, "HTTPRequestQueue")
|
||||||
|
|
||||||
|
HTTPRequestQueue::HTTPRequestQueue(int delay) {
|
||||||
|
m_delay = delay;
|
||||||
|
m_processing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTPRequestQueue::~HTTPRequestQueue() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPRequestQueue::sendNextRequest() {
|
||||||
|
if (m_queue.empty()) {
|
||||||
|
m_processing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_processing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTPRequest *req = m_queue.front();
|
||||||
|
m_queue.pop();
|
||||||
|
req->onRequestFinished.connect(boost::bind(&HTTPRequestQueue::sendNextRequest, this));
|
||||||
|
req->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPRequestQueue::queueRequest(HTTPRequest *req) {
|
||||||
|
m_queue.push(req);
|
||||||
|
|
||||||
|
if (!m_processing) {
|
||||||
|
sendNextRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -301,6 +301,7 @@ void MySQLBackend::disconnect() {
|
||||||
delete m_getBuddySetting;
|
delete m_getBuddySetting;
|
||||||
delete m_setUserOnline;
|
delete m_setUserOnline;
|
||||||
delete m_getOnlineUsers;
|
delete m_getOnlineUsers;
|
||||||
|
delete m_getUsers;
|
||||||
mysql_close(&m_conn);
|
mysql_close(&m_conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,6 +349,7 @@ bool MySQLBackend::connect() {
|
||||||
|
|
||||||
m_setUserOnline = new Statement(&m_conn, "bi", "UPDATE " + m_prefix + "users SET online=?, last_login=NOW() WHERE id=?");
|
m_setUserOnline = new Statement(&m_conn, "bi", "UPDATE " + m_prefix + "users SET online=?, last_login=NOW() WHERE id=?");
|
||||||
m_getOnlineUsers = new Statement(&m_conn, "|s", "SELECT jid FROM " + m_prefix + "users WHERE online=1");
|
m_getOnlineUsers = new Statement(&m_conn, "|s", "SELECT jid FROM " + m_prefix + "users WHERE online=1");
|
||||||
|
m_getUsers = new Statement(&m_conn, "|s", "SELECT jid FROM " + m_prefix + "users");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -482,6 +484,20 @@ bool MySQLBackend::getOnlineUsers(std::vector<std::string> &users) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MySQLBackend::getUsers(std::vector<std::string> &users) {
|
||||||
|
EXEC(m_getUsers, getUsers(users));
|
||||||
|
if (!exec_ok)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string jid;
|
||||||
|
while (m_getUsers->fetch() == 0) {
|
||||||
|
*m_getUsers >> jid;
|
||||||
|
users.push_back(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
|
long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
|
||||||
// "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)"
|
// "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)"
|
||||||
std::string groups = StorageBackend::serializeGroups(buddyInfo.groups);
|
std::string groups = StorageBackend::serializeGroups(buddyInfo.groups);
|
||||||
|
|
|
@ -71,12 +71,7 @@ std::string OAuth2::generateAuthURL() {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string OAuth2::handleOAuth2Code(const std::string &code, const std::string &state) {
|
std::string OAuth2::requestToken(const std::string &code, std::string &token) {
|
||||||
if (m_state != state) {
|
|
||||||
std::string error = "Received state code '" + state + "' does not sent state code '" + m_state + "'";
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string url = m_tokenURL + "?";
|
std::string url = m_tokenURL + "?";
|
||||||
url += "client_id=" + Util::urlencode(m_clientId);
|
url += "client_id=" + Util::urlencode(m_clientId);
|
||||||
url += "&client_secret=" + Util::urlencode(m_clientSecret);
|
url += "&client_secret=" + Util::urlencode(m_clientSecret);
|
||||||
|
@ -86,12 +81,18 @@ std::string OAuth2::handleOAuth2Code(const std::string &code, const std::string
|
||||||
url += "&redirect_uri=" + Util::urlencode(m_redirectURL);
|
url += "&redirect_uri=" + Util::urlencode(m_redirectURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string data;
|
rapidjson::Document resp;
|
||||||
HTTPRequest req;
|
HTTPRequest req(HTTPRequest::Get, url);
|
||||||
req.GET(url, data);
|
if (!req.execute(resp)) {
|
||||||
|
return req.getError();
|
||||||
|
}
|
||||||
|
|
||||||
LOG4CXX_INFO(logger, "handleOAuth2Code received token: " << data);
|
rapidjson::Value& access_token = resp["access_token"];
|
||||||
|
if (!access_token.IsString()) {
|
||||||
|
return "No 'access_token' object in the reply.";
|
||||||
|
}
|
||||||
|
|
||||||
|
token = access_token.GetString();
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,6 +245,23 @@ bool PQXXBackend::getOnlineUsers(std::vector<std::string> &users) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PQXXBackend::getUsers(std::vector<std::string> &users) {
|
||||||
|
try {
|
||||||
|
pqxx::nontransaction txn(*m_conn);
|
||||||
|
pqxx::result r = txn.exec("SELECT jid FROM " + m_prefix + "users");
|
||||||
|
|
||||||
|
for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) {
|
||||||
|
users.push_back((*it)[0].as<std::string>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& e) {
|
||||||
|
LOG4CXX_ERROR(logger, e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
|
long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
|
||||||
try {
|
try {
|
||||||
pqxx::nontransaction txn(*m_conn);
|
pqxx::nontransaction txn(*m_conn);
|
||||||
|
|
|
@ -103,6 +103,7 @@ SQLite3Backend::~SQLite3Backend(){
|
||||||
FINALIZE_STMT(m_getBuddySetting);
|
FINALIZE_STMT(m_getBuddySetting);
|
||||||
FINALIZE_STMT(m_setUserOnline);
|
FINALIZE_STMT(m_setUserOnline);
|
||||||
FINALIZE_STMT(m_getOnlineUsers);
|
FINALIZE_STMT(m_getOnlineUsers);
|
||||||
|
FINALIZE_STMT(m_getUsers);
|
||||||
sqlite3_close(m_db);
|
sqlite3_close(m_db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,6 +144,7 @@ bool SQLite3Backend::connect() {
|
||||||
|
|
||||||
PREP_STMT(m_setUserOnline, "UPDATE " + m_prefix + "users SET online=?, last_login=DATETIME('NOW') WHERE id=?");
|
PREP_STMT(m_setUserOnline, "UPDATE " + m_prefix + "users SET online=?, last_login=DATETIME('NOW') WHERE id=?");
|
||||||
PREP_STMT(m_getOnlineUsers, "SELECT jid FROM " + m_prefix + "users WHERE online=1");
|
PREP_STMT(m_getOnlineUsers, "SELECT jid FROM " + m_prefix + "users WHERE online=1");
|
||||||
|
PREP_STMT(m_getUsers, "SELECT jid FROM " + m_prefix + "users");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -283,6 +285,23 @@ bool SQLite3Backend::getOnlineUsers(std::vector<std::string> &users) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SQLite3Backend::getUsers(std::vector<std::string> &users) {
|
||||||
|
sqlite3_reset(m_getUsers);
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
while((ret = sqlite3_step(m_getUsers)) == SQLITE_ROW) {
|
||||||
|
std::string jid = (const char *) sqlite3_column_text(m_getUsers, 0);
|
||||||
|
users.push_back(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != SQLITE_DONE) {
|
||||||
|
LOG4CXX_ERROR(logger, "getUsers query"<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
long SQLite3Backend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
|
long SQLite3Backend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
|
||||||
// "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)"
|
// "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)"
|
||||||
std::string groups = StorageBackend::serializeGroups(buddyInfo.groups);
|
std::string groups = StorageBackend::serializeGroups(buddyInfo.groups);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "transport/ThreadPool.h"
|
#include "transport/ThreadPool.h"
|
||||||
#include "transport/Logging.h"
|
#include "transport/Logging.h"
|
||||||
|
|
||||||
|
namespace Transport {
|
||||||
|
|
||||||
DEFINE_LOGGER(logger, "ThreadPool")
|
DEFINE_LOGGER(logger, "ThreadPool")
|
||||||
boost::signals2::signal< void (Thread*, int) > onWorkCompleted;
|
boost::signals2::signal< void (Thread*, int) > onWorkCompleted;
|
||||||
|
|
||||||
|
@ -123,3 +125,5 @@ void ThreadPool::runAsThread(Thread *t)
|
||||||
requestQueue.push(t);
|
requestQueue.push(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "transport/Transport.h"
|
#include "transport/Transport.h"
|
||||||
#include "transport/Logging.h"
|
#include "transport/Logging.h"
|
||||||
#include "transport/Frontend.h"
|
#include "transport/Frontend.h"
|
||||||
|
#include "transport/Config.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
@ -72,7 +73,12 @@ void UsersReconnecter::handleConnected() {
|
||||||
LOG4CXX_INFO(logger, "Starting UserReconnecter.");
|
LOG4CXX_INFO(logger, "Starting UserReconnecter.");
|
||||||
m_started = true;
|
m_started = true;
|
||||||
|
|
||||||
m_storageBackend->getOnlineUsers(m_users);
|
if (CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "service.reconnect_all_users", false)) {
|
||||||
|
m_storageBackend->getUsers(m_users);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_storageBackend->getOnlineUsers(m_users);
|
||||||
|
}
|
||||||
|
|
||||||
reconnectNextUser();
|
reconnectNextUser();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue