diff --git a/modules/renderer/ExternalModalHandler.ts b/modules/renderer/ExternalModalHandler.ts index 7bbe9d6..4c0f30d 100644 --- a/modules/renderer/ExternalModalHandler.ts +++ b/modules/renderer/ExternalModalHandler.ts @@ -4,6 +4,7 @@ import {ExternalModal, kIPCChannelExternalModal} from "../shared/ipc/ExternalMod import {ObjectProxyClient} from "../shared/proxy/Client"; import {ProxiedClass} from "../shared/proxy/Definitions"; import {getIpcInstance} from "tc-shared/ipc/BrowserIPC"; +import {ModalOptions} from "tc-shared/ui/react-elements/modal/Definitions"; const modalClient = new ObjectProxyClient(kIPCChannelExternalModal); modalClient.initialize(); @@ -11,8 +12,8 @@ modalClient.initialize(); export class ExternalModalController extends AbstractExternalModalController { private handle: ProxiedClass & ExternalModal; - constructor(a, b, c) { - super(a, b, c); + constructor(modalType: string, constructorArguments?: any[], options?: ModalOptions) { + super(modalType, constructorArguments); } protected async spawnWindow(): Promise { diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 73d17e0..81731b1 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -24,8 +24,8 @@ function(setup_nodejs) set(NODEJS_URL "https://atom.io/download/atom-shell") set(NODEJS_VERSION "v8.0.0") - #set(NODEJS_URL "https://nodejs.org/download/release/") - #set(NODEJS_VERSION "v12.13.0") + set(NODEJS_URL "https://nodejs.org/download/release/") + set(NODEJS_VERSION "v12.13.0") find_package(NodeJS REQUIRED) diff --git a/native/dns/src/resolver.cpp b/native/dns/src/resolver.cpp index 620f656..e547b02 100644 --- a/native/dns/src/resolver.cpp +++ b/native/dns/src/resolver.cpp @@ -280,7 +280,7 @@ void Resolver::event_tsdns_read(Resolver::tsdns_request *request) { this->destroy_tsdns_request(request); return; } else if(buffer_length == 0) { - if(request->read_buffer.empty()) { + if(request->read_buffer.empty() || request->read_buffer == "404") { request->callback(ResultState::TSDNS_EMPTY_RESPONSE, 0, ""); } else { request->callback(ResultState::SUCCESS, 0, request->read_buffer); diff --git a/native/dns/test/main.cpp b/native/dns/test/main.cpp index b365fe5..cdb7312 100644 --- a/native/dns/test/main.cpp +++ b/native/dns/test/main.cpp @@ -43,7 +43,7 @@ int main() { auto begin = chrono::system_clock::now(); for(int i = 0; i < 1; i++) { cr(resolver, { - to_string(i) + "ts.twerion.net", + "alex.ts3clan.pp.ua", 9922 }, [begin](bool success, auto data) { auto end = chrono::system_clock::now(); diff --git a/native/dns/utils.cpp b/native/dns/utils.cpp index 73803ad..58bb35b 100644 --- a/native/dns/utils.cpp +++ b/native/dns/utils.cpp @@ -228,7 +228,7 @@ void tc::dns::cr_srv(Resolver& resolver, const ServerAddress& address, const cr_ //-------------------------- TSDNS-Resolve void tc::dns::cr_tsdns(tc::dns::Resolver &resolver, const tc::dns::ServerAddress &address, const tc::dns::cr_callback_t &callback) { - auto root = domain_root(address.host); + auto root = next_subdomain_level(address.host); cr_srv(resolver, {root, 0}, [&resolver, callback, address](bool success, auto data){ if(!success) { callback(false, "failed to resolve tsdns address: " + std::get(data)); @@ -348,6 +348,9 @@ struct CrStatus { flagged_executor_t execute_tsdns; std::tuple tsdns; + flagged_executor_t execute_root_tsdns; + std::tuple root_tsdns; + flagged_executor_t execute_subdomain; std::tuple subdomain; @@ -373,17 +376,20 @@ struct CrStatus { std::get<1>(element) = "No executor"; \ std::get<0>(element) = State::FAILED; \ } \ - } else \ - return false; \ + } else { \ + return false; \ + } \ } bool try_answer(const std::shared_ptr& _this) { - if(this->finished) + if(this->finished) { return true; + } try_answer_test(this->subsrv_ts, this->execute_subsrv_ts); try_answer_test(this->subsrv_ts3, this->execute_subsrv_ts3); try_answer_test(this->tsdns, this->execute_tsdns); + try_answer_test(this->root_tsdns, this->execute_root_tsdns); try_answer_test(this->subdomain, this->execute_subdomain); try_answer_test(this->rootsrv, this->execute_rootsrv); try_answer_test(this->rootdomain, this->execute_rootdomain); @@ -404,6 +410,7 @@ struct CrStatus { answer_log(this->subsrv_ts, this->execute_subsrv_ts); answer_log(this->subsrv_ts3, this->execute_subsrv_ts3); answer_log(this->tsdns, this->execute_tsdns); + answer_log(this->root_tsdns, this->execute_root_tsdns); answer_log(this->subdomain, this->execute_subdomain); answer_log(this->rootsrv, this->execute_rootsrv); answer_log(this->rootdomain, this->execute_rootdomain); @@ -496,8 +503,28 @@ void tc::dns::cr(Resolver& resolver, const tc::dns::ServerAddress& address, cons //Execute the TSDNS request right at the beginning because it could hang sometimes std::get<0>(status->execute_tsdns) = true; - auto root_domain = tc::dns::domain_root(status->address.host); + auto root_domain = tc::dns::next_subdomain_level(status->address.host); if(root_domain != status->address.host) { + status->execute_root_tsdns = { + false, + [&resolver, root_domain](const std::shared_ptr& status) { + //std::cout << "Execute tsdns" << std::endl; + status->pending++; + + tc::dns::cr_tsdns(resolver, { + root_domain, + status->address.port + }, [status](bool success, auto data) { + if(success) { + status->tsdns = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->tsdns = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }); + } + }; + status->execute_rootsrv = { false, [&resolver](const std::shared_ptr& status) { @@ -505,7 +532,7 @@ void tc::dns::cr(Resolver& resolver, const tc::dns::ServerAddress& address, cons status->pending++; tc::dns::cr_srv(resolver, { - tc::dns::domain_root(status->address.host), + tc::dns::next_subdomain_level(status->address.host), status->address.port }, [status](bool success, auto data) { if(success) { @@ -525,7 +552,7 @@ void tc::dns::cr(Resolver& resolver, const tc::dns::ServerAddress& address, cons status->pending++; tc::dns::cr_ip(resolver,{ - tc::dns::domain_root(status->address.host), + tc::dns::next_subdomain_level(status->address.host), status->address.port }, [status](bool success, auto data) { if(success) { diff --git a/native/dns/utils.h b/native/dns/utils.h index 5efb48f..58bac6c 100644 --- a/native/dns/utils.h +++ b/native/dns/utils.h @@ -13,17 +13,19 @@ namespace tc::dns { }; typedef std::function& /* data */)> cr_callback_t; - inline std::string domain_root(std::string input) { - size_t dot_count = 0; - auto it = input.rbegin(); - while(it != input.rend()) { - if(*it == '.' && ++dot_count == 2) - break; - it++; - } - std::string result{}; - result.append(input.begin() + std::distance(it, input.rend()), input.end()); - return result; + inline std::string next_subdomain_level(const std::string& input) { + auto next_level = input.find('.'); + if(next_level == std::string::npos) { + /* invalid input */ + return input; + } + + if(input.find('.', next_level + 1) == std::string::npos) { + /* we're already on the top level */ + return input; + } + + return input.substr(next_level + 1); } extern void cr_ip(Resolver& resolver, const ServerAddress& address, const cr_callback_t& callback); diff --git a/native/serverconnection/src/audio/AudioInput.cpp b/native/serverconnection/src/audio/AudioInput.cpp index 70ccd19..a3a333a 100644 --- a/native/serverconnection/src/audio/AudioInput.cpp +++ b/native/serverconnection/src/audio/AudioInput.cpp @@ -54,7 +54,9 @@ AudioInput::~AudioInput() { void AudioInput::set_device(const std::shared_ptr &device) { std::lock_guard lock{this->input_source_lock}; - if(device == this->input_device) return; + if(device == this->input_device) { + return; + } this->close_device(); this->input_device = device; diff --git a/native/serverconnection/src/audio/driver/AudioDriver.cpp b/native/serverconnection/src/audio/driver/AudioDriver.cpp index b443451..3771354 100644 --- a/native/serverconnection/src/audio/driver/AudioDriver.cpp +++ b/native/serverconnection/src/audio/driver/AudioDriver.cpp @@ -44,9 +44,11 @@ namespace tc::audio { return dev; } #else - for(auto& device : devices()) - if(device->id() == id && (input ? device->is_input_supported() : device->is_output_supported())) + for(auto& device : devices()) { + if(device->id() == id && (input ? device->is_input_supported() : device->is_output_supported())) { return device; + } + } #endif return nullptr; } @@ -78,8 +80,9 @@ namespace tc::audio { { std::unique_lock init_lock{initialize_lock}; if(initialize_state == 2) { - if(callback) + if(callback) { initialize_callbacks.push_back(callback); + } return; } else if(initialize_state == 1) { init_lock.unlock(); @@ -102,8 +105,9 @@ namespace tc::audio { initialize_state = 1; lock.unlock(); - for(auto& callback : callbacks) + for(auto& callback : callbacks) { callback(); + } }); threads::name(init_thread, tr("audio init")); init_thread.detach(); @@ -114,7 +118,9 @@ namespace tc::audio { std::mutex m{}; std::unique_lock init_lock{initialize_lock}; - if(initialize_state != 2) return; + if(initialize_state != 2) { + return; + } initialize_callbacks.emplace_back([&]{ cv.notify_all(); }); init_lock.unlock(); @@ -134,7 +140,9 @@ namespace tc::audio { bool AudioDevicePlayback::start(std::string &error) { std::lock_guard lock{this->state_lock}; - if(this->running) return true; + if(this->running) { + return true; + } if(!this->impl_start(error)) { log_error(category::audio, tr("Failed to start playback: {}"), error); @@ -181,8 +189,9 @@ namespace tc::audio { std::lock_guard lock{this->source_lock}; if(!buffer) { - for(auto& source : this->_sources) + for(auto& source : this->_sources) { source->fill_buffer(nullptr, samples, channels); + } return; } @@ -227,7 +236,9 @@ namespace tc::audio { std::lock_guard lock{this->state_lock}; { std::lock_guard s_lock{this->consumer_lock}; - if(!this->_consumers.empty()) return; + if(!this->_consumers.empty()) { + return; + } } this->impl_stop(); @@ -237,7 +248,9 @@ namespace tc::audio { void AudioDeviceRecord::stop() { std::lock_guard lock{this->state_lock}; - if(!this->running) return; + if(!this->running) { + return; + } this->impl_stop(); this->running = false; @@ -252,7 +265,9 @@ namespace tc::audio { void AudioDeviceRecord::remove_consumer(Consumer* source) { std::lock_guard s_lock{this->consumer_lock}; auto index = find(this->_consumers.begin(), this->_consumers.end(), source); - if(index == this->_consumers.end()) return; + if(index == this->_consumers.end()) { + return; + } this->_consumers.erase(index); } diff --git a/native/serverconnection/src/audio/driver/AudioDriver.h b/native/serverconnection/src/audio/driver/AudioDriver.h index 23b27cd..eb04709 100644 --- a/native/serverconnection/src/audio/driver/AudioDriver.h +++ b/native/serverconnection/src/audio/driver/AudioDriver.h @@ -24,9 +24,9 @@ namespace tc::audio { std::lock_guard lock{this->consumer_lock}; return this->_consumers; } + void register_consumer(Consumer* /* source */); void remove_consumer(Consumer* /* source */); - protected: virtual bool impl_start(std::string& /* error */) = 0; virtual void impl_stop() = 0; diff --git a/native/serverconnection/src/audio/driver/PortAudioRecord.cpp b/native/serverconnection/src/audio/driver/PortAudioRecord.cpp index a03a829..7b1c2a0 100644 --- a/native/serverconnection/src/audio/driver/PortAudioRecord.cpp +++ b/native/serverconnection/src/audio/driver/PortAudioRecord.cpp @@ -74,8 +74,9 @@ bool PortAudioRecord::impl_start(std::string &error) { if(err != paNoError) { error = std::string{Pa_GetErrorText(err)} + "(start stream: " + std::to_string(err) + ")"; err = Pa_CloseStream(this->stream); - if(err != paNoError) + if(err != paNoError) { log_critical(category::audio, tr("Failed to close opened pa stream. This will cause memory leaks. Error: {}/{}"), err, Pa_GetErrorText(err)); + } return false; } @@ -88,10 +89,11 @@ void PortAudioRecord::impl_stop() { Pa_AbortStream(this->stream); auto error = Pa_CloseStream(this->stream); - if(error != paNoError) + if(error != paNoError) { log_error(category::audio, tr("Failed to close PA stream: {}"), error); - else + } else { log_debug(category::audio, tr("Closed audio record stream for {} ({})"), this->info->name, Pa_GetHostApiInfo(this->info->hostApi)->name); + } this->stream = nullptr; } @@ -102,6 +104,7 @@ size_t PortAudioRecord::sample_rate() const { void PortAudioRecord::read_callback(const void *input, unsigned long frameCount, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags) { std::lock_guard consumer_lock{this->consumer_lock}; - for(auto& consumer : this->_consumers) + for(auto& consumer : this->_consumers) { consumer->consume(input, frameCount, this->source_channel_count); + } } \ No newline at end of file diff --git a/native/serverconnection/src/bindings.cpp b/native/serverconnection/src/bindings.cpp index b17217a..63fb8af 100644 --- a/native/serverconnection/src/bindings.cpp +++ b/native/serverconnection/src/bindings.cpp @@ -70,8 +70,8 @@ tc::audio::AudioOutput* global_audio_output; Nan::Set(object, (uint32_t) value, Nan::New(key).ToLocalChecked()); NAN_MODULE_INIT(init) { - logger::initialize_node(); - //logger::initialize_raw(); + //logger::initialize_node(); + logger::initialize_raw(); #ifndef WIN32 logger::info(category::general, tr("Hello World from C. PPID: {}, PID: {}"), getppid(), getpid()); diff --git a/native/serverconnection/test/js/flood.ts b/native/serverconnection/test/js/flood.ts index 2b0fb03..4419d22 100644 --- a/native/serverconnection/test/js/flood.ts +++ b/native/serverconnection/test/js/flood.ts @@ -14,6 +14,44 @@ const { host, port } = { port: target_address.split(":").length > 1 ? parseInt(target_address.split(":")[1]) : 9987 }; +function executeDownload(transferKey: string) { + let target = new ArrayBuffer(1024); + const source = handle.ft.download_transfer_object_from_buffer(target); + + const transfer = handle.ft.spawn_connection({ + client_transfer_id: 0, + server_transfer_id: 0, + + object: source, + transfer_key: transferKey, + + remote_address: "localhost", + remote_port: 30333 + }); + + transfer.callback_failed = message => { + console.log("[FT] failed: %o", message); + }; + + transfer.callback_finished = aborted => { + console.log("[FT] done (Aborted %o)", aborted); + //console.log("A: %o", transfer); + }; + + let last = 0; + transfer.callback_progress = (current, max) => { + const diff = current - last; + last = current; + console.log("[FT] Progress: %d|%d (%d) %dmb/s", current, max, Math.ceil(current / max * 100), Math.ceil(diff / 1024 / 1024)); + }; + + transfer.callback_start = () => { + console.log("[FT] start"); + }; + + transfer.start(); +} + class Bot { connection: NativeServerConnection; knwonChannelIds: number[] = []; @@ -100,12 +138,19 @@ class Bot { if(command == "initserver") { this.client_id = parseInt(args[0]["aclid"]); } else if(command == "channellistfinished"){ - this.disconnect(); this.initialized = true; - this.switchInterval.push(setInterval(() => this.switch_channel(), 10_000 + Math.random() * 5_000)); + //this.switchInterval.push(setInterval(() => this.switch_channel(), 10_000 + Math.random() * 5_000)); + setTimeout(() => this.disconnect(), 2500); } else if(command == "channellist") { for(const element of args) { this.knwonChannelIds.push(parseInt(element["cid"])); + if((parseInt(element["channel_icon_id"]) >>> 0) > 1000) { + this.connection.send_command("ftinitdownload", [{ + "clientftfid": "1", + "seekpos": "0", + "name": "/icon_" + element["channel_icon_id"], + }], []); + } } } else if(command == "notifychannelcreated") { this.knwonChannelIds.push(parseInt(args[0]["cid"])); @@ -113,9 +158,13 @@ class Bot { for(const arg of args) { const channel_id = parseInt(arg["cid"]); const index = this.knwonChannelIds.indexOf(channel_id); - if(index >= 0) + if(index >= 0) { this.knwonChannelIds.splice(index, 1); + } } + } else if(command === "notifystartdownload") { + console.log("File transfer created: %o", args[0]["ftkey"]); + executeDownload(args[0]["ftkey"]); } } @@ -130,12 +179,13 @@ class Bot { const botList: Bot[] = []; async function connectBots() { - for(let index = 0; index < 1 || true; index++) { + for(let index = 0; index < 20; index++) { + console.error("CONNECT"); const bot = new Bot(); botList.push(bot); await new Promise(resolve => bot.connect(resolve)); - await new Promise(resolve => setTimeout(resolve, 1000)); + await new Promise(resolve => setTimeout(resolve, 250)); while(botList.length > 50) { const [ bot ] = botList.splice(0, 1); bot.reset(); @@ -151,6 +201,6 @@ setInterval(() => { connection.connect(); } }); -}, 5); +}, 250); connectBots().then(undefined); \ No newline at end of file