Browse Source

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

- 优化服务器程序的错误捕捉与日志输出
- 优化翻译
master
mashiros 2 years ago
parent
commit
d0aed6f101
  1. BIN
      Locales/ja.qm
  2. BIN
      Locales/zh.qm
  3. BIN
      Locales/zh_TW.qm
  4. BIN
      bin/ADVServer.exe
  5. 14
      bin/advConfig.ini
  6. 22
      module.qml
  7. 8
      package.json
  8. 166
      qml/Common.qml
  9. 10
      qml/Main.qml
  10. 220
      qml/ServerPreferences.qml
  11. 6
      qml/StylePreferences.qml
  12. 7
      qml/WSocket.qml

BIN
Locales/ja.qm

Binary file not shown.

BIN
Locales/zh.qm

Binary file not shown.

BIN
Locales/zh_TW.qm

Binary file not shown.

BIN
bin/ADVServer.exe

Binary file not shown.

14
bin/advConfig.ini

@ -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

22
module.qml

@ -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 { }
}
}

8
package.json

@ -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"
}
]
}
}

166
qml/Common.qml

@ -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);
}
}
}

10
qml/Main.qml

@ -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

@ -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;
}
}

6
qml/StylePreferences.qml

@ -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")

7
qml/WSocket.qml

@ -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;
}
}

Loading…
Cancel
Save