Serverlist (#360)
Some checks are pending
Check Whitespace and New Line / check (push) Waiting to run
Deploy Sphinx documentation to Pages / pages (push) Waiting to run

## 服务器列表

- 重制了之前的加入服务器与保存密码的页面,以及功能
- 密码在本地以明文保存
- 根据游戏目录中的server-list.json读取公共服务器列表,还没做自动更新
- 可能有不少bug
This commit is contained in:
notify 2024-07-03 01:31:22 +08:00 committed by GitHub
parent 79ede70b6b
commit 0325c73443
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 356 additions and 313 deletions

1
.gitignore vendored
View File

@ -31,6 +31,7 @@ freekill-wrap.cxx
/freekill.server.error.log
/freekill.server.info.log
/flist.txt
/server-list.json
# windeployqt
/bearer/

View File

@ -6,7 +6,7 @@
cmake_minimum_required(VERSION 3.16)
project(FreeKill VERSION 0.4.18)
project(FreeKill VERSION 0.4.19)
add_definitions(-DFK_VERSION=\"${CMAKE_PROJECT_VERSION}\")
find_package(Qt6 REQUIRED COMPONENTS

View File

@ -10,7 +10,8 @@ QtObject {
property real winHeight
property var conf: ({})
property string lastLoginServer
property var savedPassword: ({})
//property var savedPassword: ({})
property var favoriteServers: []
property string lobbyBg
property string roomBg
property string bgmFile
@ -39,6 +40,7 @@ QtObject {
// Player property of client
property string serverAddr
property int serverPort
property string screenName: ""
property string password: ""
property string cipherText
@ -63,6 +65,43 @@ QtObject {
// disableGeneralSchemes[disableSchemeIdx] = disabledGenerals;
// }
function findFavorite(addr, port) {
for (const s of favoriteServers) {
if (s.addr === addr && s.port === port) {
return s;
}
}
return undefined;
}
function removeFavorite(addr, port) {
for (const i in favoriteServers) {
const s = favoriteServers[i];
if (s.addr === addr && s.port === port) {
favoriteServers.splice(i, 1);
saveConf();
return;
}
}
}
function addFavorite(addr, port, name, username, password) {
for (const i in favoriteServers) {
const s = favoriteServers[i];
if (s.addr === addr && s.port === port) {
s.name = name;
s.username = username;
s.password = password;
saveConf();
return false;
}
}
favoriteServers.unshift({ addr, port, name, username, password });
saveConf();
return true;
}
function loadConf() {
conf = JSON.parse(Backend.loadConf());
winX = conf.winX ?? 100;
@ -70,7 +109,8 @@ QtObject {
winWidth = conf.winWidth ?? 960;
winHeight = conf.winHeight ?? 540;
lastLoginServer = conf.lastLoginServer ?? "127.0.0.1";
savedPassword = conf.savedPassword ?? {};
//savedPassword = conf.savedPassword ?? {};
favoriteServers = conf.favoriteServers ?? [];
lobbyBg = conf.lobbyBg ?? AppPath + "/image/background";
roomBg = conf.roomBg ?? AppPath + "/image/gamebg";
bgmFile = conf.bgmFile ?? AppPath + "/audio/system/bgm.mp3";
@ -116,7 +156,8 @@ QtObject {
conf.winWidth = realMainWin.width;
conf.winHeight = realMainWin.height;
conf.lastLoginServer = lastLoginServer;
conf.savedPassword = savedPassword;
//conf.savedPassword = savedPassword;
conf.favoriteServers = favoriteServers;
conf.lobbyBg = lobbyBg;
conf.roomBg = roomBg;
conf.bgmFile = bgmFile;

View File

@ -26,7 +26,8 @@ callbacks["ServerDetected"] = (j) => {
}
const item = serverDialog.item;
if (item) {
toast.show(qsTr("Detected Server %1").arg(j.slice(7)), 10000);
// toast.show(qsTr("Detected Server %1").arg(j.slice(7)), 10000);
item.addLANServer(j.slice(7))
}
}
@ -38,7 +39,9 @@ callbacks["GetServerDetail"] = (j) => {
}
const item = serverDialog.item;
if (item) {
item.updateServerDetail(addr, [ver, icon, desc, capacity, count]);
let [_addr, port] = addr.split(',');
port = parseInt(port);
item.updateServerDetail(_addr, port, [ver, icon, desc, capacity, count]);
}
}
@ -46,18 +49,18 @@ callbacks["NetworkDelayTest"] = (jsonData) => {
// jsonData: RSA pub key
let cipherText;
let aeskey;
const savedPw = config.savedPassword[config.serverAddr];
if (savedPw?.shorten_password === config.password) {
cipherText = config.savedPassword[config.serverAddr].password;
aeskey = config.savedPassword[config.serverAddr].key;
config.aeskey = aeskey ?? "";
Backend.setAESKey(aeskey);
if (Debugging)
console.log("use remembered password", config.password);
} else {
// const savedPw = config.savedPassword[config.serverAddr];
// if (savedPw?.shorten_password === config.password) {
// cipherText = config.savedPassword[config.serverAddr].password;
// aeskey = config.savedPassword[config.serverAddr].key;
// config.aeskey = aeskey ?? "";
// Backend.setAESKey(aeskey);
// if (Debugging)
// console.log("use remembered password", config.password);
// } else {
cipherText = Backend.pubEncrypt(jsonData, config.password);
config.aeskey = Backend.getAESKey();
}
// }
config.cipherText = cipherText;
Backend.replyDelayTest(config.screenName, cipherText);
}
@ -130,12 +133,12 @@ callbacks["EnterLobby"] = (jsonData) => {
if (mainStack.depth === 1) {
// we enter the lobby successfully, so save password now.
config.lastLoginServer = config.serverAddr;
config.savedPassword[config.serverAddr] = {
username: config.screenName,
password: config.cipherText,
key: config.aeskey,
shorten_password: config.cipherText.slice(0, 8)
}
// config.savedPassword[config.serverAddr] = {
// username: config.screenName,
// password: config.cipherText,
// key: config.aeskey,
// shorten_password: config.cipherText.slice(0, 8)
// }
mainStack.push(lobby);
} else {
mainStack.pop();

View File

@ -60,12 +60,16 @@ Item {
text: qsTr("Console start")
onClicked: {
config.serverAddr = "127.0.0.1";
const serverCfg = config.savedPassword["127.0.0.1"] ?? {};
config.screenName = serverCfg.username ?? "player";
config.password = serverCfg.shorten_password ?? "1234";
config.serverPort = 9527;
// const serverCfg = config.savedPassword["127.0.0.1"] ?? {};
const serverCfg = config.findFavorite("127.0.0.1", 9527);
config.screenName = serverCfg?.username ?? "player";
config.password = serverCfg?.password ?? "1234";
mainWindow.busy = true;
config.addFavorite(config.serverAddr, config.serverPort, "",
config.screenName, config.password);
Backend.startServer(9527);
Backend.joinServer("127.0.0.1");
Backend.joinServer("127.0.0.1", 9527);
}
}

View File

@ -3,10 +3,12 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Fk
Item {
id: root
anchors.fill: parent
property var selectedServer: serverModel.get(serverList.currentIndex)
Timer {
id: opTimer
@ -18,18 +20,24 @@ Item {
Item {
height: 64
width: serverList.width - 48
clip: true
width: serverList.width / 2 - 4
RowLayout {
anchors.fill: parent
spacing: 16
Item {}
Image {
Layout.preferredHeight: 60
Layout.preferredWidth: 60
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Layout.preferredHeight: 56
Layout.preferredWidth: 56
fillMode: Image.PreserveAspectFit
source: favicon
source: {
if (!favicon) return SkinBank.MISC_DIR + "server_icon";
if (favicon === "default") return AppPath + "/image/icon.png";
return favicon;
}
}
ColumnLayout {
@ -37,22 +45,51 @@ Item {
Text {
Layout.fillWidth: true
horizontalAlignment: Text.AlignLeft
text: serverIP + " " + misMatchMsg
text: {
if (name) return name;
let a = addr;
let p = port;
if (p === 9527) p = 0;
if (a.includes(":") && p) { // IPv6
a = `[${a}]`;
}
if (p) {
p = `:${p}`;
} else {
p = "";
}
return `${a}${p}`;
}
font.bold: true
color: favicon ? "black" : "gray"
}
Text {
Layout.fillWidth: true
horizontalAlignment: Text.AlignLeft
text: description
text: delay + " ms " + misMatchMsg
textFormat: TextEdit.RichText
color: {
if (delay < 0) {
return "gray";
} else if (delay >= 0 && delay < 100) {
return "green";
} else if (delay >= 100 && delay < 500) {
return "orange";
} else {
return "red";
}
}
}
}
Text {
text: online + "/" + capacity
font.pixelSize: 30
text: online + "/<font size='1'>" + capacity + "</font>"
font.pixelSize: 26
color: favicon ? "black" : "gray"
}
Item {}
}
TapHandler {
@ -64,90 +101,51 @@ Item {
}
}
}
ColumnLayout {
x: 6
height: parent.height
Item { Layout.fillHeight: true }
Image {
Layout.preferredWidth: 24; Layout.preferredHeight: 23
source: SkinBank.MISC_DIR + "network_local"
visible: lan
}
Image {
Layout.preferredWidth: 24; Layout.preferredHeight: 23
source: SkinBank.MISC_DIR + "favorite"
visible: favorite
}
}
}
}
ListView {
id: serverList
height: parent.height - controlPanel.height - 30
width: parent.width - 80
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 10
contentHeight: serverDelegate.height * count
model: ListModel {
id: serverModel
RowLayout {
id: serverListBar
height: childrenRect.height
width: serverList.width
Text {
text: "已收藏服务器与公共服务器列表"
font.pixelSize: 18
font.bold: true
x: 32; y: 8
}
delegate: serverDelegate
ScrollBar.vertical: ScrollBar {}
clip: true
highlight: Rectangle {
color: "#AA9ABFEF"; radius: 5
// border.color: "black"; border.width: 2
}
// highlightMoveDuration: 0
currentIndex: -1
}
GridLayout {
id: controlPanel
anchors.top: serverList.bottom
anchors.topMargin: 10
width: parent.width - 80
anchors.horizontalCenter: parent.horizontalCenter
height: joinButton.height * 2 + 10
columns: 3
Item { Layout.fillWidth: true }
Button {
id: joinButton
Layout.fillWidth: true
enabled: serverList.currentIndex !== -1
text: qsTr("Join Server")
onClicked: {
const item = serverModel.get(serverList.currentIndex);
const serverCfg = config.savedPassword[item.serverIP];
config.serverAddr = item.serverIP;
config.screenName = serverCfg.username;
config.password = serverCfg.shorten_password ?? serverCfg.password;
mainWindow.busy = true;
Backend.joinServer(item.serverIP);
}
}
Button {
Layout.fillWidth: true
text: qsTr("Add New Server")
onClicked: {
drawerLoader.sourceComponent = newServerComponent;
drawer.open();
}
}
Button {
Layout.fillWidth: true
enabled: serverList.currentIndex !== -1
text: qsTr("Edit Server")
onClicked: {
drawerLoader.sourceComponent = editServerComponent;
drawer.open();
}
}
Button {
Layout.fillWidth: true
text: qsTr("Refresh List")
enabled: !opTimer.running
onClicked: {
opTimer.start();
for (let i = 0; i < serverModel.count; i++) {
const item = serverModel.get(i);
Backend.getServerInfo(item.serverIP);
if (!item.favorite && !item.lan) break;
item.delayBegin = (new Date).getTime();
Backend.getServerInfo(item.addr, item.port);
}
}
}
Button {
Layout.fillWidth: true
text: qsTr("Detect LAN")
enabled: !opTimer.running
onClicked: {
@ -157,251 +155,234 @@ Item {
}
Button {
Layout.fillWidth: true
text: qsTr("Go Back")
onClicked: serverDialog.hide();
}
}
Component {
id: newServerComponent
ColumnLayout {
signal finished();
Text {
text: qsTr("@NewServer")
font.pixelSize: 24
font.bold: true
Layout.fillWidth: true
wrapMode: Text.WordWrap
}
Text {
text: qsTr("@NewServerHint")
font.pixelSize: 16
Layout.fillWidth: true
wrapMode: Text.WordWrap
}
id: serverPanel
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 8
height: parent.height - 16
width: parent.width * 0.3
TextField {
id: serverAddrEdit
Layout.fillWidth: true
placeholderText: qsTr("Server Addr")
text: ""
}
TextField {
id: screenNameEdit
maximumLength: 32
Layout.fillWidth: true
placeholderText: qsTr("Username")
text: ""
}
TextField {
id: passwordEdit
id: addressEdit
maximumLength: 64
Layout.fillWidth: true
placeholderText: qsTr("Password")
text: ""
echoMode: showPasswordCheck.checked ? TextInput.Normal
: TextInput.Password
passwordCharacter: "*"
placeholderText: "服务器地址"
text: selectedServer?.addr ?? ""
}
CheckBox {
id: showPasswordCheck
text: qsTr("Show Password")
}
Button {
Layout.fillWidth: true
enabled: serverAddrEdit.text !== "" && screenNameEdit.text !== ""
&& passwordEdit.text !== ""
text: "OK"
onClicked: {
root.addNewServer(serverAddrEdit.text, screenNameEdit.text,
passwordEdit.text);
finished();
}
}
}
}
Component {
id: editServerComponent
ColumnLayout {
signal finished();
Text {
text: qsTr("@EditServer")
font.pixelSize: 24
font.bold: true
Layout.fillWidth: true
wrapMode: Text.WordWrap
}
Text {
text: qsTr("@EditServerHint")
font.pixelSize: 16
Layout.fillWidth: true
wrapMode: Text.WordWrap
}
TextField {
id: screenNameEdit
maximumLength: 32
id: portEdit
maximumLength: 6
Layout.fillWidth: true
placeholderText: qsTr("Username")
text: ""
placeholderText: "端口"
text: selectedServer?.port ?? ""
}
TextField {
id: passwordEdit
maximumLength: 64
Flickable {
Layout.fillHeight: true
Layout.fillWidth: true
placeholderText: qsTr("Password")
text: ""
echoMode: showPasswordCheck.checked ? TextInput.Normal
: TextInput.Password
passwordCharacter: "*"
}
CheckBox {
id: showPasswordCheck
text: qsTr("Show Password")
}
Button {
Layout.fillWidth: true
enabled: screenNameEdit.text !== "" && passwordEdit.text !== ""
text: "OK"
onClicked: {
root.editCurrentServer(screenNameEdit.text, passwordEdit.text);
finished();
}
}
Button {
Layout.fillWidth: true
text: qsTr("Delete Server")
onClicked: {
root.deleteCurrentServer();
finished();
}
}
}
}
Drawer {
id: drawer
width: parent.width * 0.3 / mainWindow.scale
height: parent.height / mainWindow.scale
dim: false
contentHeight: descText.height
clip: true
dragMargin: 0
scale: mainWindow.scale
transformOrigin: Item.TopLeft
Loader {
id: drawerLoader
anchors.fill: parent
anchors.margins: 16
onSourceChanged: {
if (item === null)
return;
item.finished.connect(() => {
sourceComponent = undefined;
drawer.close();
});
Text {
id: descText
width: parent.width
text: selectedServer?.description ?? ""
wrapMode: Text.WrapAnywhere
font.pixelSize: 18
}
}
RowLayout {
Layout.fillWidth: true
TextField {
id: usernameEdit
maximumLength: 32
Layout.fillWidth: true
placeholderText: "用户名"
text: selectedServer?.username ?? ""
}
TextField {
id: passwordEdit
maximumLength: 32
Layout.fillWidth: true
placeholderText: "密码"
passwordCharacter: "*"
echoMode: TextInput.Password
text: selectedServer?.password ?? ""
}
}
Button {
text: "登录(首次登录自动注册)"
Layout.fillWidth: true
enabled: !!(addressEdit.text && portEdit.text &&
usernameEdit.text && passwordEdit.text)
onClicked: {
const _addr = addressEdit.text;
const _port = parseInt(portEdit.text);
const _username = usernameEdit.text;
const _password = passwordEdit.text;
config.screenName = _username;
config.password = _password;
mainWindow.busy = true;
config.serverAddr = _addr;
config.serverPort = _port;
let name = selectedServer?.name;
if (_addr !== selectedServer?.addr || _port !== selectedServer?.port) {
name = "";
}
addFavorite(config.serverAddr, config.serverPort, name,
config.screenName, config.password);
Backend.joinServer(_addr, _port);
}
}
Button {
text: "从收藏夹删除"
Layout.fillWidth: true
visible: !!(selectedServer?.favorite)
onClicked: {
removeFavorite(selectedServer.addr, selectedServer.port);
}
onSourceComponentChanged: sourceChanged();
}
}
function addNewServer(addr, name, password) {
if (config.savedPassword[addr]) {
GridView {
id: serverList
height: parent.height - 16 - serverListBar.height
width: parent.width - 24 - serverPanel.width
anchors.top: serverListBar.bottom
anchors.left: parent.left
anchors.margins: 8
model: ListModel { id: serverModel }
delegate: serverDelegate
cellHeight: 64 + 8
cellWidth: serverList.width / 2
clip: true
highlight: Rectangle {
color: "#AA9ABFEF"; radius: 5
// border.color: "black"; border.width: 2
}
currentIndex: -1
}
function addFavorite(addr, port, name, username, password) {
const newItem = config.addFavorite(addr, port, name, username, password);
if (!newItem) {
for (let i = 0; i < serverModel.count; i++) {
const s = serverModel.get(i);
if (s.addr === addr && s.port === port && s.favorite) {
s.name = name;
s.username = username;
s.password = password;
return;
}
config.savedPassword[addr] = {
username: name,
password: password,
};
config.saveConf();
serverModel.append({
serverIP: addr,
}
}
serverModel.insert(0, {
addr, port, name, username, password,
misMatchMsg: "",
description: qsTr("Server not up"),
online: "-",
capacity: "-",
favicon: "https://img1.imgtp.com/2023/07/01/DGUdj8eu.png",
online: "?",
capacity: "??",
favicon: "",
delayBegin: (new Date).getTime(),
delay: -1,
favorite: true,
lan: false,
});
Backend.getServerInfo(addr);
Backend.getServerInfo(addr, port);
}
function editCurrentServer(name, password) {
const addr = serverModel.get(serverList.currentIndex).serverIP;
if (!config.savedPassword[addr]) {
return;
}
config.savedPassword[addr] = {
username: name,
password: password,
shorten_password: undefined,
key: undefined,
};
config.saveConf();
}
function deleteCurrentServer() {
const addr = serverModel.get(serverList.currentIndex).serverIP;
if (!config.savedPassword[addr]) {
return;
}
config.savedPassword[addr] = undefined;
config.saveConf();
serverModel.remove(serverList.currentIndex, 1);
function removeFavorite(addr, port) {
config.removeFavorite(addr, port);
for (let i = 0; i < serverModel.count; i++) {
const s = serverModel.get(i);
if (s.addr === addr && s.port === port && s.favorite) {
serverModel.remove(i);
serverList.currentIndex = -1;
return;
}
}
}
function updateServerDetail(addr, data) {
function addLANServer(addr) {
const port = 9527;
if (config.findFavorite(addr, port)) return;
for (let i = 0; i < serverModel.count; i++) {
const s = serverModel.get(i);
if (s.addr === addr && s.port === port && s.lan) {
s.delayBegin = (new Date).getTime();
Backend.getServerInfo(addr, port);
return;
}
if (!s.lan && !s.favorite) break;
}
serverModel.insert(0, {
addr, port,
name: "",
username: "",
password: "",
misMatchMsg: "",
description: qsTr("Server not up"),
online: "?",
capacity: "??",
favicon: "",
delayBegin: (new Date).getTime(),
delay: -1,
favorite: false,
lan: true,
});
Backend.getServerInfo(addr, port);
}
function updateServerDetail(addr, port, data) {
const [ver, icon, desc, capacity, count] = data;
for (let i = 0; i < serverModel.count; i++) {
const item = serverModel.get(i);
const ip = item.serverIP;
if (addr.endsWith(ip)) { // endsWithIPv6ip
const ip = item.addr;
const itemPort = item.port;
if (addr === ip && port == itemPort) {
const ms = (new Date).getTime();
item.misMatchMsg = "";
if (FkVersion !== ver) {
item.misMatchMsg = qsTr("@VersionMismatch").arg(ver);
}
item.delay = ms - item.delayBegin;
item.description = desc;
item.favicon = icon;
item.online = count.toString();
item.capacity = capacity.toString();
return;
}
}
}
function loadConfig() {
if (serverModel.count > 0) {
return;
}
for (let key in config.savedPassword) {
if (serverModel.count > 0) { return; }
const serverList = JSON.parse(Backend.getPublicServerList());
serverList.unshift(...config.favoriteServers);
for (const server of serverList) {
let { addr, port, name, username, password } = server;
name = name ?? "";
username = username ?? "";
password = password ?? "";
if (port === -1) break;
if (!password && config.findFavorite(addr, port)) continue;
serverModel.append({
serverIP: key,
addr, port, name, username, password,
misMatchMsg: "",
description: qsTr("Server not up"),
online: "-",
capacity: "-",
online: "?",
capacity: "??",
favicon: "",
delayBegin: (new Date).getTime(),
delay: -1,
favorite: !!password,
lan: false,
});
Backend.getServerInfo(key);
Backend.getServerInfo(addr, port);
}
}
}

View File

@ -18,6 +18,7 @@ var EQUIP_ICON_DIR = AppPath + "/image/card/equipIcon/";
var PIXANIM_DIR = AppPath + "/image/anim/"
var TILE_ICON_DIR = AppPath + "/image/button/tileicon/"
var LOBBY_IMG_DIR = AppPath + "/image/lobby/";
var MISC_DIR = AppPath + "/image/misc/";
const searchPkgResource = function(path, name, suffix) {
let ret;

View File

@ -3,8 +3,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.notify.FreeKill"
android:installLocation="preferExternal"
android:versionCode="418"
android:versionName="0.4.18">
android:versionCode="419"
android:versionName="0.4.19">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

View File

@ -1,7 +1,7 @@
{
"banwords": [],
"description": "FreeKill Server",
"iconUrl": "https://img1.imgtp.com/2023/07/01/DGUdj8eu.png",
"iconUrl": "default",
"capacity": 100,
"tempBanTime": 20,
"motd": "Welcome!",

BIN
image/misc/favorite.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
image/misc/server_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -21,7 +21,7 @@
<message>
<source>@VersionMismatch</source>
<translation>&lt;font color="red" size="4">&lt;b>Mismatch version: server is at v%1&lt;/b>&lt;/font></translation>
<translation>&lt;font color="red" size="4">&lt;b>!! v%1&lt;/b>&lt;/font></translation>
</message>
<message>

View File

@ -242,7 +242,7 @@
<message>
<source>@VersionMismatch</source>
<translation>&lt;font color="red" size="4">&lt;b>v%1&lt;/b>&lt;/font></translation>
<translation>&lt;font color="red" size="4">&lt;b>!! v%1&lt;/b>&lt;/font></translation>
</message>
<message>
<source>Server not up</source>

View File

@ -386,7 +386,7 @@ void Server::readConfig() {
// defaults
SET_DEFAULT_CONFIG("description", "FreeKill Server");
SET_DEFAULT_CONFIG("iconUrl", "https://img1.imgtp.com/2023/07/01/DGUdj8eu.png");
SET_DEFAULT_CONFIG("iconUrl", "default");
SET_DEFAULT_CONFIG("capacity", 100);
SET_DEFAULT_CONFIG("tempBanTime", 20);
SET_DEFAULT_CONFIG("motd", "Welcome!");

View File

@ -210,7 +210,7 @@ void QmlBackend::startServer(ushort port) {
}
}
void QmlBackend::joinServer(QString address) {
void QmlBackend::joinServer(QString address, ushort port) {
if (ClientInstance != nullptr)
return;
Client *client = new Client(this);
@ -222,6 +222,7 @@ void QmlBackend::joinServer(QString address) {
emit notifyUI("ErrorMsg", msg);
emit notifyUI("BackToStart", "[]");
});
/*
QString addr = "127.0.0.1";
ushort port = 9527u;
@ -232,7 +233,7 @@ void QmlBackend::joinServer(QString address) {
} else {
addr = address;
// SRV解析查询
QDnsLookup* dns = new QDnsLookup(QDnsLookup::SRV, "_freekill._tcp." + addr);
QDnsLookup *dns = new QDnsLookup(QDnsLookup::SRV, "_freekill._tcp." + addr);
QEventLoop eventLoop;
// 阻塞的SRV解析查询回调
connect(dns, &QDnsLookup::finished,[&eventLoop](void){
@ -250,8 +251,9 @@ void QmlBackend::joinServer(QString address) {
}
}
}
*/
client->connectToHost(addr, port);
client->connectToHost(address, port);
}
void QmlBackend::quitLobby(bool close) {
@ -327,6 +329,22 @@ QVariant QmlBackend::evalLuaExp(const QString &lua) {
return result;
}
QString QmlBackend::getPublicServerList() {
QFile conf("server-list.json");
// TODO: Download new JSON via http
if (!conf.exists()) {
conf.open(QIODevice::WriteOnly);
static const char *init_conf = "{}";
conf.write(init_conf);
conf.close();
return init_conf;
}
conf.open(QIODevice::ReadOnly);
auto ret = conf.readAll();
conf.close();
return ret;
}
QString QmlBackend::pubEncrypt(const QString &key, const QString &data) {
// 在用公钥加密口令时也随机生成AES密钥/IV并随着口令一起加密
// AES密钥和IV都是固定16字节的所以可以放在开头
@ -473,21 +491,14 @@ void QmlBackend::detectServer() {
9527);
}
void QmlBackend::getServerInfo(const QString &address) {
QString addr = "127.0.0.1";
ushort port = 9527u;
void QmlBackend::getServerInfo(const QString &address, ushort port) {
QString addr = address;
// ushort port = 9527u;
static const char *ask_str = "fkGetDetail,";
if (address.contains(QChar(':'))) {
QStringList texts = address.split(QChar(':'));
addr = texts.value(0);
port = texts.value(1).toUShort();
} else {
addr = address;
}
QByteArray ask(ask_str);
ask.append(address.toLatin1());
ask.append(QString(",%1").arg(port).toUtf8());
if (QHostAddress(addr).isNull()) { // 不是ip考虑解析域名
QHostInfo::lookupHost(addr, this, [=](const QHostInfo &host) {

View File

@ -33,7 +33,7 @@ public:
void setEngine(QQmlApplicationEngine *engine);
Q_INVOKABLE void startServer(ushort port);
Q_INVOKABLE void joinServer(QString address);
Q_INVOKABLE void joinServer(QString address, ushort port = 9527);
// Lobby
Q_INVOKABLE void quitLobby(bool close = true);
@ -44,6 +44,7 @@ public:
QVariantList params);
Q_INVOKABLE QVariant evalLuaExp(const QString &lua);
Q_INVOKABLE QString getPublicServerList();
Q_INVOKABLE QString pubEncrypt(const QString &key, const QString &data);
Q_INVOKABLE QString loadConf();
Q_INVOKABLE QString loadTips();
@ -62,7 +63,7 @@ public:
Q_INVOKABLE void createModBackend();
Q_INVOKABLE void detectServer();
Q_INVOKABLE void getServerInfo(const QString &addr);
Q_INVOKABLE void getServerInfo(const QString &addr, ushort port = 9527u);
Q_INVOKABLE void showDialog(const QString &type, const QString &text,
const QString &orig = QString());