TeaSpeak-Client/native/serverconnection/src/bindings.cpp

227 lines
8.1 KiB
C++

#include <v8.h>
#include <nan.h>
#include <node.h>
#include <iostream>
#include <mutex>
#include <event2/thread.h>
#include <misc/digest.h>
#include "logger.h"
#include "include/NanException.h"
#include "include/NanEventCallback.h"
#include "connection/ServerConnection.h"
#include "connection/audio/VoiceConnection.h"
#include "connection/audio/VoiceClient.h"
#include "connection/ft/FileTransferManager.h"
#include "connection/ft/FileTransferObject.h"
#include "audio/AudioOutput.h"
#include "audio/AudioDevice.h"
#include "audio/js/AudioOutputStream.h"
#include "audio/js/AudioPlayer.h"
#include "audio/js/AudioRecorder.h"
#include "audio/js/AudioConsumer.h"
#include "audio/js/AudioFilter.h"
#include "connection/audio/AudioEventLoop.h"
#ifndef WIN32
#include <unistd.h>
#endif
extern "C" {
#include <tomcrypt_misc.h>
#include <tomcrypt.h>
#include <tommath.h>
};
using namespace std;
using namespace tc;
using namespace tc::connection;
using namespace tc::ft;
void testTomMath(){
mp_int x{};
mp_init(&x);
mp_read_radix(&x, "2280880776330203449294339386427307168808659578661428574166839717243346815923951250209099128371839254311904649344289668000305972691071196233379180504231889", 10);
mp_int n{};
mp_init(&n);
mp_read_radix(&n, "436860662135489324843442078840868871476482593772359054106809367217662215065650065606351911592188139644751920724885335056877706082800496073391354240530016", 10);
mp_int exp{};
mp_init(&exp);
mp_2expt(&exp, 1000);
mp_int r{};
mp_init(&r);
if(mp_exptmod(&x, &exp, &n, &r) == CRYPT_OK) {
log_warn(category::general, tr("TomCrypt check failed. Server connects main fail due to this mistake!"));
//Nan::ThrowError("Tomcrypt library is too modern. Use an oder one!");
//return;
}
//assert(mp_exptmod(&x, &exp, &n, &r) != CRYPT_OK); //if this method succeed than tommath failed. Unknown why but it is so
mp_clear_multi(&x, &n, &exp, &r, nullptr);
}
tc::audio::AudioOutput* global_audio_output;
#define ENUM_SET(object, key, value) \
Nan::DefineOwnProperty(object, Nan::New<v8::String>(key).ToLocalChecked(), Nan::New<v8::Number>(value), v8::DontDelete); \
Nan::Set(object, value, Nan::New<v8::String>(key).ToLocalChecked());
NAN_MODULE_INIT(init) {
logger::initialize_node();
#ifndef WIN32
logger::info(category::general, tr("Hello World from C. PPID: {}, PID: {}"), getppid(), getpid());
#else
logger::info(category::general, tr("Hello World from C. PID: {}"), _getpid());
#endif
/*
{
auto data = (uint8_t*) "Hello World";
auto hash_result = digest::sha1((const char*) data, 11);
if(hash_result.length() != 20)
Nan::ThrowError("digest::sha1 test failed");
log_error(category::connection, tr("Hash result: {}"), hash_result.length());
}
*/
{
auto data = (uint8_t*) "Hello World";
auto hash_result = digest::sha1(std::string("Hello World"));
if(hash_result.length() != 20)
Nan::ThrowError("digest::sha1 test failed");
}
{
auto data = (uint8_t*) "Hello World";
uint8_t result[SHA_DIGEST_LENGTH];
digest::tomcrypt::sha1((char*) data, 11, result);
auto hash_result = std::string((const char*) result, SHA_DIGEST_LENGTH);
log_error(category::connection, tr("Hash result: {}"), hash_result.length());
}
string error;
//TODO here
//PaJack_SetClientName("TeaClient");
Pa_Initialize();
std::thread(audio::devices).detach(); /* cache the devices */
logger::info(category::general, "Loading crypt modules");
std::string descriptors = "LTGE";
{
int crypt_init = false;
for(const auto& c : descriptors)
if((crypt_init = crypt_mp_init(&c) == CRYPT_OK))
break;
if(!crypt_init) {
Nan::ThrowError("failed to init tomcrypt");
return;
}
if(register_prng(&sprng_desc) == -1) {
Nan::ThrowError("could not setup prng");
return;
}
if (register_cipher(&rijndael_desc) == -1) {
Nan::ThrowError("could not setup rijndael");
return;
}
testTomMath();
}
logger::info(category::general, "Crypt modules loaded");
#ifdef WIN32
evthread_use_windows_threads();
#else
evthread_use_pthreads();
#endif
tc::audio::init_event_loops();
/* TODO: Test error codes and make the audi playback device configurable */
global_audio_output = new tc::audio::AudioOutput(2, 48000); //48000 44100
if(!global_audio_output->open_device(error, Pa_GetDefaultOutputDevice())) {
logger::error(category::audio, "Failed to initialize default audio playback: {}", error);
} else {
if(!global_audio_output->playback()) {
logger::error(category::audio, "Failed to start audio playback");
}
}
{
auto namespace_audio = Nan::New<v8::Object>();
Nan::Set(namespace_audio, Nan::New<v8::String>("available_devices").ToLocalChecked(), Nan::GetFunction(Nan::New<v8::FunctionTemplate>(audio::available_devices)).ToLocalChecked());
{
auto namespace_playback = Nan::New<v8::Object>();
audio::player::init_js(namespace_playback);
audio::AudioOutputStreamWrapper::Init(namespace_playback);
Nan::Set(namespace_audio, Nan::New<v8::String>("playback").ToLocalChecked(), namespace_playback);
}
{
auto namespace_record = Nan::New<v8::Object>();
audio::recorder::init_js(namespace_record);
audio::recorder::AudioRecorderWrapper::Init(namespace_record);
audio::recorder::AudioConsumerWrapper::Init(namespace_record);
audio::recorder::AudioFilterWrapper::Init(namespace_record);
Nan::Set(namespace_audio, Nan::New<v8::String>("record").ToLocalChecked(), namespace_record);
}
Nan::Set(target, Nan::New<v8::String>("audio").ToLocalChecked(), namespace_audio);
}
VoiceClientWrap::Init(target);
VoiceConnectionWrap::Init(target);
{
auto enum_object = Nan::New<v8::Object>();
ENUM_SET(enum_object, "BUFFERING", tc::connection::VoiceClient::state::buffering);
ENUM_SET(enum_object, "PLAYING", tc::connection::VoiceClient::state::playing);
ENUM_SET(enum_object, "STOPPING", tc::connection::VoiceClient::state::stopping);
ENUM_SET(enum_object, "STOPPED", tc::connection::VoiceClient::state::stopped);
Nan::DefineOwnProperty(target, Nan::New<v8::String>("PlayerState").ToLocalChecked(), enum_object, v8::DontDelete);
}
transfer_manager = new tc::ft::FileTransferManager();
transfer_manager->initialize();
ServerConnection::Init(target);
Nan::Set(target, Nan::New<v8::String>("spawn_server_connection").ToLocalChecked(), Nan::GetFunction(Nan::New<v8::FunctionTemplate>(ServerConnection::new_instance)).ToLocalChecked());
/* ft namespace */
{
auto ft_namespace = Nan::New<v8::Object>();
TransferObjectWrap::Init(ft_namespace);
Nan::Set(ft_namespace,
Nan::New<v8::String>("upload_transfer_object_from_buffer").ToLocalChecked(),
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(TransferJSBufferSource::create_from_buffer)).ToLocalChecked()
);
Nan::Set(ft_namespace,
Nan::New<v8::String>("download_transfer_object_from_buffer").ToLocalChecked(),
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(TransferJSBufferTarget::create_from_buffer)).ToLocalChecked()
);
Nan::Set(ft_namespace,
Nan::New<v8::String>("upload_transfer_object_from_file").ToLocalChecked(),
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(TransferFileSource::create)).ToLocalChecked()
);
//spawn_file_connection destroy_file_connection
JSTransfer::Init(ft_namespace);
Nan::Set(ft_namespace, Nan::New<v8::String>("spawn_connection").ToLocalChecked(), Nan::GetFunction(Nan::New<v8::FunctionTemplate>(JSTransfer::NewInstance)).ToLocalChecked());
Nan::Set(ft_namespace, Nan::New<v8::String>("destroy_connection").ToLocalChecked(), Nan::GetFunction(Nan::New<v8::FunctionTemplate>(JSTransfer::destory_transfer)).ToLocalChecked());
Nan::Set(target, Nan::New<v8::String>("ft").ToLocalChecked(), ft_namespace);
}
/* setup server types */
{
auto enum_object = Nan::New<v8::Object>();
ENUM_SET(enum_object, "UNKNOWN", tc::connection::server_type::UNKNOWN);
ENUM_SET(enum_object, "TEASPEAK", tc::connection::server_type::TEASPEAK);
ENUM_SET(enum_object, "TEAMSPEAK", tc::connection::server_type::TEAMSPEAK);
Nan::DefineOwnProperty(target, Nan::New<v8::String>("ServerType").ToLocalChecked(), enum_object, v8::DontDelete);
}
}
NODE_MODULE(MODULE_NAME, init)