(matrix) Init Matrix protocol
Just the scaffolding of a Matrix protocol using mtxclient: Room-joins and (unencrypted) messages can be received, but everything's read-only as yet. More to come!
This commit is contained in:
parent
2f69f2fa04
commit
604082466e
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
|
@ -0,0 +1,142 @@
|
|||
## Haiku Generic Makefile v2.6 ##
|
||||
|
||||
## Fill in this file to specify the project being created, and the referenced
|
||||
## Makefile-Engine will do all of the hard work for you. This handles any
|
||||
## architecture of Haiku.
|
||||
##
|
||||
## For more information, see:
|
||||
## file:///system/develop/documentation/makefile-engine.html
|
||||
|
||||
# The name of the binary.
|
||||
NAME = chat-o-matic/matrix
|
||||
|
||||
# The type of binary, must be one of:
|
||||
# APP: Application
|
||||
# SHARED: Shared library or add-on
|
||||
# STATIC: Static library archive
|
||||
# DRIVER: Kernel driver
|
||||
TYPE = APP
|
||||
|
||||
# If you plan to use localization, specify the application's MIME signature.
|
||||
APP_MIME_SIG = application/x-vnd.chat-o-matic.matrix
|
||||
|
||||
|
||||
# The following lines tell Pe and Eddie where the SRCS, RDEFS, and RSRCS are
|
||||
# so that Pe and Eddie can fill them in for you.
|
||||
#%{
|
||||
# @src->@
|
||||
|
||||
# Specify the source files to use. Full paths or paths relative to the
|
||||
# Makefile can be included. All files, regardless of directory, will have
|
||||
# their object files created in the common object directory. Note that this
|
||||
# means this Makefile will not work correctly if two source files with the
|
||||
# same name (source.c or source.cpp) are included from different directories.
|
||||
# Also note that spaces in folder names do not work well with this Makefile.
|
||||
SRCS = \
|
||||
protocols/matrix/MatrixApp.cpp \
|
||||
protocols/matrix/MatrixMain.cpp \
|
||||
protocols/matrix/MatrixProtocol.cpp \
|
||||
|
||||
# Specify the resource definition files to use. Full or relative paths can be
|
||||
# used.
|
||||
RDEFS = \
|
||||
data/icons/protocols/IRC.rdef \
|
||||
protocols/matrix/matrix.rdef \
|
||||
|
||||
# Specify the resource files to use. Full or relative paths can be used.
|
||||
# Both RDEFS and RSRCS can be utilized in the same Makefile.
|
||||
RSRCS =
|
||||
|
||||
# End Pe/Eddie support.
|
||||
# @<-src@
|
||||
#%}
|
||||
|
||||
# Specify libraries to link against.
|
||||
# There are two acceptable forms of library specifications:
|
||||
# - if your library follows the naming pattern of libXXX.so or libXXX.a,
|
||||
# you can simply specify XXX for the library. (e.g. the entry for
|
||||
# "libtracker.so" would be "tracker")
|
||||
#
|
||||
# - for GCC-independent linking of standard C++ libraries, you can use
|
||||
# $(STDCPPLIBS) instead of the raw "stdc++[.r4] [supc++]" library names.
|
||||
#
|
||||
# - if your library does not follow the standard library naming scheme,
|
||||
# you need to specify the path to the library and it's name.
|
||||
# (e.g. for mylib.a, specify "mylib.a" or "path/mylib.a")
|
||||
LIBS = be bnetapi localestub matrix_client network $(STDCPPLIBS)
|
||||
|
||||
|
||||
# Specify additional paths to directories following the standard libXXX.so
|
||||
# or libXXX.a naming scheme. You can specify full paths or paths relative
|
||||
# to the Makefile. The paths included are not parsed recursively, so
|
||||
# include all of the paths where libraries must be found. Directories where
|
||||
# source files were specified are automatically included.
|
||||
LIBPATHS =
|
||||
|
||||
# Additional paths to look for system headers. These use the form
|
||||
# "#include <header>". Directories that contain the files in SRCS are
|
||||
# NOT auto-included here.
|
||||
SYSTEM_INCLUDE_PATHS = application/ libs/
|
||||
|
||||
# Additional paths paths to look for local headers. These use the form
|
||||
# #include "header". Directories that contain the files in SRCS are
|
||||
# automatically included.
|
||||
LOCAL_INCLUDE_PATHS =
|
||||
|
||||
# Specify the level of optimization that you want. Specify either NONE (O0),
|
||||
# SOME (O1), FULL (O3), or leave blank (for the default optimization level).
|
||||
OPTIMIZE :=
|
||||
|
||||
# Specify the codes for languages you are going to support in this
|
||||
# application. The default "en" one must be provided too. "make catkeys"
|
||||
# will recreate only the "locales/en.catkeys" file. Use it as a template
|
||||
# for creating catkeys for other languages. All localization files must be
|
||||
# placed in the "locales" subdirectory.
|
||||
LOCALES =
|
||||
|
||||
# Specify all the preprocessor symbols to be defined. The symbols will not
|
||||
# have their values set automatically; you must supply the value (if any) to
|
||||
# use. For example, setting DEFINES to "DEBUG=1" will cause the compiler
|
||||
# option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" would pass
|
||||
# "-DDEBUG" on the compiler's command line.
|
||||
DEFINES =
|
||||
|
||||
# Specify the warning level. Either NONE (suppress all warnings),
|
||||
# ALL (enable all warnings), or leave blank (enable default warnings).
|
||||
WARNINGS =
|
||||
|
||||
# With image symbols, stack crawls in the debugger are meaningful.
|
||||
# If set to "TRUE", symbols will be created.
|
||||
SYMBOLS :=
|
||||
|
||||
# Includes debug information, which allows the binary to be debugged easily.
|
||||
# If set to "TRUE", debug info will be created.
|
||||
DEBUGGER :=
|
||||
|
||||
# Specify any additional compiler flags to be used.
|
||||
COMPILER_FLAGS = -std=c++17
|
||||
|
||||
# Specify any additional linker flags to be used.
|
||||
LINKER_FLAGS =
|
||||
|
||||
# Specify the version of this binary. Example:
|
||||
# -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL"
|
||||
# This may also be specified in a resource.
|
||||
APP_VERSION :=
|
||||
|
||||
# (Only used when "TYPE" is "DRIVER"). Specify the desired driver install
|
||||
# location in the /dev hierarchy. Example:
|
||||
# DRIVER_PATH = video/usb
|
||||
# will instruct the "driverinstall" rule to place a symlink to your driver's
|
||||
# binary in ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will
|
||||
# appear at /dev/video/usb when loaded. The default is "misc".
|
||||
DRIVER_PATH =
|
||||
|
||||
## Include the Makefile-Engine
|
||||
DEVEL_DIRECTORY := /boot/system/develop/
|
||||
include $(DEVEL_DIRECTORY)/etc/makefile-engine
|
||||
|
||||
include Makefile.common
|
||||
include protocols/Makefile.common
|
||||
|
||||
CATKEYS_DIR = locales/matrix
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
#ifndef _MATRIX_H
|
||||
#define _MATRIX_H
|
||||
|
||||
#define MATRIX_SIGNATURE "application/x-vnd.chat-o-matic.matrix"
|
||||
#define MATRIX_ADDON "matrix"
|
||||
|
||||
#endif // _MATRIX_H
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
#include "MatrixApp.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <Catalog.h>
|
||||
#include <MessageRunner.h>
|
||||
#include <Roster.h>
|
||||
|
||||
#include <ChatOMatic.h>
|
||||
#include <ChatProtocolMessages.h>
|
||||
#include <Flags.h>
|
||||
#include <UserStatus.h>
|
||||
|
||||
#include "Matrix.h"
|
||||
#include "MatrixMessages.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "MatrixApp"
|
||||
|
||||
|
||||
std::shared_ptr<mtx::http::Client> client = nullptr;
|
||||
MatrixApp* m_app = NULL;
|
||||
|
||||
|
||||
int
|
||||
main(int arc, char** argv)
|
||||
{
|
||||
MatrixApp app;
|
||||
app.Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
MatrixApp::MatrixApp()
|
||||
:
|
||||
BApplication(MATRIX_SIGNATURE),
|
||||
fUser(NULL),
|
||||
fPassword(NULL),
|
||||
fInitStatus(B_NOT_INITIALIZED),
|
||||
fProtoThread(-1)
|
||||
{
|
||||
new BMessageRunner(this, new BMessage(CHECK_APP), 10000000, -1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MatrixApp::MessageReceived(BMessage* msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case MATRIX_REGISTER_ACCOUNT:
|
||||
{
|
||||
int64 thread_id;
|
||||
if (msg->FindInt64("thread_id", &thread_id) != B_OK)
|
||||
break;
|
||||
|
||||
fProtoThread = thread_id;
|
||||
fUser = msg->FindString("username");
|
||||
fSession = msg->GetString("session", "Chat-O-Matic [Haiku]");
|
||||
fServer = msg->FindString("server");
|
||||
fPassword = msg->FindString("password");
|
||||
|
||||
app_info info;
|
||||
GetAppInfo(&info);
|
||||
BMessage registerApp(MATRIX_ACCOUNT_REGISTERED);
|
||||
registerApp.AddInt64("team_id", info.team);
|
||||
SendMessage(registerApp);
|
||||
|
||||
Connect();
|
||||
break;
|
||||
}
|
||||
case CHECK_APP:
|
||||
{
|
||||
BRoster roster;
|
||||
if (roster.IsRunning(APP_SIGNATURE) == false)
|
||||
Quit();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BApplication::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MatrixApp::ImMessage(BMessage* msg)
|
||||
{
|
||||
int32 im_what = msg->GetInt32("im_what", -1);
|
||||
switch (im_what) {
|
||||
case IM_SET_OWN_STATUS:
|
||||
{
|
||||
}
|
||||
default: {
|
||||
std::cout << "Unhandled message for Matrix:\n";
|
||||
msg->PrintToStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MatrixApp::Connect()
|
||||
{
|
||||
client = std::make_shared<mtx::http::Client>(fServer.String());
|
||||
client->set_device_id(fSession.String());
|
||||
client->login(fUser.String(), fPassword.String(),
|
||||
[this](const mtx::responses::Login &res, mtx::http::RequestErr err)
|
||||
{
|
||||
if (err) {
|
||||
SendError("Error occured during login, please try again.", err,
|
||||
true);
|
||||
fInitStatus = B_ERROR;
|
||||
}
|
||||
else {
|
||||
client->set_access_token(res.access_token);
|
||||
fInitStatus = B_OK;
|
||||
StartLoop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MatrixApp::StartLoop()
|
||||
{
|
||||
BMessage ready(IM_MESSAGE);
|
||||
ready.AddInt32("im_what", IM_PROTOCOL_READY);
|
||||
SendMessage(ready);
|
||||
|
||||
BString mxId("@");
|
||||
mxId << fUser << ":" << fServer;
|
||||
BMessage init(IM_MESSAGE);
|
||||
init.AddInt32("im_what", IM_OWN_CONTACT_INFO);
|
||||
init.AddString("user_id", mxId);
|
||||
SendMessage(init);
|
||||
|
||||
BMessage status(IM_MESSAGE);
|
||||
status.AddInt32("im_what", IM_OWN_STATUS_SET);
|
||||
status.AddInt32("status", (int32)STATUS_ONLINE);
|
||||
SendMessage(status);
|
||||
|
||||
mtx::http::SyncOpts opts;
|
||||
opts.timeout = 0;
|
||||
client->sync(opts, &initial_sync_handler);
|
||||
client->close();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MatrixApp::SendMessage(BMessage msg)
|
||||
{
|
||||
if (fProtoThread <= 0)
|
||||
return;
|
||||
|
||||
ssize_t size = msg.FlattenedSize();
|
||||
char buffer[size];
|
||||
|
||||
send_data(fProtoThread, size, NULL, 0);
|
||||
msg.Flatten(buffer, size);
|
||||
send_data(fProtoThread, 0, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MatrixApp::SendError(const char* message, mtx::http::RequestErr err,
|
||||
bool fatal)
|
||||
{
|
||||
print_error(err);
|
||||
|
||||
BString detail;
|
||||
if (!err->matrix_error.error.empty())
|
||||
detail << err->matrix_error.error.c_str();
|
||||
|
||||
BMessage error(IM_ERROR);
|
||||
error.AddString("error", message);
|
||||
error.AddString("detail", detail);
|
||||
SendMessage(error);
|
||||
|
||||
if (fatal == true) {
|
||||
BMessage disable(IM_MESSAGE);
|
||||
disable.AddInt32("im_what", IM_PROTOCOL_DISABLE);
|
||||
SendMessage(disable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_error(mtx::http::RequestErr err, const char* message)
|
||||
{
|
||||
if (message != NULL)
|
||||
std::cerr << message << " ― ";
|
||||
std::cerr << err->status_code << " : " << err->error_code;
|
||||
if (!err->matrix_error.error.empty())
|
||||
std::cerr << " : " << err->matrix_error.error;
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
initial_sync_handler(const mtx::responses::Sync &res, mtx::http::RequestErr err)
|
||||
{
|
||||
mtx::http::SyncOpts opts;
|
||||
|
||||
if (err) {
|
||||
print_error(err, "Error occured during initial sync. Retrying…");
|
||||
if ((int)err->status_code != 200) {
|
||||
opts.timeout = 0;
|
||||
client->sync(opts, &initial_sync_handler);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
room_sync(res.rooms);
|
||||
|
||||
opts.since = res.next_batch;
|
||||
client->set_next_batch_token(res.next_batch);
|
||||
client->sync(opts, &sync_handler);
|
||||
}
|
||||
|
||||
|
||||
// Callback to executed after a /sync request completes.
|
||||
void
|
||||
sync_handler(const mtx::responses::Sync &res, mtx::http::RequestErr err)
|
||||
{
|
||||
mtx::http::SyncOpts opts;
|
||||
|
||||
if (err) {
|
||||
print_error(err, "Error occured during sync. Retrying…");
|
||||
opts.since = client->next_batch_token();
|
||||
client->sync(opts, &sync_handler);
|
||||
return;
|
||||
}
|
||||
|
||||
room_sync(res.rooms);
|
||||
|
||||
opts.since = res.next_batch;
|
||||
client->set_next_batch_token(res.next_batch);
|
||||
client->sync(opts, &sync_handler);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
room_sync(mtx::responses::Rooms rooms)
|
||||
{
|
||||
MatrixApp* app = (MatrixApp*)be_app;
|
||||
|
||||
std::map<std::string, mtx::responses::JoinedRoom> joined = rooms.join;
|
||||
for (std::map<std::string, mtx::responses::JoinedRoom>::iterator iter
|
||||
= joined.begin();
|
||||
iter != joined.end();
|
||||
++iter)
|
||||
{
|
||||
const char* chat_id = iter->first.c_str();
|
||||
mtx::responses::JoinedRoom room = iter->second;
|
||||
|
||||
if (app->fRoomList.HasString(BString(chat_id)) == false) {
|
||||
BMessage joinedMsg(IM_MESSAGE);
|
||||
joinedMsg.AddInt32("im_what", IM_ROOM_JOINED);
|
||||
joinedMsg.AddString("chat_id", chat_id);
|
||||
((MatrixApp*)be_app)->SendMessage(joinedMsg);
|
||||
|
||||
app->fRoomList.Add(BString(chat_id));
|
||||
}
|
||||
|
||||
for (mtx::events::collections::TimelineEvents &ev : room.timeline.events)
|
||||
if (auto event = std::get_if<mtx::events::RoomEvent<mtx::events::msg::Text>>(&ev);
|
||||
event != nullptr)
|
||||
{
|
||||
BMessage msg(IM_MESSAGE);
|
||||
msg.AddInt32("im_what", IM_MESSAGE_RECEIVED);
|
||||
msg.AddString("body", event->content.body.c_str());
|
||||
msg.AddString("chat_id", chat_id);
|
||||
msg.AddString("user_id", event->sender.c_str());
|
||||
app->SendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, mtx::responses::LeftRoom> left = rooms.leave;
|
||||
for (std::map<std::string, mtx::responses::LeftRoom>::iterator iter
|
||||
= left.begin();
|
||||
iter != left.end();
|
||||
++iter)
|
||||
{
|
||||
const char* chat_id = iter->first.c_str();
|
||||
if (app->fRoomList.HasString(BString(chat_id)) == true)
|
||||
app->fRoomList.Remove(BString(chat_id));
|
||||
|
||||
BMessage leftMsg(IM_MESSAGE);
|
||||
leftMsg.AddInt32("im_what", IM_ROOM_LEFT);
|
||||
leftMsg.AddString("chat_id", ((std::string)iter->first).c_str());
|
||||
((MatrixApp*)be_app)->SendMessage(leftMsg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef _MATRIX_APP_H
|
||||
#define _MATRIX_APP_H
|
||||
|
||||
#include <Application.h>
|
||||
#include <String.h>
|
||||
#include <StringList.h>
|
||||
|
||||
#include <mtx.hpp>
|
||||
#include <mtxclient/http/client.hpp>
|
||||
#include <mtxclient/http/errors.hpp>
|
||||
|
||||
|
||||
const uint32 CHECK_APP = 'Paca';
|
||||
|
||||
|
||||
class MatrixApp : public BApplication {
|
||||
public:
|
||||
MatrixApp();
|
||||
|
||||
virtual void MessageReceived(BMessage* msg);
|
||||
void ImMessage(BMessage* msg);
|
||||
|
||||
void Connect();
|
||||
void StartLoop();
|
||||
|
||||
void SendMessage(BMessage msg);
|
||||
void SendError(const char* message,
|
||||
mtx::http::RequestErr err, bool fatal = false);
|
||||
|
||||
BMessage* fSettings;
|
||||
status_t fInitStatus;
|
||||
BStringList fRoomList;
|
||||
|
||||
private:
|
||||
// Settings
|
||||
BString fUser;
|
||||
BString fPassword;
|
||||
BString fServer;
|
||||
BString fSession;
|
||||
|
||||
thread_id fProtoThread;
|
||||
};
|
||||
|
||||
|
||||
void print_error(mtx::http::RequestErr err, const char* message = NULL);
|
||||
|
||||
void login_handler(const mtx::responses::Login &res, mtx::http::RequestErr err);
|
||||
|
||||
void initial_sync_handler(const mtx::responses::Sync &res, mtx::http::RequestErr err);
|
||||
void sync_handler(const mtx::responses::Sync &res, mtx::http::RequestErr err);
|
||||
|
||||
void room_sync(mtx::responses::Rooms rooms);
|
||||
|
||||
#endif // _MATRIX_APP_H
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
#include "MatrixProtocol.h"
|
||||
|
||||
|
||||
extern "C" _EXPORT ChatProtocol* protocol_at(int32 i);
|
||||
extern "C" _EXPORT int32 protocol_count();
|
||||
extern "C" _EXPORT const char* signature();
|
||||
extern "C" _EXPORT const char* friendly_signature();
|
||||
extern "C" _EXPORT uint32 version();
|
||||
|
||||
|
||||
ChatProtocol*
|
||||
protocol_at(int32 i)
|
||||
{
|
||||
if (i == 0)
|
||||
return (ChatProtocol*)new MatrixProtocol();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
protocol_count()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
signature()
|
||||
{
|
||||
return "matrix";
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
friendly_signature()
|
||||
{
|
||||
return "Matrix";
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
version()
|
||||
{
|
||||
return APP_VERSION_1_ALPHA_1;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef _MATRIX_MESSAGES_H
|
||||
#define _MATRIX_MESSAGES_H
|
||||
|
||||
enum matrix_message {
|
||||
/*
|
||||
* Messages between the Matrix add-on and server
|
||||
*/
|
||||
|
||||
/*! Register account & thread with app →Server
|
||||
Requires: Account template, int64 thread_id */
|
||||
MATRIX_REGISTER_ACCOUNT = 'MXra',
|
||||
|
||||
|
||||
/*! Inform the protocol of app team id →Protocol
|
||||
Requires: int64 team_id */
|
||||
MATRIX_ACCOUNT_REGISTERED = 'MXar'
|
||||
};
|
||||
|
||||
#endif // _MATRIX_MESSAGES_H
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
#include "MatrixProtocol.h"
|
||||
|
||||
#include <Catalog.h>
|
||||
#include <Messenger.h>
|
||||
#include <Roster.h>
|
||||
|
||||
#include <libinterface/BitmapUtils.h>
|
||||
|
||||
#include <ChatProtocolMessages.h>
|
||||
#include <UserStatus.h>
|
||||
|
||||
#include "Matrix.h"
|
||||
#include "MatrixMessages.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "MatrixProtocol"
|
||||
|
||||
|
||||
status_t
|
||||
connect_thread(void* data)
|
||||
{
|
||||
MatrixProtocol* protocol = (MatrixProtocol*)data;
|
||||
while (true) {
|
||||
BMessage* msg = new BMessage(receive_message());
|
||||
switch (msg->what) {
|
||||
case MATRIX_ACCOUNT_REGISTERED:
|
||||
protocol->RegisterApp((team_id)msg->GetInt64("team_id", -1));
|
||||
break;
|
||||
default:
|
||||
protocol->SendMessage(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BMessage
|
||||
receive_message()
|
||||
{
|
||||
thread_id sender;
|
||||
int32 size = receive_data(&sender, NULL, 0);
|
||||
char buffer[size];
|
||||
receive_data(&sender, buffer, size);
|
||||
BMessage temp;
|
||||
temp.Unflatten(buffer);
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
MatrixProtocol::MatrixProtocol()
|
||||
:
|
||||
fAppMessenger(NULL),
|
||||
fAppTeam(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
MatrixProtocol::~MatrixProtocol()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MatrixProtocol::Init(ChatProtocolMessengerInterface* interface)
|
||||
{
|
||||
fMessenger = interface;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MatrixProtocol::Shutdown()
|
||||
{
|
||||
_SendMatrixMessage(new BMessage(B_QUIT_REQUESTED));
|
||||
kill_thread(fRecvThread);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MatrixProtocol::UpdateSettings(BMessage* settings)
|
||||
{
|
||||
fRecvThread = spawn_thread(connect_thread, "moon_w_blackjack_and_hookers",
|
||||
B_NORMAL_PRIORITY, (void*)this);
|
||||
|
||||
if (fRecvThread < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
settings->AddInt64("thread_id", fRecvThread);
|
||||
fSettings = new BMessage(*settings);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MatrixProtocol::Process(BMessage* msg)
|
||||
{
|
||||
int32 im_what = msg->GetInt32("im_what", -1);
|
||||
|
||||
switch (im_what) {
|
||||
case IM_SET_OWN_STATUS:
|
||||
{
|
||||
int32 status = msg->GetInt32("status", -1);
|
||||
switch (status) {
|
||||
case STATUS_ONLINE:
|
||||
resume_thread(fRecvThread);
|
||||
if (fAppMessenger == NULL || fAppMessenger->IsValid() == false)
|
||||
_StartApp();
|
||||
break;
|
||||
case STATUS_OFFLINE:
|
||||
{
|
||||
_SendMatrixMessage(new BMessage(B_QUIT_REQUESTED));
|
||||
kill_thread(fRecvThread);
|
||||
|
||||
delete fAppMessenger;
|
||||
fAppMessenger = NULL;
|
||||
fAppTeam = -1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
_SendMatrixMessage(msg);
|
||||
}
|
||||
}
|
||||
default:
|
||||
_SendMatrixMessage(msg);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
BMessage
|
||||
MatrixProtocol::SettingsTemplate(const char* name)
|
||||
{
|
||||
BMessage settings;
|
||||
if (strcmp(name, "account") == 0)
|
||||
settings = _AccountTemplate();
|
||||
else if (strcmp(name, "join_room") == 0 || strcmp(name, "create_room") == 0)
|
||||
settings = _RoomTemplate();
|
||||
else if (strcmp(name, "roster") == 0)
|
||||
settings = _RosterTemplate();
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
||||
BObjectList<BMessage>
|
||||
MatrixProtocol::Commands()
|
||||
{
|
||||
return BObjectList<BMessage>();
|
||||
}
|
||||
|
||||
|
||||
BBitmap*
|
||||
MatrixProtocol::Icon() const
|
||||
{
|
||||
return NULL;
|
||||
// return ReadNodeIcon(fAddOnPath.Path(), B_LARGE_ICON, true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MatrixProtocol::SendMessage(BMessage* msg)
|
||||
{
|
||||
msg->AddString("protocol", Signature());
|
||||
fMessenger->SendMessage(msg);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MatrixProtocol::RegisterApp(team_id team)
|
||||
{
|
||||
if (team < 0)
|
||||
return;
|
||||
fAppTeam = team;
|
||||
fAppMessenger = new BMessenger(NULL, team);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MatrixProtocol::_SendMatrixMessage(BMessage* msg)
|
||||
{
|
||||
msg->AddString("protocol", MATRIX_ADDON);
|
||||
if (fAppMessenger != NULL && fAppMessenger->IsValid())
|
||||
fAppMessenger->SendMessage(msg);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MatrixProtocol::_StartApp()
|
||||
{
|
||||
BMessage* start = new BMessage(*fSettings);
|
||||
start->what = MATRIX_REGISTER_ACCOUNT;
|
||||
|
||||
BRoster roster;
|
||||
if (roster.Launch(MATRIX_SIGNATURE, start) == B_OK)
|
||||
snooze(100000);
|
||||
}
|
||||
|
||||
|
||||
BMessage
|
||||
MatrixProtocol::_AccountTemplate()
|
||||
{
|
||||
BMessage settings;
|
||||
|
||||
BMessage server;
|
||||
server.AddString("name", "server");
|
||||
server.AddString("description", B_TRANSLATE("Homeserver:"));
|
||||
server.AddString("default", "matrix.org");
|
||||
server.AddString("error", B_TRANSLATE("Please enter a valid server address."));
|
||||
server.AddInt32("type", B_STRING_TYPE);
|
||||
settings.AddMessage("setting", &server);
|
||||
|
||||
BMessage user;
|
||||
user.AddString("name", "username");
|
||||
user.AddString("description", B_TRANSLATE("Username:"));
|
||||
user.AddString("error", B_TRANSLATE("You need a username in order to connect!"));
|
||||
user.AddInt32("type", B_STRING_TYPE);
|
||||
settings.AddMessage("setting", &user);
|
||||
|
||||
BMessage password;
|
||||
password.AddString("name", "password"); password.AddString("description", B_TRANSLATE("Password:"));
|
||||
password.AddString("error", B_TRANSLATE("Without a password, how will love survive?"));
|
||||
password.AddInt32("type", B_STRING_TYPE);
|
||||
settings.AddMessage("setting", &password);
|
||||
|
||||
BMessage session;
|
||||
session.AddString("name", "session");
|
||||
session.AddString("description", B_TRANSLATE("Session name:"));
|
||||
session.AddInt32("type", B_STRING_TYPE);
|
||||
session.AddString("default", "Chat-O-Matic [Haiku]");
|
||||
settings.AddMessage("setting", &session);
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
||||
BMessage
|
||||
MatrixProtocol::_RoomTemplate()
|
||||
{
|
||||
BMessage settings;
|
||||
|
||||
BMessage id;
|
||||
id.AddString("name", "chat_id");
|
||||
id.AddString("description", B_TRANSLATE("Channel:"));
|
||||
id.AddString("error", B_TRANSLATE("Please enter a channel― skipping it doesn't make sense!"));
|
||||
id.AddInt32("type", B_STRING_TYPE);
|
||||
settings.AddMessage("setting", &id);
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
||||
BMessage
|
||||
MatrixProtocol::_RosterTemplate()
|
||||
{
|
||||
BMessage settings;
|
||||
|
||||
BMessage nick;
|
||||
nick.AddString("name", "user_id");
|
||||
nick.AddString("description", B_TRANSLATE("User ID:"));
|
||||
nick.AddString("error", B_TRANSLATE("How can someone be your friend if you don't know their ID?"));
|
||||
nick.AddInt32("type", B_STRING_TYPE);
|
||||
settings.AddMessage("setting", &nick);
|
||||
|
||||
return settings;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2021, Jaidyn Levesque <jadedctrl@teknik.io>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef _MATRIX_PROTOCOL_H
|
||||
#define _MATRIX_PROTOCOL_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include <ChatProtocol.h>
|
||||
|
||||
#include "Matrix.h"
|
||||
|
||||
|
||||
status_t connect_thread(void* data);
|
||||
BMessage receive_message();
|
||||
|
||||
|
||||
class MatrixProtocol : public ChatProtocol {
|
||||
public:
|
||||
MatrixProtocol();
|
||||
~MatrixProtocol();
|
||||
|
||||
// ChatProtocol inheritance
|
||||
virtual status_t Init(ChatProtocolMessengerInterface* interface);
|
||||
virtual status_t Shutdown();
|
||||
|
||||
virtual status_t UpdateSettings(BMessage* settings);
|
||||
|
||||
virtual status_t Process(BMessage* msg);
|
||||
|
||||
virtual BMessage SettingsTemplate(const char* name);
|
||||
virtual BObjectList<BMessage>
|
||||
Commands();
|
||||
|
||||
virtual const char* Signature() const { return MATRIX_ADDON; }
|
||||
virtual const char* FriendlySignature() const { return "Matrix"; }
|
||||
|
||||
virtual BBitmap* Icon() const;
|
||||
|
||||
virtual void SetAddOnPath(BPath path) { fAddOnPath = path; }
|
||||
virtual BPath AddOnPath() { return fAddOnPath; }
|
||||
|
||||
virtual const char* GetName() { return fName; }
|
||||
virtual void SetName(const char* name) { fName = name; }
|
||||
|
||||
virtual ChatProtocolMessengerInterface*
|
||||
MessengerInterface() const { return fMessenger; }
|
||||
|
||||
// Matrix
|
||||
void SendMessage(BMessage* msg);
|
||||
void RegisterApp(team_id team);
|
||||
|
||||
private:
|
||||
void _SendMatrixMessage(BMessage* msg);
|
||||
void _StartApp();
|
||||
|
||||
// GUI templates
|
||||
BMessage _AccountTemplate();
|
||||
BMessage _RoomTemplate();
|
||||
BMessage _RosterTemplate();
|
||||
|
||||
// Settings
|
||||
BMessage* fSettings;
|
||||
|
||||
BPath fAddOnPath;
|
||||
BString fName;
|
||||
ChatProtocolMessengerInterface* fMessenger;
|
||||
|
||||
team_id fAppTeam;
|
||||
thread_id fRecvThread;
|
||||
BMessenger* fAppMessenger;
|
||||
};
|
||||
|
||||
#endif // _MATRIX_PROTOCOL_H
|
|
@ -0,0 +1,16 @@
|
|||
#include "Matrix.h"
|
||||
|
||||
resource app_signature MATRIX_SIGNATURE;
|
||||
resource app_flags B_BACKGROUND_APP | B_MULTIPLE_LAUNCH;
|
||||
|
||||
resource app_version {
|
||||
major = 0,
|
||||
middle = 0,
|
||||
minor = 1,
|
||||
|
||||
variety = B_APPV_ALPHA,
|
||||
internal = 0,
|
||||
|
||||
short_info = "Chat-O-Matic Matrix add-on",
|
||||
long_info = "©2021 Jaidyn Levesque"
|
||||
};
|
Ŝarĝante…
Reference in New Issue