Added opus script again
parent
1c024ad483
commit
fb7edd32b8
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
base_dir=`pwd`
|
||||||
|
cd "$(dirname $0)/libraries/opus/"
|
||||||
|
|
||||||
|
git checkout v1.1.2
|
||||||
|
./autogen.sh
|
||||||
|
emconfigure ./configure --disable-extra-programs --disable-doc --disable-rtcd
|
||||||
|
emmake make
|
||||||
|
|
||||||
|
cd ${base_dir}
|
|
@ -0,0 +1,42 @@
|
||||||
|
# File structure
|
||||||
|
The TeaSpeak web client is separated into 2 different parts.
|
||||||
|
|
||||||
|
## I) Application files
|
||||||
|
Application files are all files which directly belong to the app itself.
|
||||||
|
Like the javascript files who handle the UI stuff or even translation templates.
|
||||||
|
Theses files are separated into two type of files.
|
||||||
|
1. [Shared application files](#1-shared-application-files)
|
||||||
|
2. [Web application files](#2-web-application-files)
|
||||||
|
|
||||||
|
### 1. Shared application files
|
||||||
|
Containing all files used by the TeaSpeak client and the Web client.
|
||||||
|
All of these files will be found within the folder `shared`.
|
||||||
|
This folder follows the general application file structure.
|
||||||
|
More information could be found [here](#application-file-structure)
|
||||||
|
|
||||||
|
### 2. Web application files
|
||||||
|
All files which only belong to a browser only instance.
|
||||||
|
All of these files will be found within the folder `web`.
|
||||||
|
This folder follows the general application file structure.
|
||||||
|
More information could be found [here](#application-file-structure)
|
||||||
|
|
||||||
|
### application file structure
|
||||||
|
Every application root contains several subfolders.
|
||||||
|
In the following list will be listed which files belong to which folder
|
||||||
|
|
||||||
|
| Folder | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `audio` | This folder contains all audio files used by the application. More information could be found [here](). |
|
||||||
|
| `css` | This folder contains all style sheets used by the application. More information could be found [here](). |
|
||||||
|
| `js` | This folder contains all javascript files used by the application. More information could be found [here](). |
|
||||||
|
| `html` | This folder contains all HTML and PHP files used by the application. More information could be found [here](). |
|
||||||
|
| `i18n` | This folder contains all default translations. Information about the translation system could be found [here](). |
|
||||||
|
| `img` | This folder contains all image files. |
|
||||||
|
|
||||||
|
## I) Additional tools
|
||||||
|
|
||||||
|
## Environment builder
|
||||||
|
The environment builder is one of the most important tools of the entire project.
|
||||||
|
This tool, basically implemented in the file `files.php`, will be your helper while live developing.
|
||||||
|
What this tool does is, it creates a final environment where you could navigate to with your browser.
|
||||||
|
It merges all the type separated files, which had been listed above ([here](#application-file-structure)).
|
|
@ -0,0 +1,232 @@
|
||||||
|
namespace stats {
|
||||||
|
const LOG_PREFIX = "[Statistics] ";
|
||||||
|
|
||||||
|
export enum CloseCodes {
|
||||||
|
UNSET = 3000,
|
||||||
|
RECONNECT = 3001,
|
||||||
|
INTERNAL_ERROR = 3002,
|
||||||
|
|
||||||
|
BANNED = 3100,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ConnectionState {
|
||||||
|
CONNECTING,
|
||||||
|
INITIALIZING,
|
||||||
|
CONNECTED,
|
||||||
|
UNSET
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SessionConfig {
|
||||||
|
/*
|
||||||
|
* All collected statistics will only be cached by the stats server.
|
||||||
|
* No data will be saved.
|
||||||
|
*/
|
||||||
|
volatile_collection_only?: boolean;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Anonymize all IP addresses which will be provided while the stats collection.
|
||||||
|
* This option is quite useless when volatile_collection_only is active.
|
||||||
|
*/
|
||||||
|
anonymize_ip_addresses?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Config extends SessionConfig {
|
||||||
|
verbose?: boolean;
|
||||||
|
|
||||||
|
reconnect_interval?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserCountData {
|
||||||
|
online_users: number;
|
||||||
|
unique_online_users: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserCountListener = (data: UserCountData) => any;
|
||||||
|
|
||||||
|
let reconnect_timer: NodeJS.Timer;
|
||||||
|
let current_config: Config;
|
||||||
|
|
||||||
|
let last_user_count_update: number;
|
||||||
|
let user_count_listener: UserCountListener[] = [];
|
||||||
|
|
||||||
|
const DEFAULT_CONFIG: Config = {
|
||||||
|
verbose: true,
|
||||||
|
reconnect_interval: 5000,
|
||||||
|
anonymize_ip_addresses: true,
|
||||||
|
volatile_collection_only: false
|
||||||
|
};
|
||||||
|
|
||||||
|
function initialize_config_object(target_object: any, source_object: any) : any {
|
||||||
|
for(const key of Object.keys(source_object)) {
|
||||||
|
if(typeof(source_object[key]) === 'object')
|
||||||
|
initialize_config_object(target_object[key] || (target_object[key] = {}), source_object[key]);
|
||||||
|
|
||||||
|
if(typeof(target_object[key]) !== 'undefined')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
target_object[key] = source_object[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return target_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initialize(config: Config) {
|
||||||
|
current_config = initialize_config_object(config || {}, DEFAULT_CONFIG);
|
||||||
|
if(current_config.verbose)
|
||||||
|
console.log(LOG_PREFIX + tr("Initializing statistics with this config: %o"), current_config);
|
||||||
|
|
||||||
|
connection.start_connection();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function register_user_count_listener(listener: UserCountListener) {
|
||||||
|
user_count_listener.push(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function all_user_count_listener() : UserCountListener[] {
|
||||||
|
return user_count_listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deregister_user_count_listener(listener: UserCountListener) {
|
||||||
|
user_count_listener.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace connection {
|
||||||
|
let connection: WebSocket;
|
||||||
|
export let connection_state: ConnectionState = ConnectionState.UNSET;
|
||||||
|
|
||||||
|
export function start_connection() {
|
||||||
|
cancel_reconnect();
|
||||||
|
|
||||||
|
if(connection) {
|
||||||
|
const connection_copy = connection;
|
||||||
|
connection = undefined;
|
||||||
|
|
||||||
|
connection_copy.close(3001);
|
||||||
|
}
|
||||||
|
|
||||||
|
connection_state = ConnectionState.CONNECTING;
|
||||||
|
connection = new WebSocket('wss://web-stats.teaspeak.de:1774');
|
||||||
|
{
|
||||||
|
const connection_copy = connection;
|
||||||
|
connection.onclose = (event: CloseEvent) => {
|
||||||
|
if(connection_copy !== connection) return;
|
||||||
|
|
||||||
|
if(current_config.verbose)
|
||||||
|
console.log(LOG_PREFIX + tr("Lost connection to statistics server (Connection closed). Reason: %o. Event object: %o"), CloseCodes[event.code] || event.code, event);
|
||||||
|
|
||||||
|
if(event.code != CloseCodes.BANNED)
|
||||||
|
invoke_reconnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
connection.onopen = () => {
|
||||||
|
if(connection_copy !== connection) return;
|
||||||
|
|
||||||
|
if(current_config.verbose)
|
||||||
|
console.log(LOG_PREFIX + tr("Successfully connected to server. Initializing session."));
|
||||||
|
|
||||||
|
connection_state = ConnectionState.INITIALIZING;
|
||||||
|
initialize_session();
|
||||||
|
};
|
||||||
|
|
||||||
|
connection.onerror = (event: ErrorEvent) => {
|
||||||
|
if(connection_copy !== connection) return;
|
||||||
|
|
||||||
|
if(current_config.verbose)
|
||||||
|
console.log(LOG_PREFIX + tr("Received an error. Closing connection. Object: %o"), event);
|
||||||
|
|
||||||
|
connection.close(CloseCodes.INTERNAL_ERROR);
|
||||||
|
this.invoke_reconnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
connection.onmessage = (event: MessageEvent) => {
|
||||||
|
if(connection_copy !== connection) return;
|
||||||
|
|
||||||
|
if(typeof(event.data) !== 'string') {
|
||||||
|
if(current_config.verbose)
|
||||||
|
console.warn(LOG_PREFIX + tr("Received an message which isn't a string. Event object: %o"), event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_message(event.data as string);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function invoke_reconnect() {
|
||||||
|
if(reconnect_timer) {
|
||||||
|
clearTimeout(reconnect_timer);
|
||||||
|
reconnect_timer = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(current_config.verbose)
|
||||||
|
console.log(LOG_PREFIX + tr("Scheduled reconnect in %dms"), current_config.reconnect_interval);
|
||||||
|
|
||||||
|
reconnect_timer = setTimeout(() => {
|
||||||
|
if(current_config.verbose)
|
||||||
|
console.log(LOG_PREFIX + tr("Reconnecting"));
|
||||||
|
start_connection();
|
||||||
|
}, current_config.reconnect_interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cancel_reconnect() {
|
||||||
|
if(reconnect_timer) {
|
||||||
|
clearTimeout(reconnect_timer);
|
||||||
|
reconnect_timer = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_message(type: string, data: any) {
|
||||||
|
connection.send(JSON.stringify({
|
||||||
|
type: type,
|
||||||
|
data: data
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize_session() {
|
||||||
|
const config_object = {};
|
||||||
|
for(const key in SessionConfig) {
|
||||||
|
if(SessionConfig.hasOwnProperty(key))
|
||||||
|
config_object[key] = current_config[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
send_message('initialize', {
|
||||||
|
config: config_object
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_message(message: string) {
|
||||||
|
const data_object = JSON.parse(message);
|
||||||
|
const type = data_object.type as string;
|
||||||
|
const data = data_object.data;
|
||||||
|
|
||||||
|
if(typeof(handler[type]) === 'function') {
|
||||||
|
if(current_config.verbose)
|
||||||
|
console.debug(LOG_PREFIX + tr("Handling message of type %s"), type);
|
||||||
|
handler[type](data);
|
||||||
|
} else if(current_config.verbose) {
|
||||||
|
console.warn(LOG_PREFIX + tr("Received message with an unknown type (%s). Dropping message. Full message: %o"), type, data_object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace handler {
|
||||||
|
interface NotifyUserCount extends UserCountData { }
|
||||||
|
|
||||||
|
function handle_notify_user_count(data: NotifyUserCount) {
|
||||||
|
last_user_count_update = Date.now();
|
||||||
|
for(const listener of [...user_count_listener])
|
||||||
|
listener(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NotifyInitialized {}
|
||||||
|
function handle_notify_initialized(json: NotifyInitialized) {
|
||||||
|
if(current_config.verbose)
|
||||||
|
console.log(LOG_PREFIX + tr("Session successfully initialized."));
|
||||||
|
|
||||||
|
connection_state = ConnectionState.CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
handler["notifyinitialized"] = handle_notify_initialized;
|
||||||
|
handler["notifyusercount"] = handle_notify_user_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue