|
|
|
pragma Singleton
|
|
|
|
import QtQml 2.2
|
|
|
|
import QtQuick 2.7
|
|
|
|
|
|
|
|
import NERvGear 1.0 as NVG
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Item {
|
|
|
|
readonly property var styles: []
|
|
|
|
readonly property var stylesURL: []
|
|
|
|
readonly property var defaultServerCFG: {
|
|
|
|
"server": {
|
|
|
|
"port": 5050,
|
|
|
|
"maxclient": 5,
|
|
|
|
"logger": true
|
|
|
|
},
|
|
|
|
"fft": {
|
|
|
|
"attack": 5,
|
|
|
|
"decay": 5,
|
|
|
|
"norspeed": 1,
|
|
|
|
"peakthr": 10,
|
|
|
|
"fps": 35,
|
|
|
|
"changespeed": 20
|
|
|
|
}
|
|
|
|
}
|
|
|
|
readonly property string iniFile: "../bin/advConfig.ini"
|
|
|
|
readonly property string serverEXE: "../bin/ADVServer.exe"
|
|
|
|
|
|
|
|
property var serverCFG: defaultServerCFG
|
|
|
|
property string wsIp: "localhost"
|
|
|
|
property int wsPort: serverCFG.server.port
|
|
|
|
|
|
|
|
property int widgetsNum: 0
|
|
|
|
property bool debug: false
|
|
|
|
property bool rebootFlag: false
|
|
|
|
|
|
|
|
signal audioDataUpdated(var audioData)
|
|
|
|
signal serverPreferencesOpen()
|
|
|
|
|
|
|
|
function execute(path, args) {
|
|
|
|
path = NVG.Url.toLocalFile(Qt.resolvedUrl(path));
|
|
|
|
NVG.SystemCall.execute(path, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
function readFile(fileUrl) {
|
|
|
|
let request = new XMLHttpRequest();
|
|
|
|
request.open("GET", fileUrl, false);
|
|
|
|
request.send(null);
|
|
|
|
let data = request.responseText;
|
|
|
|
request = null;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
function writeFile(fileUrl, text) {
|
|
|
|
var request = new XMLHttpRequest();
|
|
|
|
request.open("PUT", fileUrl, false);
|
|
|
|
request.send(text);
|
|
|
|
return request.status;
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseINIString(data) {
|
|
|
|
let regex = {
|
|
|
|
section: /\[\s*([^]*)\s*\]\s*$/,
|
|
|
|
param: /^\s*([\w\.\-\_]+)\s*=\s*(.*?)\s*$/,
|
|
|
|
comment: /^\s*;.*$/
|
|
|
|
};
|
|
|
|
let value = {};
|
|
|
|
let lines = data.split(/\r\n|\r|\n/);
|
|
|
|
let section = null;
|
|
|
|
let match;
|
|
|
|
lines.forEach(function(line){
|
|
|
|
if (regex.comment.test(line)) {
|
|
|
|
return;
|
|
|
|
} else if (regex.param.test(line)) {
|
|
|
|
match = line.match(regex.param);
|
|
|
|
if (["true", "false"].indexOf(match[2]) > -1) {
|
|
|
|
match[2] = Boolean(1 - ["true", "false"].indexOf(match[2]));
|
|
|
|
} else if (/^\d+$/.test(match[2])) {
|
|
|
|
match[2] = Number(match[2]);
|
|
|
|
}
|
|
|
|
if (section) {
|
|
|
|
value[section][match[1]] = match[2];
|
|
|
|
} else {
|
|
|
|
value[match[1]] = match[2];
|
|
|
|
}
|
|
|
|
} else if (regex.section.test(line)) {
|
|
|
|
match = line.match(regex.section);
|
|
|
|
value[match[1]] = {};
|
|
|
|
section = match[1];
|
|
|
|
} else if(line.length === 0 && section) {
|
|
|
|
section = null;
|
|
|
|
};
|
|
|
|
});
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
function convertINIString(data) {
|
|
|
|
let value = "";
|
|
|
|
for (let section in data) {
|
|
|
|
value += "[" + section + "]\n";
|
|
|
|
for (let key in data[section]) {
|
|
|
|
value += key + " = " + String(data[section][key]) + "\n";
|
|
|
|
}
|
|
|
|
value += "\n";
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
function deepClone(obj) {
|
|
|
|
let objClone = Array.isArray(obj) ? [] : {};
|
|
|
|
if (obj && typeof obj === "object" && obj != null) {
|
|
|
|
for (var key in obj) {
|
|
|
|
if (obj.hasOwnProperty(key)) {
|
|
|
|
if (obj[key] && typeof obj[key] === "object") {
|
|
|
|
objClone[key] = deepClone(obj[key]);
|
|
|
|
} else {
|
|
|
|
objClone[key] = obj[key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return objClone;
|
|
|
|
}
|
|
|
|
|
|
|
|
//支持二级嵌套对象的更新操作
|
|
|
|
function updateObject(targetObj, sourceObj) {
|
|
|
|
for (let prop in sourceObj) {
|
|
|
|
if (sourceObj.hasOwnProperty(prop) && sourceObj[prop] !== undefined) {
|
|
|
|
if (typeof sourceObj[prop] === 'object') {
|
|
|
|
if (targetObj[prop] === undefined)
|
|
|
|
targetObj[prop] = {};
|
|
|
|
Object.assign(targetObj[prop], sourceObj[prop]);
|
|
|
|
} else {
|
|
|
|
targetObj[prop] = sourceObj[prop];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return targetObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isObjectValueEqual(a, b) {
|
|
|
|
if (a === b)
|
|
|
|
return true;
|
|
|
|
let aProps = Object.getOwnPropertyNames(a);
|
|
|
|
let bProps = Object.getOwnPropertyNames(b);
|
|
|
|
if (aProps.length !== bProps.length)
|
|
|
|
return false;
|
|
|
|
for (let prop in a) {
|
|
|
|
if (b.hasOwnProperty(prop)) {
|
|
|
|
if (typeof a[prop] === 'object') {
|
|
|
|
if (!isObjectValueEqual(a[prop], b[prop]))
|
|
|
|
return false;
|
|
|
|
} else if (a[prop] !== b[prop]) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Loader {
|
|
|
|
id: wsocket
|
|
|
|
sourceComponent: WSocket {}
|
|
|
|
active: false
|
|
|
|
}
|
|
|
|
|
|
|
|
onWidgetsNumChanged: {
|
|
|
|
wsocket.active = widgetsNum>0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function setWsocket(status) {
|
|
|
|
wsocket.active = status;
|
|
|
|
}
|
|
|
|
|
|
|
|
function rebootServer(force) {
|
|
|
|
if (force || !debug && wsocket.active && rebootFlag) {
|
|
|
|
console.log("Try to reboot ADVServer...");
|
|
|
|
execute(serverEXE, "-reboot");
|
|
|
|
if (widgetsNum) {
|
|
|
|
wsocket.active = false;
|
|
|
|
wsocket.active = true;
|
|
|
|
}
|
|
|
|
rebootFlag = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onDebugChanged: {
|
|
|
|
rebootServer();
|
|
|
|
}
|
|
|
|
|
|
|
|
onRebootFlagChanged: {
|
|
|
|
rebootServer();
|
|
|
|
if (rebootFlag && debug) {
|
|
|
|
NVG.SystemCall.execute("explorer", NVG.Url.toLocalFile(Qt.resolvedUrl("../bin/ADV_Log.log")).replace(/\//g, '\\'));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function parse_resource(resource_list, preset) {
|
|
|
|
if (preset)
|
|
|
|
resource_list.sort(function (x, y) {
|
|
|
|
let preset_order = ["/advp-style-preset/line", "/advp-style-preset/gradient_line", "/advp-style-preset/waves", "/advp-style-preset/circle", "/advp-style-preset/solidcircle", "/advp-style-preset/ordinal_scale_ui_bottom"];
|
|
|
|
if (preset_order.indexOf(x.location) < preset_order.indexOf(y.location))
|
|
|
|
return -1;
|
|
|
|
else if(preset_order.indexOf(x.location) > preset_order.indexOf(y.location))
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
resource_list.forEach(function (resource) {
|
|
|
|
if (resource.url && stylesURL.indexOf(resource.url.toString()) === -1) {
|
|
|
|
styles.push(resource.title);
|
|
|
|
stylesURL.push(resource.url.toString());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateStyleList() {
|
|
|
|
styles.length = 0;
|
|
|
|
stylesURL.length = 0;
|
|
|
|
const preset_list = NVG.Resources.filter(/advp.widget.mashiros.top/, /top.mashiros.advp-style/);
|
|
|
|
parse_resource(preset_list, true);
|
|
|
|
const third_list = NVG.Resources.filter(/.*/, /top.mashiros.advp-style/);
|
|
|
|
parse_resource(third_list, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
Component.onCompleted: {
|
|
|
|
updateStyleList();
|
|
|
|
let ini_data = readFile(iniFile);
|
|
|
|
if (ini_data) {
|
|
|
|
ini_data = ini_data.toLowerCase();
|
|
|
|
let cfg = parseINIString(ini_data);
|
|
|
|
serverCFG = Object.assign(deepClone(defaultServerCFG), cfg);
|
|
|
|
} else {
|
|
|
|
let ini_text = convertINIString(defaultServerCFG);
|
|
|
|
writeFile(iniFile, ini_text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|