basic sync wrapper

This commit is contained in:
Sorunome 2019-10-17 10:45:55 +02:00
parent 8d6f8fda05
commit 6e604860e6
No known key found for this signature in database
GPG key ID: 63E31F7B5993A9C4
8 changed files with 209 additions and 24 deletions

View file

@ -5,17 +5,34 @@
#include <3ds.h> #include <3ds.h>
#include <jansson.h> #include <jansson.h>
class MatrixClient { namespace Matrix {
class Store {
public:
virtual void setSyncToken(std::string token) = 0;
virtual std::string getSyncToken() = 0;
};
class Client {
private: private:
public:
std::string hsUrl; std::string hsUrl;
std::string token; std::string token;
int requestId; int requestId;
bool stopSyncing;
Store* store;
void startSync();
void processSync(json_t* sync);
json_t* doSync(std::string token);
json_t* doRequest(const char* method, std::string path, json_t* body = NULL);
public: public:
MatrixClient(std::string homeserverUrl, std::string matrixToken); Client(std::string homeserverUrl, std::string matrixToken, Store* clientStore = NULL);
std::string userId();
std::string sendTextMessage(std::string roomId, std::string text); std::string sendTextMessage(std::string roomId, std::string text);
std::string sendMessage(std::string roomId, json_t* content); std::string sendMessage(std::string roomId, json_t* content);
std::string sendEvent(std::string roomId, std::string eventType, json_t* content); std::string sendEvent(std::string roomId, std::string eventType, json_t* content);
json_t* doRequest(const char* method, std::string path, json_t* body = NULL);
}; };
}; // namespace Matrix
#endif // _matrixclient_h_ #endif // _matrixclient_h_

View file

@ -1,6 +0,0 @@
#ifndef _templatelib_h_
#define _templatelib_h_
int myLibFunction();
#endif // _templatelib_h_

View file

