Made the client compatible with the newest webpack stuff

This commit is contained in:
WolverinDEV 2020-04-01 21:56:23 +02:00
parent c86b9510a5
commit 75b5192801
36 changed files with 2034 additions and 7414 deletions

2
github

@ -1 +1 @@
Subproject commit 171e88fa1f9e4ea67522c1f6bc07b5ca3c8f4b49 Subproject commit 6d45c4c883f9b2a53fe1bfeb23fe559b62a61cac

View File

@ -121,6 +121,6 @@ function deploy_client() {
#install_npm #install_npm
#compile_scripts #compile_scripts
#compile_native compile_native
#package_client package_client
deploy_client deploy_client

View File

@ -8,7 +8,7 @@ const SETTINGS_DIR = path.join(APP_DATA, "settings");
let _local_storage: {[key: string]: any} = {}; let _local_storage: {[key: string]: any} = {};
let _local_storage_save: {[key: string]: boolean} = {}; let _local_storage_save: {[key: string]: boolean} = {};
export async function initialize() { export async function initialize() {
await fs.mkdirs(SETTINGS_DIR); await fs.mkdirp(SETTINGS_DIR);
const files = await fs.readdir(SETTINGS_DIR); const files = await fs.readdir(SETTINGS_DIR);
for(const file of files) { for(const file of files) {

View File

@ -1,6 +1,9 @@
window["require_setup"](module); import {createErrorModal} from "tc-shared/ui/elements/Modal";
import * as electron from "electron"; import * as electron from "electron";
import {tr, tra} from "tc-shared/i18n/localize";
import {server_connections} from "tc-shared/ui/frames/connection_handlers";
import {handle_connect_request} from "tc-shared/main";
electron.ipcRenderer.on('connect', (event, url) => handle_native_connect_request(url)); electron.ipcRenderer.on('connect', (event, url) => handle_native_connect_request(url));

View File

@ -1,44 +1,19 @@
window["require_setup"](module); import * as native from "tc-native/connection";
import {audio as naudio} from "teaclient_connection";
namespace audio.player {
//FIXME: Native audio initialize handle! //FIXME: Native audio initialize handle!
export interface Device { export interface Device {
device_id: string; device_id: string;
name: string; name: string;
} }
interface Navigator {
mozGetUserMedia(constraints: MediaStreamConstraints, successCallback: NavigatorUserMediaSuccessCallback, errorCallback: NavigatorUserMediaErrorCallback): void;
webkitGetUserMedia(constraints: MediaStreamConstraints, successCallback: NavigatorUserMediaSuccessCallback, errorCallback: NavigatorUserMediaErrorCallback): void;
}
let _initialized_callbacks: (() => any)[] = []; let _initialized_callbacks: (() => any)[] = [];
export let _initialized = false; export let _initialized = false;
export let _initializing = false; export let _initializing = false;
export let _audioContext: AudioContext; export let _current_device: native.audio.AudioDevice;
export let _processor: ScriptProcessorNode;
export let _output_stream: naudio.playback.OwnedAudioOutputStream;
export let _current_device: naudio.AudioDevice;
export function initialized() : boolean { export function initialized() : boolean {
return _initialized; return _initialized;
} }
export function context() : AudioContext {
if(!_audioContext) throw "Initialize first!";
return _audioContext;
}
export function destination() : AudioNode {
if(!_initialized)
throw "Audio player hasn't yet be initialized";
return _processor || _audioContext.destination;
}
export function on_ready(cb: () => any) { export function on_ready(cb: () => any) {
if(_initialized) if(_initialized)
cb(); cb();
@ -50,38 +25,7 @@ namespace audio.player {
if(_initializing) return; if(_initializing) return;
_initializing = true; _initializing = true;
naudio.initialize(() => { native.audio.initialize(() => {
_output_stream = naudio.playback.create_stream();
_output_stream.set_buffer_max_latency(0.4);
_output_stream.set_buffer_latency(0.02);
_output_stream.callback_overflow = () => {
console.warn("Main audio overflow");
_output_stream.clear();
};
_output_stream.callback_underflow = () => {
console.warn("Main audio underflow");
};
_audioContext = new AudioContext({
sampleRate: _output_stream.sample_rate
});
_processor = _audioContext.createScriptProcessor(1024 * 8, _output_stream.channels, _output_stream.channels);
_processor.onaudioprocess = function(event) {
const buffer = event.inputBuffer;
//console.log("Received %d channels of %d with a rate of %d", buffer.numberOfChannels, buffer.length, buffer.sampleRate);
const target_buffer = new Float32Array(buffer.numberOfChannels * buffer.length);
for(let channel = 0; channel < buffer.numberOfChannels; channel++) {
const channel_data = buffer.getChannelData(channel);
target_buffer.set(channel_data, channel * buffer.length);
}
_output_stream.write_data_rated(target_buffer.buffer, false, buffer.sampleRate);
};
_processor.connect(_audioContext.destination);
_initialized = true; _initialized = true;
for(const callback of _initialized_callbacks) for(const callback of _initialized_callbacks)
callback(); callback();
@ -91,18 +35,18 @@ namespace audio.player {
} }
export async function available_devices() : Promise<Device[]> { export async function available_devices() : Promise<Device[]> {
return naudio.available_devices().filter(e => e.output_supported || e.output_default); return native.audio.available_devices().filter(e => e.output_supported || e.output_default);
} }
export async function set_device(device_id?: string) : Promise<void> { export async function set_device(device_id?: string) : Promise<void> {
const dev = naudio.available_devices().filter(e => e.device_id == device_id); const dev = native.audio.available_devices().filter(e => e.device_id == device_id);
if(dev.length == 0) { if(dev.length == 0) {
console.warn("Missing audio device with is %s", device_id); console.warn("Missing audio device with is %s", device_id);
throw "invalid device id"; throw "invalid device id";
} }
try { try {
naudio.playback.set_device(dev[0].device_id); native.audio.playback.set_device(dev[0].device_id);
} catch(error) { } catch(error) {
if(error instanceof Error) if(error instanceof Error)
throw error.message; throw error.message;
@ -115,18 +59,15 @@ namespace audio.player {
if(_current_device) if(_current_device)
return _current_device; return _current_device;
const dev = naudio.available_devices().filter(e => e.output_default); const dev = native.audio.available_devices().filter(e => e.output_default);
if(dev.length > 0) if(dev.length > 0)
return dev[0]; return dev[0];
return {device_id: "default", name: "default"} as Device; return {device_id: "default", name: "default"} as Device;
} }
export function get_master_volume() : number { export function get_master_volume() : number {
return naudio.playback.get_master_volume(); return native.audio.playback.get_master_volume();
} }
export function set_master_volume(volume: number) { export function set_master_volume(volume: number) {
naudio.playback.set_master_volume(volume); native.audio.playback.set_master_volume(volume);
} }
}
Object.assign(window["audio"] || (window["audio"] = {} as any), audio);

View File

@ -1,12 +1,13 @@
window["require_setup"](module); import {
filter,
import {audio as naudio} from "teaclient_connection"; AbstractInput,
// <reference types="../imports/import_shared.d.ts" /> InputDevice,
/// <reference types="../../modules/renderer/imports/imports_shared.d.ts" /> InputState,
InputConsumer,
export namespace _audio.recorder { InputConsumerType, InputStartResult, LevelMeter
import InputDevice = audio.recorder.InputDevice; } from "tc-shared/voice/RecorderBase";
import AbstractInput = audio.recorder.AbstractInput; import {audio} from "tc-native/connection";
import {tr} from "tc-shared/i18n/localize";
interface NativeDevice extends InputDevice { interface NativeDevice extends InputDevice {
device_index: number; device_index: number;
@ -16,9 +17,9 @@ export namespace _audio.recorder {
let _device_cache: NativeDevice[] = undefined; let _device_cache: NativeDevice[] = undefined;
export function devices() : InputDevice[] { export function devices() : InputDevice[] {
//TODO: Handle device updates! //TODO: Handle device updates!
if(!naudio.initialized()) return []; if(!audio.initialized()) return [];
return _device_cache || (_device_cache = naudio.available_devices().filter(e => e.input_supported || e.input_default).map(e => { return _device_cache || (_device_cache = audio.available_devices().filter(e => e.input_supported || e.input_default).map(e => {
return { return {
unique_id: e.device_id, unique_id: e.device_id,
channels: 2, /* TODO */ channels: 2, /* TODO */
@ -39,9 +40,9 @@ export namespace _audio.recorder {
return new NativeInput(); return new NativeInput();
} }
namespace filter { namespace filters {
export abstract class NativeFilter implements audio.recorder.filter.Filter { export abstract class NativeFilter implements filter.Filter {
type: audio.recorder.filter.Type; type: filter.Type;
handle: NativeInput; handle: NativeInput;
enabled: boolean = false; enabled: boolean = false;
@ -54,8 +55,8 @@ export namespace _audio.recorder {
is_enabled(): boolean { return this.enabled; } is_enabled(): boolean { return this.enabled; }
} }
export class NThresholdFilter extends NativeFilter implements audio.recorder.filter.ThresholdFilter { export class NThresholdFilter extends NativeFilter implements filter.ThresholdFilter {
private filter: naudio.record.ThresholdConsumeFilter; private filter: audio.record.ThresholdConsumeFilter;
private _margin_frames: number = 6; /* 120ms */ private _margin_frames: number = 6; /* 120ms */
private _threshold: number = 50; private _threshold: number = 50;
@ -67,7 +68,7 @@ export namespace _audio.recorder {
callback_level: (level: number) => any; callback_level: (level: number) => any;
constructor(handle) { constructor(handle) {
super(handle, audio.recorder.filter.Type.THRESHOLD); super(handle, filter.Type.THRESHOLD);
Object.defineProperty(this, 'callback_level', { Object.defineProperty(this, 'callback_level', {
get(): any { get(): any {
@ -150,12 +151,12 @@ export namespace _audio.recorder {
} }
} }
export class NStateFilter extends NativeFilter implements audio.recorder.filter.StateFilter { export class NStateFilter extends NativeFilter implements filter.StateFilter {
private filter: naudio.record.StateConsumeFilter; private filter: audio.record.StateConsumeFilter;
private active = false; private active = false;
constructor(handle) { constructor(handle) {
super(handle, audio.recorder.filter.Type.STATE); super(handle, filter.Type.STATE);
} }
finalize() { finalize() {
@ -188,13 +189,13 @@ export namespace _audio.recorder {
} }
} }
export class NVoiceLevelFilter extends NativeFilter implements audio.recorder.filter.VoiceLevelFilter { export class NVoiceLevelFilter extends NativeFilter implements filter.VoiceLevelFilter {
private filter: naudio.record.VADConsumeFilter; private filter: audio.record.VADConsumeFilter;
private level = 3; private level = 3;
private _margin_frames = 5; private _margin_frames = 5;
constructor(handle) { constructor(handle) {
super(handle, audio.recorder.filter.Type.VOICE_LEVEL); super(handle, filter.Type.VOICE_LEVEL);
} }
finalize() { finalize() {
@ -242,62 +243,62 @@ export namespace _audio.recorder {
} }
export class NativeInput implements AbstractInput { export class NativeInput implements AbstractInput {
private handle: naudio.record.AudioRecorder; private handle: audio.record.AudioRecorder;
consumer: naudio.record.AudioConsumer; consumer: audio.record.AudioConsumer;
private _current_device: audio.recorder.InputDevice; private _current_device: InputDevice;
private _current_state: audio.recorder.InputState = audio.recorder.InputState.PAUSED; private _current_state: InputState = InputState.PAUSED;
callback_begin: () => any; callback_begin: () => any;
callback_end: () => any; callback_end: () => any;
private filters: filter.NativeFilter[] = []; private filters: filters.NativeFilter[] = [];
constructor() { constructor() {
this.handle = naudio.record.create_recorder(); this.handle = audio.record.create_recorder();
this.consumer = this.handle.create_consumer(); this.consumer = this.handle.create_consumer();
this.consumer.callback_ended = () => { this.consumer.callback_ended = () => {
if(this._current_state !== audio.recorder.InputState.RECORDING) if(this._current_state !== InputState.RECORDING)
return; return;
this._current_state = audio.recorder.InputState.DRY; this._current_state = InputState.DRY;
if(this.callback_end) if(this.callback_end)
this.callback_end(); this.callback_end();
}; };
this.consumer.callback_started = () => { this.consumer.callback_started = () => {
if(this._current_state !== audio.recorder.InputState.DRY) if(this._current_state !== InputState.DRY)
return; return;
this._current_state = audio.recorder.InputState.RECORDING; this._current_state = InputState.RECORDING;
if(this.callback_begin) if(this.callback_begin)
this.callback_begin(); this.callback_begin();
}; };
this._current_state = audio.recorder.InputState.PAUSED; this._current_state = InputState.PAUSED;
} }
/* TODO: some kind of finalize? */ /* TODO: some kind of finalize? */
current_consumer(): audio.recorder.InputConsumer | undefined { current_consumer(): InputConsumer | undefined {
return { return {
type: audio.recorder.InputConsumerType.NATIVE type: InputConsumerType.NATIVE
}; };
} }
async set_consumer(consumer: audio.recorder.InputConsumer): Promise<void> { async set_consumer(consumer: InputConsumer): Promise<void> {
if(typeof(consumer) !== "undefined") if(typeof(consumer) !== "undefined")
throw "we only support native consumers!"; /* TODO: May create a general wrapper? */ throw "we only support native consumers!"; /* TODO: May create a general wrapper? */
return; return;
} }
async set_device(_device: audio.recorder.InputDevice | undefined): Promise<void> { async set_device(_device: InputDevice | undefined): Promise<void> {
if(_device === this._current_device) if(_device === this._current_device)
return; return;
this._current_device = _device; this._current_device = _device;
try { try {
await new Promise(resolve => this.handle.set_device(this._current_device ? this._current_device.unique_id : undefined, resolve)); await new Promise(resolve => this.handle.set_device(this._current_device ? this._current_device.unique_id : undefined, resolve));
if(this._current_state !== audio.recorder.InputState.PAUSED && this._current_device) if(this._current_state !== InputState.PAUSED && this._current_device)
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
this.handle.start(flag => { this.handle.start(flag => {
if(typeof flag === "boolean" && flag) if(typeof flag === "boolean" && flag)
@ -312,23 +313,23 @@ export namespace _audio.recorder {
} }
} }
current_device(): audio.recorder.InputDevice | undefined { current_device(): InputDevice | undefined {
return this._current_device; return this._current_device;
} }
current_state(): audio.recorder.InputState { current_state(): InputState {
return this._current_state; return this._current_state;
} }
disable_filter(type: audio.recorder.filter.Type) { disable_filter(type: filter.Type) {
const filter = this.get_filter(type) as filter.NativeFilter; const filter = this.get_filter(type) as filters.NativeFilter;
if(filter.is_enabled()) if(filter.is_enabled())
filter.enabled = false; filter.enabled = false;
filter.finalize(); filter.finalize();
} }
enable_filter(type: audio.recorder.filter.Type) { enable_filter(type: filter.Type) {
const filter = this.get_filter(type) as filter.NativeFilter; const filter = this.get_filter(type) as filters.NativeFilter;
if(!filter.is_enabled()) { if(!filter.is_enabled()) {
filter.enabled = true; filter.enabled = true;
filter.initialize(); filter.initialize();
@ -342,21 +343,21 @@ export namespace _audio.recorder {
} }
} }
get_filter(type: audio.recorder.filter.Type): audio.recorder.filter.Filter | undefined { get_filter(type: filter.Type): filter.Filter | undefined {
for(const filter of this.filters) for(const filter of this.filters)
if(filter.type === type) if(filter.type === type)
return filter; return filter;
let _filter: filter.NativeFilter; let _filter: filters.NativeFilter;
switch (type) { switch (type) {
case audio.recorder.filter.Type.THRESHOLD: case filter.Type.THRESHOLD:
_filter = new filter.NThresholdFilter(this); _filter = new filters.NThresholdFilter(this);
break; break;
case audio.recorder.filter.Type.STATE: case filter.Type.STATE:
_filter = new filter.NStateFilter(this); _filter = new filters.NStateFilter(this);
break; break;
case audio.recorder.filter.Type.VOICE_LEVEL: case filter.Type.VOICE_LEVEL:
_filter = new filter.NVoiceLevelFilter(this); _filter = new filters.NVoiceLevelFilter(this);
break; break;
default: default:
throw "this filter isn't supported!"; throw "this filter isn't supported!";
@ -365,25 +366,25 @@ export namespace _audio.recorder {
return _filter; return _filter;
} }
supports_filter(type: audio.recorder.filter.Type) : boolean { supports_filter(type: filter.Type) : boolean {
switch (type) { switch (type) {
case audio.recorder.filter.Type.THRESHOLD: case filter.Type.THRESHOLD:
case audio.recorder.filter.Type.STATE: case filter.Type.STATE:
case audio.recorder.filter.Type.VOICE_LEVEL: case filter.Type.VOICE_LEVEL:
return true; return true;
default: default:
return false; return false;
} }
} }
async start(): Promise<audio.recorder.InputStartResult> { async start(): Promise<InputStartResult> {
try { try {
await this.stop(); await this.stop();
} catch(error) { } catch(error) {
console.warn(tr("Failed to stop old record session before start (%o)"), error); console.warn(tr("Failed to stop old record session before start (%o)"), error);
} }
this._current_state = audio.recorder.InputState.DRY; this._current_state = InputState.DRY;
try { try {
if(this._current_device) if(this._current_device)
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
@ -397,9 +398,9 @@ export namespace _audio.recorder {
for(const filter of this.filters) for(const filter of this.filters)
if(filter.is_enabled()) if(filter.is_enabled())
filter.initialize(); filter.initialize();
return audio.recorder.InputStartResult.EOK; return InputStartResult.EOK;
} catch(error) { } catch(error) {
this._current_state = audio.recorder.InputState.PAUSED; this._current_state = InputState.PAUSED;
throw error; throw error;
} }
} }
@ -410,7 +411,7 @@ export namespace _audio.recorder {
filter.finalize(); filter.finalize();
if(this.callback_end) if(this.callback_end)
this.callback_end(); this.callback_end();
this._current_state = audio.recorder.InputState.PAUSED; this._current_state = InputState.PAUSED;
} }
get_volume(): number { get_volume(): number {
@ -422,19 +423,19 @@ export namespace _audio.recorder {
} }
} }
export async function create_levelmeter(device: InputDevice) : Promise<audio.recorder.LevelMeter> { export async function create_levelmeter(device: InputDevice) : Promise<LevelMeter> {
const meter = new NativeLevelmenter(device as any); const meter = new NativeLevelmenter(device as any);
await meter.initialize(); await meter.initialize();
return meter; return meter;
} }
class NativeLevelmenter implements audio.recorder.LevelMeter { class NativeLevelmenter implements LevelMeter {
readonly _device: NativeDevice; readonly _device: NativeDevice;
private _callback: (num: number) => any; private _callback: (num: number) => any;
private _recorder: naudio.record.AudioRecorder; private _recorder: audio.record.AudioRecorder;
private _consumer: naudio.record.AudioConsumer; private _consumer: audio.record.AudioConsumer;
private _filter: naudio.record.ThresholdConsumeFilter; private _filter: audio.record.ThresholdConsumeFilter;
constructor(device: NativeDevice) { constructor(device: NativeDevice) {
this._device = device; this._device = device;
@ -442,7 +443,7 @@ export namespace _audio.recorder {
async initialize() { async initialize() {
try { try {
this._recorder = naudio.record.create_recorder(); this._recorder = audio.record.create_recorder();
this._consumer = this._recorder.create_consumer(); this._consumer = this._recorder.create_consumer();
this._filter = this._consumer.create_filter_threshold(.5); this._filter = this._consumer.create_filter_threshold(.5);
@ -467,7 +468,8 @@ export namespace _audio.recorder {
/* references this variable, needs a destory() call, else memory leak */ /* references this variable, needs a destory() call, else memory leak */
this._filter.set_analyze_filter(value => { this._filter.set_analyze_filter(value => {
(this._callback || (() => {}))(value); (this._callback || (() => {
}))(value);
}); });
} }
@ -479,13 +481,14 @@ export namespace _audio.recorder {
if (this._consumer) if (this._consumer)
this._recorder.delete_consumer(this._consumer); this._recorder.delete_consumer(this._consumer);
this._recorder.stop(); this._recorder.stop();
this._recorder.set_device(undefined, () => {}); /* -1 := No device */ this._recorder.set_device(undefined, () => {
}); /* -1 := No device */
this._recorder = undefined; this._recorder = undefined;
this._consumer = undefined; this._consumer = undefined;
this._filter = undefined; this._filter = undefined;
} }
device(): audio.recorder.InputDevice { device(): InputDevice {
return this._device; return this._device;
} }
@ -493,6 +496,3 @@ export namespace _audio.recorder {
this._callback = callback; this._callback = callback;
} }
} }
}
Object.assign(window["audio"] || (window["audio"] = {} as any), _audio);

View File

@ -1,12 +1,8 @@
window["require_setup"](module); import {audio as naudio} from "tc-native/connection";
// <reference types="../imports/import_shared.d.ts" />
/// <reference types="../../modules/renderer/imports/imports_shared.d.ts" />
import {audio as naudio} from "teaclient_connection";
import * as paths from "path"; import * as paths from "path";
import {SoundFile} from "tc-shared/sound/Sounds";
namespace audio.sounds { export async function play_sound(file: SoundFile) : Promise<void> {
export async function play_sound(file: sound.SoundFile) : Promise<void> {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
let pathname = paths.dirname(decodeURIComponent(location.pathname)); let pathname = paths.dirname(decodeURIComponent(location.pathname));
if(pathname[0] === '/' && pathname[2] === ':') //e.g.: /C:/test... if(pathname[0] === '/' && pathname[2] === ':') //e.g.: /C:/test...
@ -26,6 +22,3 @@ namespace audio.sounds {
}); });
}); });
} }
}
Object.assign(window["audio"] || (window["audio"] = {} as any), audio);

View File

@ -0,0 +1,16 @@
import * as handler from "../../audio/AudioPlayer";
export const initialize = handler.initialize;
export const initialized = handler.initialized;
export const context = handler.context;
export const get_master_volume = handler.get_master_volume;
export const set_master_volume = handler.set_master_volume;
export const on_ready = handler.on_ready;
export const available_devices = handler.available_devices;
export const set_device = handler.set_device;
export const current_device = handler.current_device;
export const initializeFromGesture = () => {};

View File

@ -0,0 +1,8 @@
import * as handler from "../../audio/AudioRecorder";
export const devices = handler.devices;
export const device_refresh_available = handler.device_refresh_available;
export const refresh_devices = handler.refresh_devices;
export const create_input = handler.create_input;
export const create_levelmeter = handler.create_levelmeter;

View File

@ -0,0 +1,3 @@
import * as handler from "../../audio/sounds";
export const play_sound = handler.play_sound;

View File

@ -0,0 +1,4 @@
import * as handler from "../connection/ServerConnection";
export const spawn_server_connection = handler.spawn_server_connection;
export const destroy_server_connection = handler.destroy_server_connection;

View File

@ -0,0 +1,4 @@
import * as handler from "../dns/dns_resolver";
export const supported = handler.supported;
export const resolve_address = handler.resolve_address;

View File

@ -0,0 +1,12 @@
import * as handler from "../ppt";
export const initialize = handler.initialize;
export const finalize = handler.finalize;
export const register_key_listener = handler.register_key_listener;
export const unregister_key_listener = handler.unregister_key_listener;
export const register_key_hook = handler.register_key_hook;
export const unregister_key_hook = handler.unregister_key_hook;
export const key_pressed = handler.key_pressed;

View File

@ -1,13 +1,10 @@
/// <reference path="../imports/imports_shared.d.ts" /> import * as native from "tc-native/connection";
window["require_setup"](module);
import * as native from "teaclient_connection";
import * as path from "path"; import * as path from "path";
import {DownloadKey, DownloadTransfer, UploadKey, UploadTransfer} from "tc-shared/FileManager";
import {base64_encode_ab, str2ab8} from "tc-shared/utils/buffers";
namespace _transfer { class NativeFileDownload implements DownloadTransfer {
class NativeFileDownload implements transfer.DownloadTransfer { readonly key: DownloadKey;
readonly key: transfer.DownloadKey;
private _handle: native.ft.NativeFileTransfer; private _handle: native.ft.NativeFileTransfer;
private _buffer: Uint8Array; private _buffer: Uint8Array;
@ -17,7 +14,7 @@ namespace _transfer {
private _result_success: () => any; private _result_success: () => any;
private _result_error: (error: any) => any; private _result_error: (error: any) => any;
constructor(key: transfer.DownloadKey) { constructor(key: DownloadKey) {
this.key = key; this.key = key;
this._buffer = new Uint8Array(key.total_size); this._buffer = new Uint8Array(key.total_size);
this._handle = native.ft.spawn_connection({ this._handle = native.ft.spawn_connection({
@ -33,7 +30,7 @@ namespace _transfer {
}); });
} }
get_key(): transfer.DownloadKey { get_key(): DownloadKey {
return this.key; return this.key;
} }
@ -89,8 +86,8 @@ namespace _transfer {
} }
} }
class NativeFileUpload implements transfer.UploadTransfer { class NativeFileUpload implements UploadTransfer {
readonly transfer_key: transfer.UploadKey; readonly transfer_key: UploadKey;
private _handle: native.ft.NativeFileTransfer; private _handle: native.ft.NativeFileTransfer;
private _result: Promise<void>; private _result: Promise<void>;
@ -98,7 +95,7 @@ namespace _transfer {
private _result_success: () => any; private _result_success: () => any;
private _result_error: (error: any) => any; private _result_error: (error: any) => any;
constructor(key: transfer.UploadKey) { constructor(key: UploadKey) {
this.transfer_key = key; this.transfer_key = key;
} }
@ -167,20 +164,17 @@ namespace _transfer {
})); }));
} }
get_key(): transfer.UploadKey { get_key(): UploadKey {
return this.transfer_key; return this.transfer_key;
} }
} }
export function spawn_download_transfer(key: transfer.DownloadKey) : transfer.DownloadTransfer { export function spawn_download_transfer(key: DownloadKey) : DownloadTransfer {
return new NativeFileDownload(key); return new NativeFileDownload(key);
} }
export function spawn_upload_transfer(key: transfer.UploadKey) : transfer.UploadTransfer { export function spawn_upload_transfer(key: UploadKey) : UploadTransfer {
return new NativeFileUpload(key); return new NativeFileUpload(key);
} }
}
Object.assign(window["transfer"] || (window["transfer"] = {} as any), _transfer);

View File

@ -1,19 +1,22 @@
/// <reference path="../imports/imports_shared.d.ts" /> import {AbstractCommandHandler, AbstractCommandHandlerBoss} from "tc-shared/connection/AbstractCommandHandler";
window["require_setup"](module);
import { import {
destroy_server_connection as _destroy_server_connection, AbstractServerConnection, CommandOptionDefaults, CommandOptions,
NativeServerConnection, ConnectionStateListener,
ServerType, ServerCommand,
spawn_server_connection as _spawn_server_connection voice
} from "teaclient_connection"; } from "tc-shared/connection/ConnectionBase";
import {_audio} from "./VoiceConnection"; import {CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
import {tr} from "tc-shared/i18n/localize";
import {ConnectionHandler, ConnectionState, DisconnectReason} from "tc-shared/ConnectionHandler";
import {NativeServerConnection, ServerType, spawn_server_connection as spawn_native_server_connection, destroy_server_connection as destroy_native_server_connection} from "tc-native/connection";
import {ConnectionCommandHandler} from "tc-shared/connection/CommandHandler";
import {HandshakeHandler} from "tc-shared/connection/HandshakeHandler";
import {ServerAddress} from "tc-shared/ui/server";
import {TeaSpeakHandshakeHandler} from "tc-shared/profiles/identities/TeamSpeakIdentity";
import AbstractVoiceConnection = voice.AbstractVoiceConnection;
import {VoiceConnection} from "./VoiceConnection";
export namespace _connection { class ErrorCommandHandler extends AbstractCommandHandler {
export namespace native {
import VoiceConnection = _audio.native.VoiceConnection;
class ErrorCommandHandler extends connection.AbstractCommandHandler {
private _handle: ServerConnection; private _handle: ServerConnection;
constructor(handle: ServerConnection) { constructor(handle: ServerConnection) {
@ -21,7 +24,7 @@ export namespace _connection {
this._handle = handle; this._handle = handle;
} }
handle_command(command: connection.ServerCommand): boolean { handle_command(command: ServerCommand): boolean {
if(command.command === "error") { if(command.command === "error") {
const return_listener: {[key: string]: (result: CommandResult) => any} = this._handle["_return_listener"]; const return_listener: {[key: string]: (result: CommandResult) => any} = this._handle["_return_listener"];
const data = command.arguments[0]; const data = command.arguments[0];
@ -107,7 +110,7 @@ export namespace _connection {
} }
} }
export class ServerConnection extends connection.AbstractServerConnection { export class ServerConnection extends AbstractServerConnection {
private _native_handle: NativeServerConnection; private _native_handle: NativeServerConnection;
private _voice_connection: VoiceConnection; private _voice_connection: VoiceConnection;
@ -116,26 +119,26 @@ export namespace _connection {
private _command_handler: NativeConnectionCommandBoss; private _command_handler: NativeConnectionCommandBoss;
private _command_error_handler: ErrorCommandHandler; private _command_error_handler: ErrorCommandHandler;
private _command_handler_default: connection.ConnectionCommandHandler; private _command_handler_default: ConnectionCommandHandler;
private _remote_address: ServerAddress; private _remote_address: ServerAddress;
private _handshake_handler: connection.HandshakeHandler; private _handshake_handler: HandshakeHandler;
private _return_code_index: number = 0; private _return_code_index: number = 0;
onconnectionstatechanged: connection.ConnectionStateListener; onconnectionstatechanged: ConnectionStateListener;
constructor(props: ConnectionHandler) { constructor(props: ConnectionHandler) {
super(props); super(props);
this._command_handler = new NativeConnectionCommandBoss(this); this._command_handler = new NativeConnectionCommandBoss(this);
this._command_error_handler = new ErrorCommandHandler(this); this._command_error_handler = new ErrorCommandHandler(this);
this._command_handler_default = new connection.ConnectionCommandHandler(this); this._command_handler_default = new ConnectionCommandHandler(this);
this._command_handler.register_handler(this._command_error_handler); this._command_handler.register_handler(this._command_error_handler);
this._command_handler.register_handler(this._command_handler_default); this._command_handler.register_handler(this._command_handler_default);
this._native_handle = _spawn_server_connection(); this._native_handle = spawn_native_server_connection();
this._native_handle.callback_disconnect = reason => { this._native_handle.callback_disconnect = reason => {
this.client.handleDisconnect(DisconnectReason.CONNECTION_CLOSED, { this.client.handleDisconnect(DisconnectReason.CONNECTION_CLOSED, {
reason: reason, reason: reason,
@ -163,11 +166,11 @@ export namespace _connection {
finalize() { finalize() {
if(this._native_handle) if(this._native_handle)
_destroy_server_connection(this._native_handle); destroy_native_server_connection(this._native_handle);
this._native_handle = undefined; this._native_handle = undefined;
} }
connect(address: ServerAddress, handshake: connection.HandshakeHandler, timeout?: number): Promise<void> { connect(address: ServerAddress, handshake: HandshakeHandler, timeout?: number): Promise<void> {
this._remote_address = address; this._remote_address = address;
this._handshake_handler = handshake; this._handshake_handler = handshake;
this._do_teamspeak = false; this._do_teamspeak = false;
@ -199,7 +202,7 @@ export namespace _connection {
} }
}, },
identity_key: (handshake.get_identity_handler() as profiles.identities.TeaSpeakHandshakeHandler).identity.private_key, identity_key: (handshake.get_identity_handler() as TeaSpeakHandshakeHandler).identity.private_key,
teamspeak: false teamspeak: false
}) })
}); });
@ -210,7 +213,7 @@ export namespace _connection {
return this._remote_address; return this._remote_address;
} }
handshake_handler(): connection.HandshakeHandler { handshake_handler(): HandshakeHandler {
return this._handshake_handler; return this._handshake_handler;
} }
@ -232,11 +235,11 @@ export namespace _connection {
return true; return true;
} }
voice_connection(): connection.voice.AbstractVoiceConnection { voice_connection(): AbstractVoiceConnection {
return this._voice_connection; return this._voice_connection;
} }
command_handler_boss(): connection.AbstractCommandHandlerBoss { command_handler_boss(): AbstractCommandHandlerBoss {
return this._command_handler; return this._command_handler;
} }
@ -244,14 +247,14 @@ export namespace _connection {
return (this._return_code_index++).toString(); return (this._return_code_index++).toString();
} }
send_command(command: string, data?: any, _options?: connection.CommandOptions): Promise<CommandResult> { send_command(command: string, data?: any, _options?: CommandOptions): Promise<CommandResult> {
if(!this.connected()) { if(!this.connected()) {
console.warn(tr("Tried to send a command without a valid connection.")); console.warn(tr("Tried to send a command without a valid connection."));
return Promise.reject(tr("not connected")); return Promise.reject(tr("not connected"));
} }
const options: connection.CommandOptions = {}; const options: CommandOptions = {};
Object.assign(options, connection.CommandOptionDefaults); Object.assign(options, CommandOptionDefaults);
Object.assign(options, _options); Object.assign(options, _options);
data = $.isArray(data) ? data : [data || {}]; data = $.isArray(data) ? data : [data || {}];
@ -293,26 +296,23 @@ export namespace _connection {
}; };
} }
} }
}
export class NativeConnectionCommandBoss extends connection.AbstractCommandHandlerBoss { export class NativeConnectionCommandBoss extends AbstractCommandHandlerBoss {
constructor(connection: connection.AbstractServerConnection) { constructor(connection: AbstractServerConnection) {
super(connection); super(connection);
} }
} }
/* override the "normal" connection */ /* override the "normal" connection */
export function spawn_server_connection(handle: ConnectionHandler) : connection.AbstractServerConnection { export function spawn_server_connection(handle: ConnectionHandler) : AbstractServerConnection {
console.log("Spawning native connection"); console.log("Spawning native connection");
return new native.ServerConnection(handle); /* will be overridden by the client */ return new ServerConnection(handle); /* will be overridden by the client */
} }
export function destroy_server_connection(handle: connection.AbstractServerConnection) { export function destroy_server_connection(handle: AbstractServerConnection) {
if(!(handle instanceof native.ServerConnection)) if(!(handle instanceof ServerConnection))
throw "invalid handle"; throw "invalid handle";
//TODO: Here! //TODO: Here!
console.log("Call to destroy a server connection"); console.log("Call to destroy a server connection");
} }
}
Object.assign(window["connection"] || (window["connection"] = {} as any), _connection);

View File

@ -1,16 +1,16 @@
import {_connection} from "./ServerConnection"; import {voice} from "tc-shared/connection/ConnectionBase";
import {_audio as _recorder} from "../audio/AudioRecorder"; import AbstractVoiceConnection = voice.AbstractVoiceConnection;
import {ServerConnection} from "./ServerConnection";
import {NativeVoiceConnection} from "tc-native/connection";
import {RecorderProfile} from "tc-shared/voice/RecorderProfile";
import {tr} from "tc-shared/i18n/localize";
import {LogCategory} from "tc-shared/log";
import * as log from "tc-shared/log";
import VoiceClient = voice.VoiceClient;
import LatencySettings = voice.LatencySettings;
import {NativeInput} from "../audio/AudioRecorder";
import { export class VoiceConnection extends AbstractVoiceConnection {
NativeVoiceConnection,
NativeVoiceClient
} from "teaclient_connection";
export namespace _audio {
export namespace native {
import ServerConnection = _connection.native.ServerConnection;
export class VoiceConnection extends connection.voice.AbstractVoiceConnection {
readonly connection: ServerConnection; readonly connection: ServerConnection;
readonly handle: NativeVoiceConnection; readonly handle: NativeVoiceConnection;
@ -32,7 +32,7 @@ export namespace _audio {
await this._audio_source.unmount(); await this._audio_source.unmount();
if(recorder) { if(recorder) {
if(!(recorder.input instanceof _recorder.recorder.NativeInput)) if(!(recorder.input instanceof NativeInput))
throw "Recorder input must be an instance of NativeInput!"; throw "Recorder input must be an instance of NativeInput!";
await recorder.unmount(); await recorder.unmount();
} }
@ -56,7 +56,7 @@ export namespace _audio {
this.connection.client.update_voice_status(undefined); this.connection.client.update_voice_status(undefined);
}; };
this.handle.set_audio_source((recorder.input as _recorder.recorder.NativeInput).consumer); this.handle.set_audio_source((recorder.input as NativeInput).consumer);
} }
this.connection.client.update_voice_status(undefined); this.connection.client.update_voice_status(undefined);
} }
@ -114,7 +114,7 @@ export namespace _audio {
return this._audio_source; return this._audio_source;
} }
available_clients(): connection.voice.VoiceClient[] { available_clients(): VoiceClient[] {
return this.handle.available_clients().map(e => Object.assign(e, { return this.handle.available_clients().map(e => Object.assign(e, {
support_latency_settings() { return true; }, support_latency_settings() { return true; },
reset_latency_settings: function() { reset_latency_settings: function() {
@ -123,7 +123,7 @@ export namespace _audio {
stream.set_buffer_max_latency(0.2); stream.set_buffer_max_latency(0.2);
return this.latency_settings(); return this.latency_settings();
}, },
latency_settings: function (settings?: connection.voice.LatencySettings) : connection.voice.LatencySettings { latency_settings: function (settings?: LatencySettings) : LatencySettings {
const stream = this.get_stream(); const stream = this.get_stream();
if(typeof settings !== "undefined") { if(typeof settings !== "undefined") {
stream.set_buffer_latency(settings.min_buffer / 1000); stream.set_buffer_latency(settings.min_buffer / 1000);
@ -143,19 +143,19 @@ export namespace _audio {
})); }));
} }
find_client(client_id: number) : connection.voice.VoiceClient | undefined { find_client(client_id: number) : VoiceClient | undefined {
for(const client of this.available_clients()) for(const client of this.available_clients())
if(client.client_id === client_id) if(client.client_id === client_id)
return client; return client;
return undefined; return undefined;
} }
unregister_client(client: connection.voice.VoiceClient): Promise<void> { unregister_client(client: VoiceClient): Promise<void> {
this.handle.unregister_client(client.client_id); this.handle.unregister_client(client.client_id);
return Promise.resolve(); return Promise.resolve();
} }
register_client(client_id: number): connection.voice.VoiceClient { register_client(client_id: number): VoiceClient {
const client = this.handle.register_client(client_id); const client = this.handle.register_client(client_id);
const c = this.find_client(client_id); const c = this.find_client(client_id);
c.reset_latency_settings(); c.reset_latency_settings();
@ -178,5 +178,3 @@ export namespace _audio {
return this.handle.set_encoder_codec(codec); return this.handle.set_encoder_codec(codec);
} }
} }
}
}

View File

@ -1,7 +1,5 @@
import {class_to_image} from "./icon-helper"; import {class_to_image} from "./icon-helper";
import * as contextmenu from "tc-shared/ui/elements/ContextMenu";
window["require_setup"](module);
import * as electron from "electron"; import * as electron from "electron";
const remote = electron.remote; const remote = electron.remote;
const {Menu, MenuItem} = remote; const {Menu, MenuItem} = remote;
@ -124,5 +122,3 @@ class ElectronContextMenu implements contextmenu.ContextMenuProvider {
} }
contextmenu.set_provider(new ElectronContextMenu()); contextmenu.set_provider(new ElectronContextMenu());
export {};

View File

@ -1,11 +1,11 @@
/// <reference path="../imports/imports_shared.d.ts" /> import {ServerAddress} from "tc-shared/ui/server";
import * as loader from "tc-loader";
window["require_setup"](module); import {AddressTarget, ResolveOptions} from "tc-shared/dns";
import * as dns_handler from "teaclient_dns"; import * as dns_handler from "tc-native/dns";
namespace _dns {
export function supported() { return true; } export function supported() { return true; }
export async function resolve_address(address: ServerAddress, _options?: dns.ResolveOptions) : Promise<dns.AddressTarget> { export async function resolve_address(address: ServerAddress, _options?: ResolveOptions) : Promise<AddressTarget> {
/* backwards compatibility */ /* backwards compatibility */
if(typeof(address) === "string") { if(typeof(address) === "string") {
address = { address = {
@ -14,7 +14,7 @@ namespace _dns {
} }
} }
return new Promise<dns.AddressTarget>((resolve, reject) => { return new Promise<AddressTarget>((resolve, reject) => {
dns_handler.resolve_cr(address.host, address.port, result => { dns_handler.resolve_cr(address.host, address.port, result => {
if(typeof(result) === "string") if(typeof(result) === "string")
reject(result); reject(result);
@ -26,9 +26,7 @@ namespace _dns {
}); });
}) })
} }
}
Object.assign(window["dns"] || (window["dns"] = {} as any), _dns);
loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, { loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, {
name: "Native DNS initialized", name: "Native DNS initialized",
function: async () => { function: async () => {

View File

@ -33,7 +33,7 @@ export function class_to_image(klass: string) : NativeImage {
export async function initialize() { export async function initialize() {
if(!_div) { if(!_div) {
_div = $.spawn("div"); _div = $(document.createElement("div"));
_div.css('display', 'none'); _div.css('display', 'none');
_div.appendTo(document.body); _div.appendTo(document.body);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,97 +0,0 @@
/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/loader/loader.ts */
declare interface Window {
tr(message: string): string;
}
declare namespace loader {
export namespace config {
export const loader_groups;
export const verbose;
export const error;
}
export type Task = {
name: string;
priority: number; /* tasks with the same priority will be executed in sync */
function: () => Promise<void>;
};
export enum Stage {
/*
loading loader required files (incl this)
*/
INITIALIZING,
/*
setting up the loading process
*/
SETUP,
/*
loading all style sheet files
*/
STYLE,
/*
loading all javascript files
*/
JAVASCRIPT,
/*
loading all template files
*/
TEMPLATES,
/*
initializing static/global stuff
*/
JAVASCRIPT_INITIALIZING,
/*
finalizing load process
*/
FINALIZING,
/*
invoking main task
*/
LOADED,
DONE
}
export function get_cache_version();
export function finished();
export function running();
export function register_task(stage: Stage, task: Task);
export function execute(): Promise<any>;
export function execute_managed();
export type DependSource = {
url: string;
depends: string[];
};
export type SourcePath = string | DependSource | string[];
export class SyntaxError {
source: any;
constructor(source: any);
}
export function load_script(path: SourcePath): Promise<void>;
export function load_scripts(paths: SourcePath[]): Promise<void>;
export function load_style(path: SourcePath): Promise<void>;
export function load_styles(paths: SourcePath[]): Promise<void>;
export type ErrorHandler = (message: string, detail: string) => void;
export function critical_error(message: string, detail?: string);
export function critical_error_handler(handler?: ErrorHandler, override?: boolean): ErrorHandler;
}
declare let _fadeout_warned;
declare function fadeoutLoader(duration?, minAge?, ignoreAge?);
/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/loader/app.ts */
declare interface Window {
$: JQuery;
}
declare namespace app {
export enum Type {
UNKNOWN,
CLIENT_RELEASE,
CLIENT_DEBUG,
WEB_DEBUG,
WEB_RELEASE
}
export let type: Type;
export function is_web();
export function ui_version();
}
declare const loader_javascript;
declare const loader_webassembly;
declare const loader_style;
declare function load_templates(): Promise<any>;

View File

@ -1,2 +0,0 @@
imports_shared.d.ts
imports_shared_loader.d.ts

View File

@ -1,12 +1,7 @@
/// <reference path="imports/imports_shared.d.ts" /> /* --------------- bootstrap --------------- */
import * as rh from "./require-handler";
import {Arguments, parse_arguments, process_args} from "../shared/process-arguments";
import * as electron from "electron";
import {remote} from "electron";
import * as crash_handler from "../crash_handler"; import * as crash_handler from "../crash_handler";
import * as path from "path"; import * as path from "path";
import * as os from "os";
import ipcRenderer = electron.ipcRenderer;
/* first of all setup crash handler */ /* first of all setup crash handler */
{ {
@ -14,6 +9,8 @@ import ipcRenderer = electron.ipcRenderer;
crash_handler.initialize_handler("renderer", is_electron_run); crash_handler.initialize_handler("renderer", is_electron_run);
} }
/* some decls */
declare global {
interface Window { interface Window {
$: any; $: any;
jQuery: any; jQuery: any;
@ -25,36 +22,28 @@ interface Window {
open_connected_question: () => Promise<boolean>; open_connected_question: () => Promise<boolean>;
} }
}
rh.initialize(path.join(__dirname, "backend-impl"));
/* --------------- main initialize --------------- */
import {Arguments, parse_arguments, process_args} from "../shared/process-arguments";
import * as electron from "electron";
import {remote} from "electron";
import * as os from "os";
import * as loader from "tc-loader";
import ipcRenderer = electron.ipcRenderer;
declare const window: Window;
export const require_native: NodeRequireFunction = id => require(id);
export const initialize = async () => {
/* we use out own jquery resource */ /* we use out own jquery resource */
loader.register_task(loader.Stage.JAVASCRIPT, { loader.register_task(loader.Stage.JAVASCRIPT, {
name: "teaclient jquery", name: "teaclient jquery",
function: jquery_initialize, function: async () => {
window.$ = require("jquery");
window.jQuery = window.$;
Object.assign(window.$, window.jsrender = require('jsrender'));
},
priority: 80 priority: 80
}); });
loader.register_task(loader.Stage.JAVASCRIPT, {
name: "teaclient general",
function: load_basic_modules,
priority: 10
});
loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, {
name: "teaclient javascript init",
function: load_modules,
priority: 50
});
loader.register_task(loader.Stage.INITIALIZING, {
name: "teaclient initialize modules",
function: module_loader_setup,
priority: 60
});
loader.register_task(loader.Stage.INITIALIZING, { loader.register_task(loader.Stage.INITIALIZING, {
name: "teaclient initialize persistent storage", name: "teaclient initialize persistent storage",
function: async () => { function: async () => {
@ -66,13 +55,41 @@ export const initialize = async () => {
loader.register_task(loader.Stage.INITIALIZING, { loader.register_task(loader.Stage.INITIALIZING, {
name: "teaclient initialize logging", name: "teaclient initialize logging",
function: initialize_logging, function: async () => {
const logger = require("./logger");
logger.setup();
},
priority: 80 priority: 80
}); });
loader.register_task(loader.Stage.INITIALIZING, { loader.register_task(loader.Stage.INITIALIZING, {
name: "teaclient initialize error", name: "teaclient initialize error",
function: initialize_error_handler, function: async () => {
const _impl = message => {
if(!process_args.has_flag(Arguments.DEBUG)) {
console.error("Displaying critical error: %o", message);
message = message.replace(/<br>/i, "\n");
const win = remote.getCurrentWindow();
remote.dialog.showMessageBox({
type: "error",
buttons: ["exit"],
title: "A critical error happened!",
message: message
});
win.close();
} else {
console.error("Received critical error: %o", message);
console.error("Ignoring error due to the debug mode");
}
};
if(window.impl_display_critical_error)
window.impl_display_critical_error = _impl;
else
window.displayCriticalError = _impl;
},
priority: 100 priority: 100
}); });
@ -120,160 +137,27 @@ export const initialize = async () => {
ipcRenderer.send('basic-action', "parse-connect-arguments"); ipcRenderer.send('basic-action', "parse-connect-arguments");
}, },
priority: 0 priority: 0
})
};
const jquery_initialize = async () => {
window.$ = require("jquery");
window.jQuery = window.$;
Object.assign(window.$, window.jsrender = require('jsrender'));
};
const initialize_logging = async () => {
const logger = require("./logger");
logger.setup();
};
const initialize_error_handler = async () => {
const _impl = message => {
if(!process_args.has_flag(Arguments.DEBUG)) {
console.error("Displaying critical error: %o", message);
message = message.replace(/<br>/i, "\n");
const win = remote.getCurrentWindow();
remote.dialog.showMessageBox({
type: "error",
buttons: ["exit"],
title: "A critical error happened!",
message: message
}); });
win.close();
} else {
console.error("Received critical error: %o", message);
console.error("Ignoring error due to the debug mode");
}
};
if(window.impl_display_critical_error) loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, {
window.impl_display_critical_error = _impl; name: "teaclient load adapters",
else function: async () => {
window.displayCriticalError = _impl; /* all files which replaces a native driver */
};
const module_loader_setup = async () => {
const native_paths = (() => {
const app_path = (remote || electron).app.getAppPath();
const result = [];
result.push(app_path + "/native/build/" + os.platform() + "_" + os.arch() + "/");
if(app_path.endsWith(".asar"))
result.push(path.join(path.dirname(app_path), "natives"));
return result;
})();
window["require_setup"] = _mod => {
if(!_mod || !_mod.paths) return;
_mod.paths.push(...native_paths);
const original_require = _mod.__proto__.require;
if(!_mod.proxied) {
_mod.require = (path: string) => {
if(path.endsWith("imports/imports_shared")) {
console.log("Proxy require for %s. Using 'window' as result.", path);
return window;
}
return original_require.apply(_mod, [path]);
};
_mod.proxied = true;
}
};
};
const load_basic_modules = async () => {
require("./logger");
require("./audio/AudioPlayer"); /* setup audio */
require("./audio/AudioRecorder"); /* setup audio */
require("./audio/sounds"); /* setup audio */
};
const load_modules = async () => {
window["require_setup"](this);
console.log(module.paths);
console.log("Loading native extensions...");
try {
try { try {
require("./version"); require("./version");
} catch(error) {
console.error("Failed to load version extension");
console.dir(error);
throw error;
}
try {
require("./app_backend");
} catch(error) {
console.error("Failed to load renderer app backend");
console.dir(error);
throw error;
}
try {
const helper = require("./icon-helper");
await helper.initialize();
} catch(error) {
console.error("Failed to load the icon helper extension");
console.dir(error);
throw error;
}
try {
require("./ppt");
} catch(error) {
console.error("Failed to load ppt");
console.dir(error);
throw error;
}
try {
require("./connection/ServerConnection");
} catch(error) {
console.error("Failed to load server connection extension");
console.dir(error);
throw error;
}
try {
require("./connection/FileTransfer");
} catch(error) {
console.error("Failed to load file transfer extension");
console.dir(error);
throw error;
}
try {
require("./dns/dns_resolver");
} catch(error) {
console.error("Failed to load dns extension");
console.dir(error);
throw error;
}
try {
require("./menu"); require("./menu");
} catch(error) {
console.error("Failed to load menu extension");
console.dir(error);
throw error;
}
try {
require("./context-menu"); require("./context-menu");
} catch(error) { require("./app_backend");
console.error("Failed to load context menu extension"); require("./icon-helper").initialize();
console.dir(error);
throw error;
}
} catch (error) { } catch (error) {
console.log(error); console.log(error);
window.displayCriticalError("Failed to load native extensions: " + error); window.displayCriticalError("Failed to load native extensions: " + error);
throw error; throw error;
} }
console.log("Loaded native extensions");
remote.getCurrentWindow().on('focus', () => remote.getCurrentWindow().flashFrame(false)); remote.getCurrentWindow().on('focus', () => remote.getCurrentWindow().flashFrame(false));
// remote.getCurrentWindow().flashFrame(true); },
}; priority: 60
});
export async function initialize() { }

View File

@ -1,16 +1,10 @@
import {class_to_image} from "./icon-helper"; import {class_to_image} from "./icon-helper";
window["require_setup"](module);
import * as electron from "electron"; import * as electron from "electron";
//import {top_menu as dtop_menu, Icon} from "./imports/imports_shared"; import * as mbar from "tc-shared/ui/frames/MenuBar";
/// <reference types="./imports/import_shared.d.ts" />
import dtop_menu = top_menu;
import {Arguments, process_args} from "../shared/process-arguments"; import {Arguments, process_args} from "../shared/process-arguments";
namespace _top_menu {
import ipcRenderer = electron.ipcRenderer; import ipcRenderer = electron.ipcRenderer;
import {Icon} from "tc-shared/FileManager";
namespace native { namespace native {
import ipcRenderer = electron.ipcRenderer; import ipcRenderer = electron.ipcRenderer;
let _item_index = 1; let _item_index = 1;
@ -26,7 +20,7 @@ namespace _top_menu {
} }
abstract build() : electron.MenuItemConstructorOptions; abstract build() : electron.MenuItemConstructorOptions;
abstract items(): (dtop_menu.MenuItem | dtop_menu.HRItem)[]; abstract items(): (mbar.MenuItem | mbar.HRItem)[];
trigger_click() { trigger_click() {
if(this._click) if(this._click)
@ -34,7 +28,7 @@ namespace _top_menu {
} }
} }
class NativeMenuItem extends NativeMenuBase implements dtop_menu.MenuItem { class NativeMenuItem extends NativeMenuBase implements mbar.MenuItem {
private _items: (NativeMenuItem | NativeHrItem)[] = []; private _items: (NativeMenuItem | NativeHrItem)[] = [];
private _label: string; private _label: string;
private _enabled: boolean = true; private _enabled: boolean = true;
@ -47,13 +41,13 @@ namespace _top_menu {
} }
append_hr(): dtop_menu.HRItem { append_hr(): mbar.HRItem {
const item = new NativeHrItem(this._handle); const item = new NativeHrItem(this._handle);
this._items.push(item); this._items.push(item);
return item; return item;
} }
append_item(label: string): dtop_menu.MenuItem { append_item(label: string): mbar.MenuItem {
const item = new NativeMenuItem(this._handle); const item = new NativeMenuItem(this._handle);
item.label(label); item.label(label);
this._items.push(item); this._items.push(item);
@ -65,7 +59,7 @@ namespace _top_menu {
return this; return this;
} }
delete_item(item: dtop_menu.MenuItem | dtop_menu.HRItem) { delete_item(item: mbar.MenuItem | mbar.HRItem) {
const i_index = this._items.indexOf(item as any); const i_index = this._items.indexOf(item as any);
if(i_index < 0) return; if(i_index < 0) return;
this._items.splice(i_index, 1); this._items.splice(i_index, 1);
@ -86,7 +80,7 @@ namespace _top_menu {
return ""; return "";
} }
items(): (dtop_menu.MenuItem | dtop_menu.HRItem)[] { items(): (mbar.MenuItem | mbar.HRItem)[] {
return this._items; return this._items;
} }
@ -117,7 +111,7 @@ namespace _top_menu {
} }
} }
class NativeHrItem extends NativeMenuBase implements dtop_menu.HRItem { class NativeHrItem extends NativeMenuBase implements mbar.HRItem {
constructor(handle: NativeMenuBar) { constructor(handle: NativeMenuBar) {
super(handle); super(handle);
} }
@ -129,7 +123,7 @@ namespace _top_menu {
} }
} }
items(): (dtop_menu.MenuItem | dtop_menu.HRItem)[] { items(): (mbar.MenuItem | mbar.HRItem)[] {
return []; return [];
} }
} }
@ -157,7 +151,7 @@ namespace _top_menu {
} }
export class NativeMenuBar implements dtop_menu.MenuBarDriver { export class NativeMenuBar implements mbar.MenuBarDriver {
private static _instance: NativeMenuBar; private static _instance: NativeMenuBar;
private menu: electron.Menu; private menu: electron.Menu;
@ -170,14 +164,14 @@ namespace _top_menu {
return this._instance; return this._instance;
} }
append_item(label: string): dtop_menu.MenuItem { append_item(label: string): mbar.MenuItem {
const item = new NativeMenuItem(this); const item = new NativeMenuItem(this);
item.label(label); item.label(label);
this._items.push(item); this._items.push(item);
return item; return item;
} }
delete_item(item: dtop_menu.MenuItem) { delete_item(item: mbar.MenuItem) {
const i_index = this._items.indexOf(item as any); const i_index = this._items.indexOf(item as any);
if(i_index < 0) return; if(i_index < 0) return;
this._items.splice(i_index, 1); this._items.splice(i_index, 1);
@ -196,7 +190,7 @@ namespace _top_menu {
return this._items.map(e => e.build()); return this._items.map(e => e.build());
} }
items(): dtop_menu.MenuItem[] { items(): mbar.MenuItem[] {
return this._items; return this._items;
} }
@ -222,13 +216,9 @@ namespace _top_menu {
} }
} }
//Global variable mbar.set_driver(native.NativeMenuBar.instance());
// @ts-ignore // @ts-ignore
top_menu.set_driver(native.NativeMenuBar.instance()); mbar.native_actions = {
const call_basic_action = (name: string, ...args: any[]) => ipcRenderer.send('basic-action', name, ...args);
top_menu.native_actions = {
open_change_log() { open_change_log() {
call_basic_action("open-changelog"); call_basic_action("open-changelog");
}, },
@ -251,7 +241,6 @@ namespace _top_menu {
show_dev_tools() { return process_args.has_flag(Arguments.DEV_TOOLS); } show_dev_tools() { return process_args.has_flag(Arguments.DEV_TOOLS); }
}; };
}
export {}; const call_basic_action = (name: string, ...args: any[]) => ipcRenderer.send('basic-action', name, ...args);

View File

@ -1,15 +1,16 @@
window["require_setup"](module); import {KeyEvent as NKeyEvent, RegisterCallback, UnregisterCallback} from "tc-native/ppt";
import {EventType, KeyEvent, KeyHook, SpecialKey} from "tc-shared/PPTListener";
import {tr} from "tc-shared/i18n/localize";
import {LogCategory} from "tc-shared/log";
import * as log from "tc-shared/log";
import {KeyEvent as NKeyEvent} from "teaclient_ppt"; let key_listener: ((_: KeyEvent) => any)[] = [];
namespace _ppt {
let key_listener: ((_: ppt.KeyEvent) => any)[] = [];
let native_ppt; function listener_key(type: EventType, nevent: NKeyEvent) {
function listener_key(type: ppt.EventType, nevent: NKeyEvent) {
if(nevent.key_code === 'VoidSymbol' || nevent.key_code === 'error') if(nevent.key_code === 'VoidSymbol' || nevent.key_code === 'error')
nevent.key_code = undefined; /* trigger event for state update */ nevent.key_code = undefined; /* trigger event for state update */
let event: ppt.KeyEvent = { let event: KeyEvent = {
type: type, type: type,
key: nevent.key_code, key: nevent.key_code,
@ -30,61 +31,60 @@ namespace _ppt {
//console.log("Native event!: %o", event); //console.log("Native event!: %o", event);
if(event.type == 0) if(event.type == 0)
listener_key(ppt.EventType.KEY_PRESS, event); listener_key(EventType.KEY_PRESS, event);
else if(event.type == 1) else if(event.type == 1)
listener_key(ppt.EventType.KEY_RELEASE, event); listener_key(EventType.KEY_RELEASE, event);
else if(event.type == 2) else if(event.type == 2)
listener_key(ppt.EventType.KEY_TYPED, event); listener_key(EventType.KEY_TYPED, event);
else else
console.warn(tr("Received unknown native event: %o"), event); console.warn(tr("Received unknown native event: %o"), event);
} }
export async function initialize() : Promise<void> { export async function initialize() : Promise<void> {
native_ppt = require("teaclient_ppt");
register_key_listener(listener_hook); register_key_listener(listener_hook);
native_ppt.RegisterCallback(native_keyhook); RegisterCallback(native_keyhook);
} }
export function finalize() { export function finalize() {
unregister_key_listener(listener_hook); unregister_key_listener(listener_hook);
native_ppt.UnregisterCallback(native_keyhook); UnregisterCallback(native_keyhook);
} }
export function register_key_listener(listener: (_: ppt.KeyEvent) => any) { export function register_key_listener(listener: (_: KeyEvent) => any) {
key_listener.push(listener); key_listener.push(listener);
} }
export function unregister_key_listener(listener: (_: ppt.KeyEvent) => any) { export function unregister_key_listener(listener: (_: KeyEvent) => any) {
key_listener.remove(listener); const index = key_listener.findIndex(e => e === listener);
if(index !== -1) key_listener.splice(index, 1);
} }
let key_hooks: ppt.KeyHook[] = []; let key_hooks: KeyHook[] = [];
interface CurrentState { interface CurrentState {
keys: {[code: string]:ppt.KeyEvent}; keys: {[code: string]:KeyEvent};
special: { [key:number]:boolean }; special: { [key:number]:boolean };
} }
let current_state: CurrentState = { let current_state: CurrentState = {
special: [] special: []
} as any; } as any;
let key_hooks_active: ppt.KeyHook[] = []; let key_hooks_active: KeyHook[] = [];
function listener_hook(event: ppt.KeyEvent) { function listener_hook(event: KeyEvent) {
if(event.type == ppt.EventType.KEY_TYPED) if(event.type == EventType.KEY_TYPED)
return; return;
let old_hooks = [...key_hooks_active]; let old_hooks = [...key_hooks_active];
let new_hooks = []; let new_hooks = [];
current_state.special[ppt.SpecialKey.ALT] = event.key_alt; current_state.special[SpecialKey.ALT] = event.key_alt;
current_state.special[ppt.SpecialKey.CTRL] = event.key_ctrl; current_state.special[SpecialKey.CTRL] = event.key_ctrl;
current_state.special[ppt.SpecialKey.SHIFT] = event.key_shift; current_state.special[SpecialKey.SHIFT] = event.key_shift;
current_state.special[ppt.SpecialKey.WINDOWS] = event.key_windows; current_state.special[SpecialKey.WINDOWS] = event.key_windows;
current_state[event.key_code] = undefined; current_state[event.key_code] = undefined;
if(event.type == ppt.EventType.KEY_PRESS) { if(event.type == EventType.KEY_PRESS) {
current_state[event.key_code] = event; current_state[event.key_code] = event;
for(const hook of key_hooks) { for(const hook of key_hooks) {
@ -95,7 +95,9 @@ namespace _ppt {
if(hook.key_windows != event.key_windows) continue; if(hook.key_windows != event.key_windows) continue;
new_hooks.push(hook); new_hooks.push(hook);
if(!old_hooks.remove(hook) && hook.callback_press) { const index = old_hooks.findIndex(e => e === hook);
if(index !== -1 && hook.callback_press) {
old_hooks.splice(index, 1);
hook.callback_press(); hook.callback_press();
log.trace(LogCategory.GENERAL, tr("Trigger key press for %o!"), hook); log.trace(LogCategory.GENERAL, tr("Trigger key press for %o!"), hook);
} }
@ -118,20 +120,22 @@ namespace _ppt {
} }
export function register_key_hook(hook: ppt.KeyHook) { export function register_key_hook(hook: KeyHook) {
key_hooks.push(hook); key_hooks.push(hook);
} }
export function unregister_key_hook(hook: ppt.KeyHook) { export function unregister_key_hook(hook: KeyHook) {
key_hooks.remove(hook); let index;
key_hooks_active.remove(hook);
index = key_hooks.findIndex(e => e === hook);
if(index !== -1) key_hooks.splice(index, 1);
index = key_hooks_active.findIndex(e => e === hook);
if(index !== -1) key_hooks_active.splice(index, 1);
} }
export function key_pressed(code: string | ppt.SpecialKey) : boolean { export function key_pressed(code: string | SpecialKey) : boolean {
if(typeof(code) === 'string') if(typeof(code) === 'string')
return typeof(current_state[code]) === "object"; return typeof(current_state[code]) === "object";
return current_state.special[code]; return current_state.special[code];
} }
}
Object.assign(window["ppt"] || (window["ppt"] = {} as any), _ppt);
console.dir(_ppt);

View File

@ -0,0 +1,106 @@
import * as path from "path";
import {remote} from "electron";
import * as electron from "electron";
import * as os from "os";
const Module = require("module");
interface ModuleOverride {
name?: string,
test: string | RegExp | ((request: string) => boolean);
callback: (this: string, request: string, parent?: NodeJS.Module) => any;
}
const overrides: ModuleOverride[] = [];
function proxied_load(request: string, parent?: NodeJS.Module) {
for(const override of overrides) {
let test_satisfied = false;
if(typeof override.test === "string") {
test_satisfied = override.test === request;
} else if(typeof override.test === "function") {
test_satisfied = override.test(request);
} else if(typeof override === "object") {
if(override.test instanceof RegExp)
test_satisfied = !!request.match(override.test);
}
if(test_satisfied) {
//console.log("Using override %s for %s", override.name || "unnamed", request);
return override.callback.apply(this, arguments);
}
}
//console.log("No override found for %s", request);
return proxied_load.original_load.apply(this, arguments);
}
function shared_backend_loader(request: string) {
if(!request.startsWith("tc-backend/")) throw "invalid target";
const target = request.substr(11);
return require(path.join(backend_root, target));
}
namespace proxied_load {
export let original_load: typeof Module.require;
}
let backend_root: string;
export function initialize(backend_root_: string) {
backend_root = backend_root_;
proxied_load.original_load = Module._load;
Module._load = proxied_load;
window["backend-loader"] = {
require: shared_backend_loader
};
}
overrides.push({
name: "tc-loader",
test: "tc-loader",
callback: () => window["loader"]
});
overrides.push({
name: "native loader",
test: /^tc-native\/[a-zA-Z_-]+$/,
callback: request => {
const name = request.substr(10);
const file_mapping = {
connection: "teaclient_connection.node",
ppt: "teaclient_ppt.node",
dns: "teaclient_dns.node"
};
if(typeof file_mapping[name] !== "string")
throw "unknown native module";
const app_path = (remote || electron).app.getAppPath();
const target_path = path.join(app_path, "native", "build", os.platform() + "_" + os.arch(), file_mapping[name]);
return require(target_path);
}
});
overrides.push({
name: "shared loader",
test: /^tc-shared\/.*/,
callback: request => {
const webpack_path = path.dirname("shared/js/" + request.substr(10)); //FIXME: Get the prefix from a variable!
const loader = require("tc-loader");
const mapping = loader.module_mapping().find(e => e.application === "client-app"); //FIXME: Variable name!
if(!mapping) throw "missing mapping";
const entries = mapping.modules.filter(e => e.context === webpack_path);
if(!entries.length) throw "unknown target path";
const basename = path.basename(request, path.extname(request));
const entry = entries.find(e => path.basename(e.resource, path.extname(e.resource)) === basename);
if(!entry) throw "unknown import";
return window["shared-require"](entry.id);
}
});

View File

@ -1,3 +1,4 @@
//FIXME!
namespace native { namespace native {
const remote = require('electron').remote; const remote = require('electron').remote;
export async function client_version() : Promise<string> { export async function client_version() : Promise<string> {

View File

@ -1,4 +1,4 @@
declare module "teaclient_dns" { declare module "tc-native/dns" {
export function resolve_cr(host: string, port: number, callback: (result: string | {host: string, port: number}) => any); export function resolve_cr(host: string, port: number, callback: (result: string | {host: string, port: number}) => any);
export function initialize(); export function initialize();
} }

View File

@ -1,4 +1,4 @@
declare module "teaclient_ppt" { declare module "tc-native/ppt" {
enum KeyEventType { enum KeyEventType {
PRESS = 0, PRESS = 0,
RELEASE = 1, RELEASE = 1,

View File

@ -1,4 +1,4 @@
declare module "teaclient_connection" { declare module "tc-native/connection" {
export enum ServerType { export enum ServerType {
UNKNOWN, UNKNOWN,
TEASPEAK, TEASPEAK,

View File

@ -139,6 +139,7 @@ void ProtocolHandler::execute_resend() {
this->handle->close_connection(); this->handle->close_connection();
return; return;
} }
log_trace(category::connection, tr("Resended {}"), resended);
auto socket = this->handle->get_socket(); auto socket = this->handle->get_socket();
if(socket) { if(socket) {
@ -164,6 +165,7 @@ void ProtocolHandler::progress_packet(const pipes::buffer_view &buffer) {
auto packet_type = packet->type(); auto packet_type = packet->type();
auto packet_id = packet->packetId(); auto packet_id = packet->packetId();
auto ordered = packet_type.type() == protocol::COMMAND || packet_type.type() == protocol::COMMAND_LOW; auto ordered = packet_type.type() == protocol::COMMAND || packet_type.type() == protocol::COMMAND_LOW;
log_trace(category::connection, tr("Received packet {} with id {}"), packet->type().name(), packet->packetId());
/* special handling */ /* special handling */
if(packet_type.type() == protocol::INIT1) { if(packet_type.type() == protocol::INIT1) {
@ -253,6 +255,7 @@ void ProtocolHandler::progress_packet(const pipes::buffer_view &buffer) {
unique_lock queue_lock(read_queue.buffer_lock); unique_lock queue_lock(read_queue.buffer_lock);
if(ordered) { /* ordered */ if(ordered) { /* ordered */
log_trace(category::connection, tr("Inserting packet {} with id {}"), packet->type().name(), packet->packetId());
if(!read_queue.insert_index(packet_id, std::forward<shared_ptr<ServerPacket>>(packet))) { if(!read_queue.insert_index(packet_id, std::forward<shared_ptr<ServerPacket>>(packet))) {
log_warn(category::connection, tr("Failed to insert ordered packet into queue. ({} | {} | {})"), packet_type.name(), read_queue.current_index(), packet_id); log_warn(category::connection, tr("Failed to insert ordered packet into queue. ({} | {} | {})"), packet_type.name(), read_queue.current_index(), packet_id);
} }
@ -519,7 +522,7 @@ bool ProtocolHandler::create_datagram_packets(std::vector<pipes::buffer> &result
void ProtocolHandler::send_command(const ts::Command &cmd, const std::function<void(bool)> &ack_callback) { void ProtocolHandler::send_command(const ts::Command &cmd, const std::function<void(bool)> &ack_callback) {
auto data = cmd.build(); auto data = cmd.build();
auto packet = make_shared<ClientPacket>(PacketTypeInfo::Command, pipes::buffer_view{data.data(), data.size()}); auto packet = make_shared<ClientPacket>(PacketTypeInfo::Command, pipes::buffer_view{data.data(), data.size()});
if(ack_callback) { if(ack_callback || true) {
auto begin = chrono::system_clock::now(); auto begin = chrono::system_clock::now();
packet->setListener(make_unique<threads::Future<bool>>()); packet->setListener(make_unique<threads::Future<bool>>());
packet->getListener()->waitAndGetLater([ack_callback, begin](bool f) { packet->getListener()->waitAndGetLater([ack_callback, begin](bool f) {
@ -527,7 +530,7 @@ void ProtocolHandler::send_command(const ts::Command &cmd, const std::function<v
if(ack_callback) if(ack_callback)
ack_callback(f); ack_callback(f);
log_trace(category::connection, tr("Time needed for command: {}"), chrono::duration_cast<chrono::milliseconds>(end - begin).count()); log_trace(category::connection, tr("Time needed for command: {}ms. Success: {}"), chrono::duration_cast<chrono::milliseconds>(end - begin).count(), f);
}); });
} }
packet->enable_flag(PacketFlag::NewProtocol); packet->enable_flag(PacketFlag::NewProtocol);
@ -541,6 +544,18 @@ void ProtocolHandler::send_packet(const std::shared_ptr<ts::protocol::ClientPack
return; return;
} }
{
if(packet->type() == protocol::PacketTypeInfo::Command && this->connection_state == connection_state::CONNECTED && false) {
ts::Command cmd{"whoami"};
auto data = cmd.build();
auto p1 = make_shared<ClientPacket>(PacketTypeInfo::Command, pipes::buffer_view{data.data(), data.size()});
if(!this->create_datagram_packets(result, p1))
log_error(category::connection, tr("failed to encode trap"));
std::reverse(result.begin(), result.end());
}
}
log_trace(category::connection, tr("Split up {} {} to {} packets. Ack waiting: {}"), packet->packetId(), packet->type().name(), result.size(), this->acknowledge_handler.awaiting_acknowledge());
auto socket = this->handle->get_socket(); auto socket = this->handle->get_socket();
if(!socket) { if(!socket) {
log_error(category::connection, tr("Failed to get socket!")); log_error(category::connection, tr("Failed to get socket!"));

View File

@ -1,7 +1,5 @@
#include "ProtocolHandler.h" #include "ProtocolHandler.h"
#include "ServerConnection.h"
#include "Socket.h" #include "Socket.h"
#include <protocol/buffers.h>
#include <thread> #include <thread>
#include <iostream> #include <iostream>
#include <tomcrypt.h> #include <tomcrypt.h>
@ -21,7 +19,9 @@ using namespace ts;
void ProtocolHandler::handlePacketAck(const std::shared_ptr<ts::protocol::ServerPacket> &ack) { void ProtocolHandler::handlePacketAck(const std::shared_ptr<ts::protocol::ServerPacket> &ack) {
string error; string error;
log_trace(category::connection, tr("Handle packet acknowledge for {}"), be2le16(&ack->data()[0])); log_trace(category::connection, tr("Handle packet acknowledge for {}"), be2le16(&ack->data()[0]));
this->acknowledge_handler.process_acknowledge(ack->type().type(), ack->data(), error); if(!this->acknowledge_handler.process_acknowledge(ack->type().type(), ack->data(), error)) {
log_warn(category::connection, tr("Failed to handle acknowledge {}: {}"), be2le16(&ack->data()[0]) ,error);
}
} }
void ProtocolHandler::handlePacketCommand(const std::shared_ptr<ts::protocol::ServerPacket> &packet) { void ProtocolHandler::handlePacketCommand(const std::shared_ptr<ts::protocol::ServerPacket> &packet) {

View File

@ -496,6 +496,7 @@ NAN_METHOD(ServerConnection::send_command) {
cmd[strobf("hwid").string()] = system_uuid(); /* we dont want anybody to patch this out */ cmd[strobf("hwid").string()] = system_uuid(); /* we dont want anybody to patch this out */
} }
} }
log_trace(category::audio, tr("Sending data {}"), cmd.command());
this->protocol_handler->send_command(cmd); this->protocol_handler->send_command(cmd);
auto end = chrono::system_clock::now(); auto end = chrono::system_clock::now();
} }

245
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "TeaClient", "name": "TeaClient",
"version": "1.4.3-2", "version": "1.4.4",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -17,6 +17,18 @@
"got": "^9.6.0", "got": "^9.6.0",
"sanitize-filename": "^1.6.2", "sanitize-filename": "^1.6.2",
"sumchecker": "^3.0.1" "sumchecker": "^3.0.1"
},
"dependencies": {
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
}
} }
}, },
"@sindresorhus/is": { "@sindresorhus/is": {
@ -383,6 +395,11 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
}, },
"at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
},
"atob": { "atob": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
@ -777,23 +794,104 @@
} }
}, },
"chokidar": { "chokidar": {
"version": "2.1.8", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz",
"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==",
"dev": true,
"requires": {
"anymatch": "~3.1.1",
"braces": "~3.0.2",
"fsevents": "~2.1.2",
"glob-parent": "~5.1.0",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.3.0"
},
"dependencies": {
"anymatch": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
"dev": true, "dev": true,
"requires": { "requires": {
"anymatch": "^2.0.0",
"async-each": "^1.0.1",
"braces": "^2.3.2",
"fsevents": "^1.2.7",
"glob-parent": "^3.1.0",
"inherits": "^2.0.3",
"is-binary-path": "^1.0.0",
"is-glob": "^4.0.0",
"normalize-path": "^3.0.0", "normalize-path": "^3.0.0",
"path-is-absolute": "^1.0.0", "picomatch": "^2.0.4"
"readdirp": "^2.2.1", }
"upath": "^1.1.1" },
"binary-extensions": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
"integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
"dev": true
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"fsevents": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
"integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
"dev": true,
"optional": true
},
"glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
},
"is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"requires": {
"binary-extensions": "^2.0.0"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"readdirp": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
"integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==",
"dev": true,
"requires": {
"picomatch": "^2.0.7"
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
}
} }
}, },
"chownr": { "chownr": {
@ -1489,9 +1587,9 @@
} }
}, },
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}, },
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
@ -1868,9 +1966,9 @@
} }
}, },
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true "dev": true
}, },
"ms": { "ms": {
@ -2026,9 +2124,9 @@
} }
}, },
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true "dev": true
}, },
"ms": { "ms": {
@ -2089,6 +2187,18 @@
"ora": "^3.4.0", "ora": "^3.4.0",
"spawn-rx": "^3.0.0", "spawn-rx": "^3.0.0",
"yargs": "^14.2.0" "yargs": "^14.2.0"
},
"dependencies": {
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
}
} }
}, },
"electron-winstaller": { "electron-winstaller": {
@ -2188,6 +2298,17 @@
"uuid": "^3.3.3" "uuid": "^3.3.3"
}, },
"dependencies": { "dependencies": {
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"dev": true,
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"klaw": { "klaw": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
@ -2553,13 +2674,30 @@
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
}, },
"fs-extra": { "fs-extra": {
"version": "8.1.0", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==",
"requires": { "requires": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0", "graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0", "jsonfile": "^6.0.1",
"universalify": "^0.1.0" "universalify": "^1.0.0"
},
"dependencies": {
"jsonfile": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
"integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^1.0.0"
}
},
"universalify": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
"integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="
}
} }
}, },
"fs-minipass": { "fs-minipass": {
@ -4232,9 +4370,9 @@
}, },
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
} }
} }
}, },
@ -4502,6 +4640,26 @@
"update-notifier": "^2.5.0" "update-notifier": "^2.5.0"
}, },
"dependencies": { "dependencies": {
"chokidar": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
"dev": true,
"requires": {
"anymatch": "^2.0.0",
"async-each": "^1.0.1",
"braces": "^2.3.2",
"fsevents": "^1.2.7",
"glob-parent": "^3.1.0",
"inherits": "^2.0.3",
"is-binary-path": "^1.0.0",
"is-glob": "^4.0.0",
"normalize-path": "^3.0.0",
"path-is-absolute": "^1.0.0",
"readdirp": "^2.2.1",
"upath": "^1.1.1"
}
},
"debug": { "debug": {
"version": "3.2.6", "version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
@ -4628,9 +4786,9 @@
} }
}, },
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}, },
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
@ -4981,6 +5139,12 @@
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
}, },
"picomatch": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
"dev": true
},
"pify": { "pify": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
@ -5143,9 +5307,9 @@
}, },
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
} }
} }
}, },
@ -6607,6 +6771,11 @@
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}, },
"v8-callsites": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/v8-callsites/-/v8-callsites-1.2.1.tgz",
"integrity": "sha1-PKTi3t9Q60ieNwVu1ksCVele84Y="
},
"validate-npm-package-license": { "validate-npm-package-license": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",

View File

@ -38,14 +38,14 @@
"asar": "^2.0.1", "asar": "^2.0.1",
"cmake-js": "^4.0.1", "cmake-js": "^4.0.1",
"ejs": "^2.7.1", "ejs": "^2.7.1",
"electron-installer-windows": "^1.1.1", "electron-installer-windows": "^1.1.0",
"electron-packager": "8.7.2", "electron-packager": "8.7.2",
"electron-winstaller": "^2.7.0", "electron-winstaller": "^2.7.0",
"electron-wix-msi": "^2.2.0", "electron-wix-msi": "^2.1.1",
"nodemon": "^1.19.4", "nodemon": "^1.19.4",
"platform-dependent-modules": "0.0.14", "platform-dependent-modules": "0.0.14",
"rc": "^1.2.8", "rc": "^1.2.8",
"rcedit": "^1.1.2", "rcedit": "^1.1.1",
"sass": "^1.23.2", "sass": "^1.23.2",
"typescript": "^3.7.2" "typescript": "^3.7.2"
}, },
@ -62,7 +62,7 @@
"electron-rebuild": "^1.8.6", "electron-rebuild": "^1.8.6",
"extend": "^3.0.2", "extend": "^3.0.2",
"extsprintf": "^1.4.0", "extsprintf": "^1.4.0",
"fs-extra": "^8.1.0", "fs-extra": "^9.0.0",
"http-signature": "^1.3.1", "http-signature": "^1.3.1",
"jquery": "^3.4.1", "jquery": "^3.4.1",
"json-stringify-safe": "^5.0.1", "json-stringify-safe": "^5.0.1",
@ -80,7 +80,8 @@
"safer-buffer": "^2.1.2", "safer-buffer": "^2.1.2",
"sshpk": "^1.16.1", "sshpk": "^1.16.1",
"tar-stream": "^2.1.0", "tar-stream": "^2.1.0",
"tough-cookie": "^3.0.1" "tough-cookie": "^3.0.1",
"v8-callsites": "latest"
}, },
"config": { "config": {
"platformDependentModules": { "platformDependentModules": {

View File

@ -6,7 +6,12 @@
"moduleResolution": "node", "moduleResolution": "node",
"rootDirs": [ "rootDirs": [
"modules" "modules"
] ],
"baseUrl": ".",
"paths": {
"tc-shared/*": ["imports/shared-app/*"],
"tc-loader": ["imports/loader"]
}
}, },
"exclude": [ "exclude": [
"node_modules", "node_modules",