- 增加服务器参数设置对话框

- 优化服务器程序的错误捕捉与日志输出
- 优化翻译
This commit is contained in:
mashiros 2022-05-12 20:12:56 +08:00
parent 66d57a3f4c
commit d0aed6f101
12 changed files with 394 additions and 59 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,13 +1,13 @@
[Server]
ip = local
port = 5055
maxClient = 10
[server]
port = 5050
maxclient = 5
logger = true
[FFT]
[fft]
attack = 5
decay = 5
norspeed = 1
peakthr = 10
norspeed = 10
fps = 35
changeSpeed = 20
changespeed = 20

View File

@ -1,13 +1,15 @@
import NERvGear 1.0 as NVG
import NERvGear.Private 1.0 as NVGP
import QtQuick 2.12
import QtQuick.Controls 2.12
import "./qml"
NVG.Module {
initialize: function () {
console.log("Initializing ADV-Plugin.");
Common.execute("../bin/ADVServer.exe", "-reboot");
// Common.setWsocket(true);
Common.execute(Common.serverEXE, "-reboot");
return true;
}
@ -18,6 +20,20 @@ NVG.Module {
cleanup: function () {
console.log("Cleaning up ADV-Plugin.");
Common.setWsocket(false);
Common.execute("../bin/ADVServer.exe", "-close");
Common.execute(Common.serverEXE, "-close");
}
Connections {
target: Common
onServerPreferencesOpen: {
serverDialog.active = true;
serverDialog.item.visible = true;
}
}
Loader {
id: serverDialog
active: false
sourceComponent: ServerPreferences { }
}
}

View File

@ -1,7 +1,7 @@
{
"name": "top.mashiros.widget.advp",
"version": "1.2.1",
"version": "1.3.0",
"title": {
"en": "ADV Plugin",
"zh": "音频可视化插件",
@ -115,7 +115,7 @@
"ja": "オーディナル・スケール- UI 下部"
},
"entry": "./styles/Preset_Ordinal_Scale_UI_bottom/Style.qml"
},
},
{
"location": "/preset/advp-style-preset/line",
"catalog": "preset/widget",
@ -189,4 +189,4 @@
"entry": "Presets/Ordinal_Scale_UI_bottom/preset.json"
}
]
}
}

View File