@ -6,22 +6,46 @@
#include <malloc.h> #include <malloc.h>
#include <curl/curl.h> #include <curl/curl.h>
#include <string.h> #include <string.h>
#include "util.h"
#include "memorystore.h"
#include <sys/socket.h> #include <sys/socket.h>
#define SOC_ALIGN 0x1000 #define SOC_ALIGN 0x1000
#define SOC_BUFFERSIZE 0x100000 #define SOC_BUFFERSIZE 0x100000
#define SYNC_TIMEOUT 10000
namespace Matrix {
static u32 *SOC_buffer = NULL; static u32 *SOC_buffer = NULL;
MatrixClient::MatrixClient(std::string homeserverUrl, std::string matrixToken) { Client::Client(std::string homeserverUrl, std::string matrixToken, Store* clientStore) {
hsUrl = homeserverUrl; hsUrl = homeserverUrl;
token = matrixToken; token = matrixToken;
requestId = 0; requestId = 0;
stopSyncing = false;
if (!clientStore) {
clientStore = new MemoryStore();
}
store = clientStore;
} }
std::string MatrixClient::sendTextMessage(std::string roomId, std::string text) { std::string Client::userId() {
json_t* ret = doRequest("GET", "/_matrix/client/r0/account/whoami");
if (!ret) {
return "";
}
json_t* userId = json_object_get(ret, "user_id");
if (!userId) {
json_decref(ret);
return "";
}
const char* userIdStr = json_string_value(userId);
json_decref(ret);
return userIdStr;
}
std::string Client::sendTextMessage(std::string roomId, std::string text) {
json_t* request = json_object(); json_t* request = json_object();
json_object_set_new(request, "msgtype", json_string("m.text")); json_object_set_new(request, "msgtype", json_string("m.text"));
json_object_set_new(request, "body", json_string(text.c_str())); json_object_set_new(request, "body", json_string(text.c_str()));
@ -30,13 +54,13 @@ std::string MatrixClient::sendTextMessage(std::string roomId, std::string text)
return eventId; return eventId;
} }
std::string MatrixClient::sendMessage(std::string roomId, json_t* content) { std::string Client::sendMessage(std::string roomId, json_t* content) {
return sendEvent(roomId, "m.room.message", content); return sendEvent(roomId, "m.room.message", content);
} }
std::string MatrixClient::sendEvent(std::string roomId, std::string eventType, json_t* content) { std::string Client::sendEvent(std::string roomId, std::string eventType, json_t* content) {
std::string txid = std::to_string(time(NULL)) + "_REQ_" + std::to_string(requestId); std::string txid = std::to_string(time(NULL)) + "_REQ_" + std::to_string(requestId);
std::string path = "/_matrix/client/r0/rooms/" + roomId + "/send/" + eventType + "/" + txid; std::string path = "/_matrix/client/r0/rooms/" + urlencode(roomId) + "/send/" + urlencode(eventType) + "/" + urlencode(txid);
json_t* ret = doRequest("PUT", path, content); json_t* ret = doRequest("PUT", path, content);
if (!ret) { if (!ret) {
return ""; return "";
@ -52,12 +76,95 @@ std::string MatrixClient::sendEvent(std::string roomId, std::string eventType, j
return eventIdStr; return eventIdStr;
} }
void Client::processSync(json_t* sync) {
json_t* rooms = json_object_get(sync, "rooms");
if (!rooms) {
return; // nothing to do
}
json_t* leftRooms = json_object_get(rooms, "leave");
json_t* invitedRooms = json_object_get(rooms, "invite");
json_t* joinedRooms = json_object_get(rooms, "join");
const char* roomId;
json_t* room;
if (leftRooms) {
json_object_foreach(leftRooms, roomId, room) {
// rooms that we left
}
}
if (invitedRooms) {
json_object_foreach(invitedRooms, roomId, room) {
// rooms that we were invited to
}
}
if (joinedRooms) {
json_object_foreach(joinedRooms, roomId, room) {
// rooms that we are joined
printf(roomId);
printf(":\n");
json_t* timeline = json_object_get(room, "timeline");
if (!timeline) {
printf("no timeline\n");
continue;
}
json_t* events = json_object_get(timeline, "events");
if (!events) {
printf("no events\n");
continue;
}
size_t index;
json_t* event;
json_array_foreach(events, index, event) {
json_t* eventType = json_object_get(event, "type");
printf(json_string_value(eventType));
printf("\n");
}
}
}
}
void Client::startSync() {
std::string token = store->getSyncToken();
if (stopSyncing) {
return;
}
json_t* ret = doSync(token);
if (ret) {
// set the token for the next batch
json_t* token = json_object_get(ret, "next_batch");
if (token) {
printf("Found next batch\n");
store->setSyncToken(json_string_value(token));
} else {
printf("No next batch\n");
store->setSyncToken("");
}
processSync(ret);
json_decref(ret);
}
}
json_t* Client::doSync(std::string token) {
printf("Doing sync with token ");
printf(token.c_str());
printf("\n");
std::string query = "?full_state=false&timeout=" + std::to_string(SYNC_TIMEOUT);
if (token != "") {
query += "&since=" + token;
}
return doRequest("GET", "/_matrix/client/r0/sync" + query);
}
size_t DoRequestWriteCallback(char *contents, size_t size, size_t nmemb, void *userp) { size_t DoRequestWriteCallback(char *contents, size_t size, size_t nmemb, void *userp) {
((std::string*)userp)->append((char*)contents, size * nmemb); ((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb; return size * nmemb;
} }
json_t* MatrixClient::doRequest(const char* method, std::string path, json_t* body) { json_t* Client::doRequest(const char* method, std::string path, json_t* body) {
std::string url = hsUrl + path; std::string url = hsUrl + path;
requestId++; requestId++;
@ -101,6 +208,7 @@ json_t* MatrixClient::doRequest(const char* method, std::string path, json_t* bo
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DoRequestWriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DoRequestWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
// curl_easy_setopt(curl, CURLOPT_STDERR, stdout); // curl_easy_setopt(curl, CURLOPT_STDERR, stdout);
@ -111,8 +219,8 @@ json_t* MatrixClient::doRequest(const char* method, std::string path, json_t* bo
} }
curl_easy_cleanup(curl); curl_easy_cleanup(curl);
printf(readBuffer.c_str()); // printf(readBuffer.c_str());
printf("\n"); // printf("\n");
json_error_t error; json_error_t error;
json_t* content = json_loads(readBuffer.c_str(), 0, &error); json_t* content = json_loads(readBuffer.c_str(), 0, &error);
if (!content) { if (!content) {
@ -121,3 +229,5 @@ json_t* MatrixClient::doRequest(const char* method, std::string path, json_t* bo
} }
return content; return content;
} }
}; // namespace Matrix

18
source/memorystore.cpp Normal file
View file

@ -0,0 +1,18 @@
#include "memorystore.h"
#include <string>
namespace Matrix {
MemoryStore::MemoryStore() {
syncToken = "";
}
void MemoryStore::setSyncToken(std::string token) {
syncToken = token;
}
std::string MemoryStore::getSyncToken() {
return syncToken;
}
}; // namespace Matrix

20
source/memorystore.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef _memorystore_h_
#define _memorystore_h_
#include "../include/matrixclient.h"
#include <string>
namespace Matrix {
class MemoryStore : public Store {
private:
std::string syncToken;
public:
MemoryStore();
void setSyncToken(std::string token);
std::string getSyncToken();
};
}; // namespace Matrix
#endif // _memorystore_h_

View file

@ -1,6 +0,0 @@
int myLibFunction() {
return 42;
}

24
source/util.cpp Normal file
View file

@ -0,0 +1,24 @@
#include "util.h"
#include <string>
#include <sstream>
// from http://www.zedwood.com/article/cpp-urlencode-function
std::string urlencode(std::string s) {
static const char lookup[]= "0123456789abcdef";
std::stringstream e;
for(int i = 0, ix = s.length(); i < ix; i++) {
const char& c = s[i];
if ( (48 <= c && c <= 57) ||//0-9
(65 <= c && c <= 90) ||//abc...xyz
(97 <= c && c <= 122) || //ABC...XYZ
(c=='-' || c=='_' || c=='.' || c=='~')
) {
e << c;
} else {
e << '%';
e << lookup[ (c&0xF0)>>4 ];
e << lookup[ (c&0x0F) ];
}
}
return e.str();
}

8
source/util.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef _UTIL_H_
#define _UTIL_H_
#include <string>
std::string urlencode(std::string str);
#endif // _UTIL_H_