Restructured project and fixed some minor issues

canary
WolverinDEV 2019-05-21 18:15:02 +02:00
parent 331fa4c505
commit a5365465a2
30 changed files with 251 additions and 182 deletions

View File

@ -1,4 +1,10 @@
# Changelog:
* **21.05.19**
- Restructured project
- Redesigned the audio input API (required for the client)
- Minifying release file
- Fixed travis builds
* **29.04.19**
- Added a master volume slider and separated it from the sounds master volume
- Saving changed sound and master volume settings

View File

@ -30,7 +30,7 @@
],
[ /* shared generated worker codec */
"type" => "js",
"search-pattern" => "/(WorkerCodec.js|WorkerPOW.js)$/",
"search-pattern" => "/(WorkerPOW.js)$/",
"build-target" => "dev|rel",
"path" => "js/workers/",
@ -188,6 +188,14 @@
];
$APP_FILE_LIST_WEB_SOURCE = [
[ /* web generated worker codec */
"type" => "js",
"search-pattern" => "/(WorkerCodec.js)$/",
"build-target" => "dev|rel",
"path" => "js/workers/",
"local-path" => "./web/js/workers/"
],
[ /* web javascript files (development mode only) */
"web-only" => true,
"type" => "js",
@ -200,7 +208,7 @@
[ /* web merged javascript files (shared inclusive) */
"web-only" => true,
"type" => "js",
"search-pattern" => "/.*\.js$/",
"search-pattern" => "/client(\.min)?\.js$/",
"build-target" => "rel",
"path" => "js/",

View File

@ -13,7 +13,8 @@
"trgen": "node tools/trgen/index.js",
"ttsc": "ttsc",
"csso": "csso",
"rebuild-structure-web-dev": "php files.php generate web dev"
"rebuild-structure-web-dev": "php files.php generate web dev",
"minify-web-rel-file": "minify web/generated/client.js --outFile web/generated/client.min.js --evaluate --removeDebugger --undefinedToVoid --mangle.keepClassName --deadcode.keepFnArgs"
},
"author": "TeaSpeak (WolverinDEV)",
"license": "ISC",
@ -24,6 +25,7 @@
"@types/node": "^9.4.6",
"@types/sha256": "^0.2.0",
"@types/websocket": "0.0.38",
"babel-minify": "^0.5.0",
"csso-cli": "^2.0.2",
"electron": "^3.0.2",
"gulp": "^3.9.1",

30
shared/backend/audio.d.ts vendored Normal file
View File

@ -0,0 +1,30 @@
declare namespace audio {
export namespace player {
export function initialize() : boolean;
export function initialized() : boolean;
export function context() : AudioContext;
export function get_master_volume() : number;
export function set_master_volume(volume: number);
export function destination() : AudioNode;
export function on_ready(cb: () => any);
export function available_devices() : Promise<Device[]>;
export function set_device(device_id: string) : Promise<void>;
export function current_device() : Device;
export function initializeFromGesture();
}
export namespace recorder {
export function devices() : InputDevice[];
export function device_refresh_available() : boolean;
export function refresh_devices() : Promise<void>;
export function create_input() : AbstractInput;
}
}

3
shared/backend/connection.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
declare namespace connection {
export function spawn_server_connection(handle: ConnectionHandler) : AbstractServerConnection;
}

8
shared/backend/forum.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
/* only available for the client */
declare namespace forum {
export function register_callback(callback: () => any);
export function open();
export function logout();
export function sync_main();
}

12
shared/backend/ppt.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
declare namespace ppt {
export function initialize() : Promise<void>;
export function finalize(); // most the times not really required
export function register_key_listener(listener: (_: KeyEvent) => any);
export function unregister_key_listener(listener: (_: KeyEvent) => any);
export function register_key_hook(hook: KeyHook);
export function unregister_key_hook(hook: KeyHook);
export function key_pressed(code: string | SpecialKey) : boolean;
}

2
shared/backend/readme.md Normal file
View File

@ -0,0 +1,2 @@
This folder contains declarations files which are required to be implemented
Else the UI shared pack wound work

View File

@ -1,5 +1,4 @@
/// <reference path="log.ts" />
/// <reference path="voice/VoiceClient.ts" />
/// <reference path="proto.ts" />
/// <reference path="ui/view.ts" />
/// <reference path="settings.ts" />

View File

@ -49,17 +49,4 @@ namespace ppt {
result += " + " + (key.key_code ? key.key_code : tr("unset"));
return result.substr(3);
}
/*
export declare function initialize() : Promise<void>;
export declare function finalize(); // most the times not really required
export declare function register_key_listener(listener: (_: KeyEvent) => any);
export declare function unregister_key_listener(listener: (_: KeyEvent) => any);
export declare function register_key_hook(hook: KeyHook);
export declare function unregister_key_hook(hook: KeyHook);
export declare function key_pressed(code: string | SpecialKey) : boolean;
*/
}

8
shared/js/audio/audio.ts Normal file
View File

@ -0,0 +1,8 @@
namespace audio {
export namespace player {
export interface Device {
device_id: string;
name: string;
}
}
}

View File

@ -1,3 +1,4 @@
/// <reference path="ConnectionBase.ts" />
namespace connection {
export class ServerConnectionCommandBoss extends AbstractCommandHandlerBoss {
@ -119,10 +120,6 @@ namespace connection {
//We could setup the voice channel
if(this.connection.support_voice()) {
console.log(tr("Setting up voice"));
const connection = this.connection.voice_connection();
if(connection instanceof audio.js.VoiceConnection)
connection.createSession();
} else {
console.log(tr("Skipping voice setup (No voice bridge available)"));
}

View File

@ -0,0 +1,92 @@
enum ErrorID {
PERMISSION_ERROR = 2568,
EMPTY_RESULT = 0x0501,
PLAYLIST_IS_IN_USE = 0x2103
}
class CommandResult {
success: boolean;
id: number;
message: string;
extra_message: string;
json: any;
constructor(json) {
this.json = json;
this.id = parseInt(json["id"]);
this.message = json["msg"];
this.extra_message = "";
if(json["extra_msg"]) this.extra_message = json["extra_msg"];
this.success = this.id == 0;
}
}
interface ClientNameInfo {
//cluid=tYzKUryn\/\/Y8VBMf8PHUT6B1eiE= name=Exp clname=Exp cldbid=9
client_unique_id: string;
client_nickname: string;
client_database_id: number;
}
interface ClientNameFromUid {
promise: LaterPromise<ClientNameInfo[]>,
keys: string[],
response: ClientNameInfo[]
}
interface QueryListEntry {
username: string;
unique_id: string;
bounded_server: number;
}
interface QueryList {
flag_own: boolean;
flag_all: boolean;
queries: QueryListEntry[];
}
interface Playlist {
playlist_id: number;
playlist_bot_id: number;
playlist_title: string;
playlist_type: number;
playlist_owner_dbid: number;
playlist_owner_name: string;
needed_power_modify: number;
needed_power_permission_modify: number;
needed_power_delete: number;
needed_power_song_add: number;
needed_power_song_move: number;
needed_power_song_remove: number;
}
interface PlaylistInfo {
playlist_id: number,
playlist_title: string,
playlist_description: string,
playlist_type: number,
playlist_owner_dbid: number,
playlist_owner_name: string,
playlist_flag_delete_played: boolean,
playlist_flag_finished: boolean,
playlist_replay_mode: number,
playlist_current_song_id: number,
}
interface PlaylistSong {
song_id: number;
song_previous_song_id: number;
song_invoker: string;
song_url: string;
song_url_loader: string;
song_loaded: boolean;
song_metadata: string;
}

View File

@ -594,10 +594,6 @@ const loader_javascript = {
"js/voice/RecorderBase.js",
"js/voice/RecorderProfile.js",
//Load codec
"js/codec/Codec.js",
"js/codec/BasicCodec.js",
//Load general stuff
"js/settings.js",
"js/bookmarks.js",
@ -610,13 +606,11 @@ const loader_javascript = {
"js/connection/CommandHandler.js",
"js/connection/CommandHelper.js",
"js/connection/HandshakeHandler.js",
"js/connection/ServerConnection.js",
"js/connection/ServerConnectionDeclaration.js",
"js/stats.js",
"js/PPTListener.js",
"js/codec/CodecWrapperWorker.js",
"js/profiles/identities/NameIdentity.js", //Depends on Identity
"js/profiles/identities/TeaForumIdentity.js", //Depends on Identity
"js/profiles/identities/TeamSpeakIdentity.js", //Depends on Identity
@ -634,6 +628,14 @@ const loader_javascript = {
"js/voice/JavascriptRecorder.js",
"js/voice/VoiceHandler.js",
"js/voice/VoiceClient.js",
//Connection
"js/connection/ServerConnection.js",
//Load codec
"js/codec/Codec.js",
"js/codec/BasicCodec.js",
"js/codec/CodecWrapperWorker.js",
]);
},
load_scripts_debug_client: async () => {

View File

@ -7,6 +7,7 @@
/// <reference path="ui/modal/ModalBanList.ts" />
/// <reference path="settings.ts" />
/// <reference path="log.ts" />
/// <reference path="PPTListener.ts" />
let settings: Settings;

View File

@ -1,6 +1,5 @@
/// <reference path="../../ui/elements/modal.ts" />
/// <reference path="../../proto.ts" />
/// <reference path="../../voice/VoiceClient.ts" />
/// <reference path="../../profiles/Identity.ts" />
namespace Modals {

View File

@ -1,4 +1,3 @@
/// <reference path="../voice/VoiceHandler.ts" />
/// <reference path="../ConnectionHandler.ts" />
/// <reference path="../proto.ts" />
/// <reference path="channel.ts" />

View File

@ -11,13 +11,6 @@ namespace audio {
channels: number;
}
export declare function devices() : InputDevice[];
export declare function device_refresh_available() : boolean;
export declare function refresh_devices() : Promise<void>;
export declare function create_input() : AbstractInput;
export enum InputConsumerType {
CALLBACK,
NODE,
@ -29,15 +22,11 @@ namespace audio {
}
export interface CallbackInputConsumer extends InputConsumer {
type: InputConsumerType.CALLBACK;
callback_audio?: (buffer: AudioBuffer) => any;
callback_buffer?: (buffer: Float32Array, samples: number, channels: number) => any;
}
export interface NodeInputConsumer extends InputConsumer {
type: InputConsumerType.NODE;
callback_node: (source_node: AudioNode) => any;
callback_disconnect: (source_node: AudioNode) => any;
}
@ -62,8 +51,6 @@ namespace audio {
}
export interface ThresholdFilter extends Filter, MarginedFilter {
type: Type.THRESHOLD;
get_threshold() : number;
set_threshold(value: number) : Promise<void>;
@ -71,14 +58,10 @@ namespace audio {
}
export interface VoiceLevelFilter extends Filter, MarginedFilter {
type: Type.VOICE_LEVEL;
get_level() : number;
}
export interface StateFilter extends Filter {
type: Type.STATE;
set_state(state: boolean) : Promise<void>;
is_active() : boolean; /* if true the the filter allows data to pass */
}
@ -91,27 +74,27 @@ namespace audio {
DRY
}
export abstract class AbstractInput {
abstract current_state() : InputState;
abstract start() : Promise<void>;
abstract stop() : Promise<void>;
abstract current_device() : InputDevice | undefined;
abstract set_device(device: InputDevice | undefined) : Promise<void>;
abstract current_consumer() : InputConsumer | undefined;
abstract set_consumer(consumer: InputConsumer) : Promise<void>;
export interface AbstractInput {
callback_state_change: () => any;
callback_begin: () => any;
callback_end: () => any;
abstract get_filter(type: filter.Type) : filter.Filter | undefined;
current_state() : InputState;
abstract clear_filter();
abstract disable_filter(type: filter.Type);
abstract enable_filter(type: filter.Type);
start() : Promise<void>;
stop() : Promise<void>;
current_device() : InputDevice | undefined;
set_device(device: InputDevice | undefined) : Promise<void>;
current_consumer() : InputConsumer | undefined;
set_consumer(consumer: InputConsumer) : Promise<void>;
get_filter(type: filter.Type) : filter.Filter | undefined;
clear_filter();
disable_filter(type: filter.Type);
enable_filter(type: filter.Type);
}
}

View File

@ -1,3 +1,4 @@
/// <reference path="../PPTListener.ts" />
type VadType = "threshold" | "push_to_talk" | "active";
interface RecorderProfileConfig {

View File

@ -4,6 +4,7 @@
"target": "es6",
"module": "commonjs",
"sourceMap": true,
"experimentalDecorators": true,
"plugins": [ /* ttypescript */
{
"transform": "../../tools/trgen/ttsc_transformer.js",
@ -18,6 +19,7 @@
],
"include": [
"../declarations/imports_*.d.ts",
"../backend",
"../js/**/*.ts"
]
}

View File

@ -23,6 +23,7 @@
"include": [
"../declarations/imports_*.d.ts",
"../declarations/exports_loader.d.ts",
"../js/**/*.ts"
"../js/**/*.ts",
"../backend"
]
}

View File

@ -7,6 +7,7 @@
"include": [
"../declarations/imports_*.d.ts",
"../declarations/exports_packed.d.ts",
"../js/load.ts"
"../js/load.ts",
"../backend"
]
}

View File

@ -21,3 +21,13 @@ if [ $? -ne 0 ]; then
echo "Failed to build file"
exit 1
fi
echo "Mergin files"
if [ -e generated/client.js ]; then
rm generated/client.js
fi
cat ../shared/generated/shared.js > generated/client.js
cat generated/web.js >> generated/client.js
npm run minify-web-rel-file

View File

@ -1,5 +1,6 @@
/// <reference path="../declarations/imports_shared.d.ts"/>
namespace ppt {
interface WebKeyEvent extends KeyEvent {
canceled: boolean;

View File

@ -3,7 +3,7 @@ interface Navigator {
webkitGetUserMedia(constraints: MediaStreamConstraints, successCallback: NavigatorUserMediaSuccessCallback, errorCallback: NavigatorUserMediaErrorCallback): void;
}
namespace audio.player {
namespace audio.player {
let _globalContext: AudioContext;
let _global_destination: GainNode;
@ -11,11 +11,6 @@ namespace audio.player {
let _initialized_listener: (() => any)[] = [];
let _master_volume: number = 1;
export interface Device {
device_id: string;
name: string;
}
export function initialize() : boolean {
context();
return true;

View File

@ -1,29 +1,3 @@
enum ErrorID {
PERMISSION_ERROR = 2568,
EMPTY_RESULT = 0x0501,
PLAYLIST_IS_IN_USE = 0x2103
}
class CommandResult {
success: boolean;
id: number;
message: string;
extra_message: string;
json: any;
constructor(json) {
this.json = json;
this.id = parseInt(json["id"]);
this.message = json["msg"];
this.extra_message = "";
if(json["extra_msg"]) this.extra_message = json["extra_msg"];
this.success = this.id == 0;
}
}
class ReturnListener<T> {
resolve: (value?: T | PromiseLike<T>) => void;
reject: (reason?: any) => void;
@ -214,6 +188,9 @@ namespace connection {
command: json["command"],
arguments: json["data"]
});
if(json["command"] === "initserver" && this._voice_connection)
this._voice_connection.createSession(); /* FIXME: Move it to a handler boss and not here! */
group.end();
} else if(json["type"] === "WebRTC") {
if(this._voice_connection)
@ -326,70 +303,3 @@ namespace connection {
return new ServerConnection(handle); /* will be overridden by the client */
}
}
interface ClientNameInfo {
//cluid=tYzKUryn\/\/Y8VBMf8PHUT6B1eiE= name=Exp clname=Exp cldbid=9
client_unique_id: string;
client_nickname: string;
client_database_id: number;
}
interface ClientNameFromUid {
promise: LaterPromise<ClientNameInfo[]>,
keys: string[],
response: ClientNameInfo[]
}
interface QueryListEntry {
username: string;
unique_id: string;
bounded_server: number;
}
interface QueryList {
flag_own: boolean;
flag_all: boolean;
queries: QueryListEntry[];
}
interface Playlist {
playlist_id: number;
playlist_bot_id: number;
playlist_title: string;
playlist_type: number;
playlist_owner_dbid: number;
playlist_owner_name: string;
needed_power_modify: number;
needed_power_permission_modify: number;
needed_power_delete: number;
needed_power_song_add: number;
needed_power_song_move: number;
needed_power_song_remove: number;
}
interface PlaylistInfo {
playlist_id: number,
playlist_title: string,
playlist_description: string,
playlist_type: number,
playlist_owner_dbid: number,
playlist_owner_name: string,
playlist_flag_delete_played: boolean,
playlist_flag_finished: boolean,
playlist_replay_mode: number,
playlist_current_song_id: number,
}
interface PlaylistSong {
song_id: number;
song_previous_song_id: number;
song_invoker: string;
song_url: string;
song_url_loader: string;
song_loaded: boolean;
song_metadata: string;
}

View File

@ -1,9 +1,11 @@
/// <reference path="../../declarations/imports_shared.d.ts"/>
namespace audio {
export namespace recorder {
/* TODO: Recognise if we got device permission and update list */
let _queried_devices: JavascriptInputDevice[];
interface JavascriptInputDevice extends InputDevice {
export interface JavascriptInputDevice extends InputDevice {
device_id: string;
group_id: string;
}
@ -54,6 +56,8 @@ namespace audio {
export namespace filter {
export abstract class JAbstractFilter<NodeType extends AudioNode> implements Filter {
type;
source_node: AudioNode;
audio_node: NodeType;
@ -74,7 +78,9 @@ namespace audio {
export class JThresholdFilter extends JAbstractFilter<GainNode> implements ThresholdFilter {
private static update_task_interval = 20; /* 20ms */
type: Type.THRESHOLD = Type.THRESHOLD;
type = Type.THRESHOLD;
callback_level?: (value: number) => any;
private _threshold = 50;
private _update_task: any;
@ -180,7 +186,7 @@ namespace audio {
}
export class JStateFilter extends JAbstractFilter<GainNode> implements StateFilter {
type: Type.STATE = Type.STATE;
type = Type.STATE;
finalize() {
if(this.source_node) {
@ -219,7 +225,7 @@ namespace audio {
}
}
class JavascriptInput extends AbstractInput {
class JavascriptInput implements AbstractInput {
private _state: InputState = InputState.PAUSED;
private _current_device: JavascriptInputDevice | undefined;
private _current_consumer: InputConsumer;
@ -235,9 +241,11 @@ namespace audio {
private _filters: filter.Filter[] = [];
private _filter_active: boolean = false;
constructor() {
super();
callback_state_change: () => any = undefined;
callback_begin: () => any = undefined;
callback_end: () => any = undefined;
constructor() {
player.on_ready(() => this._audio_initialized());
}
@ -318,7 +326,7 @@ namespace audio {
} catch(error) {
if(error instanceof DOMException) {
if(error.code == 0 || error.name == "NotAllowedError") {
console.warn(tr("Browser does not allow mirophone access"));
console.warn(tr("Browser does not allow microphone access"));
this._state = InputState.PAUSED;
createErrorModal(tr("Failed to create microphone"), tr("Microphone recording failed. Please allow TeaWeb access to your microphone")).open();
return;
@ -440,11 +448,12 @@ namespace audio {
}
clear_filter() {
for(const filter of this._filters) {
if(!filter.is_enabled())
for(const _filter of this._filters) {
if(!_filter.is_enabled())
continue;
filter.finalize();
filter.enabled = false;
const c_filter = _filter as any as filter.JAbstractFilter<AudioNode>;
c_filter.finalize();
c_filter.enabled = false;
}
this._initialize_filters();

View File

@ -1,4 +1,4 @@
/// <reference path="../connection/ConnectionBase.ts" />
/// <reference path="../../declarations/imports_shared.d.ts"/>
namespace audio {
export namespace js {

View File

@ -1,5 +1,4 @@
/// <reference path="../ConnectionHandler.ts" />
/// <reference path="../codec/Codec.ts" />
/// <reference path="../../declarations/imports_shared.d.ts"/>
/// <reference path="VoiceClient.ts" />
namespace audio {

View File

@ -3,12 +3,14 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "none",
"outFile": "../generated/client.js",
"outFile": "../generated/web.js",
"allowJs": true
},
"exclude": [
"../js/workers"
],
"include": [
"../declarations/imports_*.d.ts",
"../js/**/*.ts",
"../../shared/generated/shared.js"
"../js/**/*.ts"
]
}