@ -9,18 +9,41 @@ 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 wsocketClosed()
signal serverPreferencesOpen()
function execute(path, args) {
path = NVG.Url.toLocalFile(Qt.resolvedUrl(path));
NVG.SystemCall.execute(path, args);
}
function openFile(fileUrl) {
function readFile(fileUrl) {
let request = new XMLHttpRequest();
request.open("GET", fileUrl, false);
request.send(null);
@ -29,7 +52,14 @@ Item {
return data;
}
function parseINIString(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*$/,
@ -40,56 +70,113 @@ Item {
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(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;
};
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 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 {
Component.onCompleted: {
let ini_data = openFile("../bin/advConfig.ini");
ini_data = ini_data.toLowerCase();
let cfg = parseINIString(ini_data);
if(cfg["server"]["ip"].toLowerCase() === "local") {
wsIp = "localhost";
} else {
wsIp = cfg["server"]["ip"];
}
wsPort = cfg["server"]["port"];
}}
active: widgetsNum>0
sourceComponent: WSocket {}
active: false
}
onWidgetsNumChanged: {
wsocket.active = widgetsNum>0;
}
function setWsocket(status) {
wsocket.active = status;
}
onWsocketClosed: {
if (wsocket.active) {
function rebootServer(force) {
if (force || !debug && wsocket.active && rebootFlag) {
console.log("Try to reboot ADVServer...");
execute("../bin/ADVServer.exe", "-reboot");
execute(serverEXE, "-reboot");
wsocket.active = false;
wsocket.active = true;
rebootFlag = false;
}
}
onDebugChanged: {
rebootServer();
}
onRebootFlagChanged: {
rebootServer();
}
function parse_resource(resource_list, sort) {
if (sort)
resource_list.sort(function (x, y) {
@ -120,5 +207,14 @@ Item {
Component.onCompleted: {
updateStyleList();
let ini_data = readFile(iniFile);
if (ini_data) {
ini_data = ini_data.toLowerCase();
let cfg = parseINIString(ini_data);
serverCFG = Object.assign(defaultServerCFG, cfg);
} else {
let ini_text = convertINIString(defaultServerCFG);
writeFile(iniFile, ini_text);
}
}
}

View File

@ -55,13 +55,19 @@ T.Widget {
menu: Menu {
Action {
text: qsTr("Settings") + "..."
enabled: !styleDialog.active
text: qsTr("Style Settings") + "..."
onTriggered: {
Common.updateStyleList();
styleDialog.active = true;
}
}
Action {
text: qsTr("Server Settings") + "..."
onTriggered: {
Common.serverPreferencesOpen();
}
}
}
Component.onCompleted: {

220
qml/ServerPreferences.qml Normal file
View File

@ -0,0 +1,220 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import NERvGear 1.0 as NVG
import NERvGear.Preferences 1.0 as P
import NERvGear.Controls 1.0
import "."
NVG.Window {
title: qsTr("ADV-Server: Settings")
visible: true
minimumWidth: 480
minimumHeight: 600
width: minimumWidth
height: minimumHeight
Page {
id: cfg_page
anchors.fill: parent
header: TitleBar {
text: qsTr("Server Settings")
standardButtons: Dialog.Save | Dialog.Reset
onAccepted: {
let cfg = Object.assign(Common.deepClone(Common.serverCFG), rootPreference.save());
if (cfg.server.logger) {
Common.debug = _debug.value;
} else {
Common.debug = false;
}
if (!Common.isObjectValueEqual(cfg, Common.serverCFG)) {
Common.setWsocket(false);
Common.serverCFG = cfg;
let ini_text = Common.convertINIString(Common.serverCFG);
Common.writeFile(Common.iniFile, ini_text);
Common.rebootServer(true);
Common.setWsocket(true);
}
serverDialog.active = false;
}
onReset: {
rootPreference.load(Common.defaultServerCFG);
}
}
ColumnLayout {
id: root
anchors.fill: parent
anchors.margins: 16
anchors.topMargin: 0
Flickable {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
contentWidth: preferenceLayout.implicitWidth
contentHeight: preferenceLayout.implicitHeight
ColumnLayout {
id: preferenceLayout
width: root.width
P.SwitchPreference {
id: _debug
Layout.fillWidth: true
name: "debug"
label: qsTr("Debug Mode")
message: qsTr("Logging must be enabled and saved.")
warning: value ? qsTr("This will disable the error recovery function!") : ""
enabled: Common.serverCFG.server.logger
defaultValue: Common.debug
onPreferenceEdited: {
Common.debug = value;
}
}
P.PreferenceGroup {
id: rootPreference
Layout.fillWidth: true
P.PreferenceGroup {
Layout.fillWidth: true
name: "server"
Heading { text: qsTr("General") }
P.SpinPreference {
name: "port"
label: qsTr("Port")
display: P.TextFieldPreference.ExpandLabel
editable: true
from: 1
to: 65535
value: String(value)
defaultValue: Common.defaultServerCFG["server"]["port"]
}
P.SpinPreference {
name: "maxclient"
label: qsTr("Max Number of Clients")
message: qsTr("Maximum number of server connections\n(All ADV widgets share one connection).")
display: P.TextFieldPreference.ExpandLabel
editable: true
from: 1
to: 15
value: String(value)
defaultValue: Common.defaultServerCFG["server"]["maxclient"]
}
P.SwitchPreference {
id: _server_logger
name: "logger"
label: qsTr("Enable Logging")
message: qsTr("Enable to output log file (ADV_Log.log).")
defaultValue: Common.defaultServerCFG["server"]["logger"]
}
P.ItemPreference {
label: qsTr("Open Log File")
Layout.fillWidth: true
enabled: _debug.enabled
select: function () {
NVG.SystemCall.execute("explorer", NVG.Url.toLocalFile(Qt.resolvedUrl("../bin/ADV_Log.log")).replace(/\//g, '\\'));
}
}
}
P.PreferenceGroup {
Layout.fillWidth: true
name: "fft"
Heading { text: qsTr("Data") }
P.SpinPreference {
name: "attack"
label: qsTr("Increase Speed")
display: P.TextFieldPreference.ExpandLabel
editable: true
from: 1
to: 200
defaultValue: Common.defaultServerCFG["fft"]["attack"]
}
P.SpinPreference {
name: "decay"
label: qsTr("Reduction Speed")
display: P.TextFieldPreference.ExpandLabel
editable: true
from: 1
to: 200
defaultValue: Common.defaultServerCFG["fft"]["decay"]
}
P.SpinPreference {
name: "peakthr"
label: qsTr("Peak Extra Increment")
message: qsTr("Extra increment of data normalization peak.")
display: P.TextFieldPreference.ExpandLabel
editable: true
from: 0
to: 1000
defaultValue: Common.defaultServerCFG["fft"]["peakthr"]
}
P.SpinPreference {
name: "norspeed"
label: qsTr("Dynamic Normalization Factor")
message: qsTr("Convergence speed of data normalization peak.")
display: P.TextFieldPreference.ExpandLabel
editable: true
from: 1
to: 100
defaultValue: Common.defaultServerCFG["fft"]["norspeed"]
}
P.SpinPreference {
id: _fps
name: "fps"
label: qsTr("Transmission Rate")
message: qsTr("Number of data sent per second.")
display: P.TextFieldPreference.ExpandLabel
editable: true
from: 10
to: 60
defaultValue: Common.defaultServerCFG["fft"]["fps"]
}
P.SpinPreference {
name: "changespeed"
label: qsTr("Change Speed")
message: qsTr("Adjust the data change speed.")
display: P.TextFieldPreference.ExpandLabel
editable: true
from: 1
to: _fps.value - 1
defaultValue: Common.defaultServerCFG["fft"]["changespeed"]
}
}
Component.onCompleted: {
rootPreference.load(Common.serverCFG)
}
}
}
}
}
}
onClosing: {
serverDialog.active = false;
}
}

View File

@ -11,7 +11,7 @@ import "."
NVG.Window {
id: window
title: qsTr("ADV-Plugin: Settings")
title: qsTr("ADV-Style: Settings")
visible: true
minimumWidth: 480
minimumHeight: 600
@ -26,7 +26,7 @@ NVG.Window {
anchors.fill: parent
header: TitleBar {
text: qsTr("Settings")
text: qsTr("Style Settings")
standardButtons: Dialog.Save | Dialog.Reset
onAccepted: {
@ -82,7 +82,7 @@ NVG.Window {
defaultValue: 0
model: Common.styles
}
Heading {
id: heading
text: Common.styles[styleList.value] + " " + qsTr("Configuration")

View File

@ -4,15 +4,12 @@ import "."
WebSocket {
property string wsIp: "localhost"
property int wsPort: 5050
url: "ws://" + wsIp + ":" + wsPort
url: "ws://" + Common.wsIp + ":" + Common.wsPort
active: true
onStatusChanged: {
if(status === WebSocket.Closed || status === WebSocket.Error) {
Common.wsocketClosed();
Common.rebootFlag = true;
}
}