修了一些需要重新编译的bug

修大厅卡死尸体
修“已经有人登入”
修服务端翻译文件
增加出牌时间设置
修Linux下复制文件bug
再次尝试wasm
This commit is contained in:
notify 2023-04-30 18:54:23 +08:00 committed by GitHub
parent 3dfff72836
commit 34ce4c9859
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 380 additions and 111 deletions

View File

@ -5,10 +5,8 @@ cmake_minimum_required(VERSION 3.16)
project(FreeKill VERSION 0.1.6)
add_definitions(-DFK_VERSION=\"${CMAKE_PROJECT_VERSION}\")
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
include_directories(fkparse/src)
add_subdirectory(fkparse)
endif ()
include_directories(fkparse/src)
add_subdirectory(fkparse)
find_package(Qt6 REQUIRED COMPONENTS
Network
@ -86,14 +84,53 @@ add_custom_command(
)
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
file(GLOB_RECURSE FK_RESOURCE_FILES
RELATIVE ${PROJECT_SOURCE_DIR}
*.lua *.qml *.js *.png *.jpg *.mp3
)
list(APPEND FK_RESOURCE_FILES "fonts/FZLBGBK.ttf")
qt_add_resources(FreeKill "qrc"
PREFIX "/"
FILES ${FK_RESOURCE_FILES}
)
set(CMAKE_MODULE_LINKER_FLAGS ${CMAKE_MODULE_LINKER_FLAGS}
"-s INITIAL_MEMORY=64MB"
)
file(GLOB_RECURSE FK_SCRIPT_FILES
RELATIVE ${PROJECT_SOURCE_DIR}
*.lua *.qml *.js *.fkp *.sql zh_CN.qm
)
qt_add_resources(FreeKill "scripts_qrc"
PREFIX "/"
FILES ${FK_SCRIPT_FILES}
)
qt_add_resources(FreeKill "font_qrc"
PREFIX "/"
FILES "fonts/FZLBGBK.ttf"
)
file(GLOB_RECURSE FK_IMG_FILES
RELATIVE ${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/image/*.jpg
${PROJECT_SOURCE_DIR}/image/*.png
)
qt_add_resources(FreeKill "img_qrc"
PREFIX "/"
FILES ${FK_IMG_FILES}
)
file(GLOB_RECURSE FK_AUDIO_FILES
RELATIVE ${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/audio/*.mp3
)
qt_add_resources(FreeKill "audio_qrc"
PREFIX "/"
FILES ${FK_AUDIO_FILES}
)
file(GLOB_RECURSE FK_PKG_FILES
RELATIVE ${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/packages/*.mp3
${PROJECT_SOURCE_DIR}/packages/*.jpg
${PROJECT_SOURCE_DIR}/packages/*.png
)
qt_add_resources(FreeKill "pkg_qrc"
PREFIX "/"
FILES ${FK_PKG_FILES}
)
endif()
add_subdirectory(src)

@ -1 +1 @@
Subproject commit 64481662879765f5631a291d512f7a74125051f3
Subproject commit fd7023f0752bfaa6fc5230ef1b1835eb4dfefe2f

View File

@ -30,6 +30,7 @@ Fk:loadTranslationTable{
["$RoomName"] = "%1的房间",
["Player num"] = "玩家数目",
["Select general num"] = "选将数目",
["Operation timeout"] = "操作时长(秒)",
["Game Mode"] = "游戏模式",
["Enable free assign"] = "自由选将",
["Enable deputy general"] = "启用副将机制",

View File

@ -23,6 +23,8 @@ QtObject {
property real bgmVolume
property bool disableMsgAudio
property int preferredTimeout
// Player property of client
property string serverAddr
property string screenName: ""
@ -56,6 +58,7 @@ QtObject {
Backend.volume = conf.effectVolume ?? 50.;
bgmVolume = conf.bgmVolume ?? 50.;
disableMsgAudio = conf.disableMsgAudio ?? false;
preferredTimeout = conf.preferredTimeout ?? 15;
}
function saveConf() {
@ -77,6 +80,7 @@ QtObject {
conf.effectVolume = Backend.volume;
conf.bgmVolume = bgmVolume;
conf.disableMsgAudio = disableMsgAudio;
conf.preferredTimeout = preferredTimeout;
Backend.saveConf(JSON.stringify(conf, undefined, 2));
}

View File

@ -5,8 +5,6 @@ import QtQuick.Controls
import QtQuick.Layouts
ColumnLayout {
spacing: 20
RowLayout {
anchors.rightMargin: 8
spacing: 16
@ -80,6 +78,24 @@ ColumnLayout {
}
}
RowLayout {
anchors.rightMargin: 8
spacing: 16
Text {
text: Backend.translate("Operation timeout")
}
SpinBox {
from: 10
to: 60
editable: true
value: config.preferredTimeout
onValueChanged: {
config.preferredTimeout = value;
}
}
}
Switch {
id: freeAssignCheck
checked: Debugging ? true : false
@ -102,7 +118,7 @@ ColumnLayout {
mainWindow.busy = true;
ClientInstance.notifyServer(
"CreateRoom",
JSON.stringify([roomName.text, playerNum.value, {
JSON.stringify([roomName.text, playerNum.value, config.preferredTimeout, {
enableFreeAssign: freeAssignCheck.checked,
enableDeputy: deputyCheck.checked,
gameMode: config.preferedMode,

View File

@ -1,65 +1,187 @@
// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
Item {
id: root
scale: 2
// Change this to your server's IP or domain name
property string server_addr: ServerAddr
Frame {
id: join_server
Item {
width: 960 * 0.8
height: 540 * 0.8
anchors.centerIn: parent
background: Rectangle {
color: "#88888888"
radius: 2
Item {
id: left
width: 300
height: parent.height
Image {
id: lady
width: parent.width + 20
height: parent.height
fillMode: Image.PreserveAspectFit
}
Image {
anchors.bottom: parent.bottom
anchors.bottomMargin: 12
width: parent.width
source: AppPath + "/image/widelogo"
}
}
Column {
spacing: 8
TextField {
id: screenNameEdit
maximumLength: 32
text: "player"
onTextChanged: {
passwordEdit.text = "";
let data = config.savedPassword[server_addr.editText];
if (data) {
if (text === data.username) {
passwordEdit.text = data.shorten_password;
Rectangle {
id: right
anchors.left: left.right
width: parent.width - left.width
height: parent.height
color: "#88EEEEEE"
radius: 16
ColumnLayout {
width: parent.width * 0.8
height: parent.height * 0.8
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 40
//spacing
Text {
text: qsTr("Welcome back!")
font.pixelSize: 28
Layout.alignment: Qt.AlignHCenter
}
GridLayout {
columns: 2
rowSpacing: 20
Text {
text: qsTr("Server Addr")
}
ComboBox {
id: server_addr
Layout.fillWidth: true
model: []
editable: true
onEditTextChanged: {
if (model.indexOf(editText) === -1) {
passwordEdit.text = "";
} else {
let data = config.savedPassword[editText];
screenNameEdit.text = data.username;
passwordEdit.text = data.shorten_password;
}
}
}
Text {
text: qsTr("Username")
}
TextField {
id: screenNameEdit
Layout.fillWidth: true
placeholderText: qsTr("Username")
text: ""
onTextChanged: {
passwordEdit.text = "";
let data = config.savedPassword[server_addr.editText];
if (data) {
if (text === data.username) {
passwordEdit.text = data.shorten_password;
}
}
}
}
CheckBox {
id: showPasswordCheck
text: qsTr("Show Password")
}
TextField {
id: passwordEdit
Layout.fillWidth: true
placeholderText: qsTr("Password")
text: ""
echoMode: showPasswordCheck.checked ? TextInput.Normal : TextInput.Password
passwordCharacter: "*"
}
}
Button {
text: qsTr("Join Server")
Layout.fillWidth: true
display: AbstractButton.TextBesideIcon
icon.name: "go-next"
enabled: passwordEdit.text !== ""
onClicked: {
config.serverAddr = server_addr.editText;
config.screenName = screenNameEdit.text;
config.password = passwordEdit.text;
mainWindow.busy = true;
Backend.joinServer(server_addr.editText);
}
}
Button {
Layout.fillWidth: true
text: qsTr("PackageManage")
onClicked: {
mainStack.push(packageManage);
}
}
}
TextField {
id: passwordEdit
maximumLength: 64
text: ""
echoMode: TextInput.Password
passwordCharacter: "*"
Text {
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.leftMargin: 12
anchors.bottomMargin: 12
text: "FreeKill " + FkVersion
font.pixelSize: 16
font.bold: true
}
Button {
text: "Login"
enabled: passwordEdit.text !== ""
onClicked: {
config.serverAddr = server_addr;
config.screenName = screenNameEdit.text;
config.password = passwordEdit.text;
mainWindow.busy = true;
Backend.joinServer(server_addr);
Text {
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: 8
anchors.bottomMargin: 8
text: qsTr("FAQ")
color: "blue"
font.pixelSize: 24
font.underline: true
TapHandler {
onTapped: {
errDialog.txt = qsTr("$LoginFAQ");
errDialog.open();
}
}
}
}
}
function downloadComplete() {
toast.show(qsTr("updated packages for md5"));
}
Component.onCompleted: {
config.loadConf();
lady.source = config.ladyImg;
server_addr.model = Object.keys(config.savedPassword);
server_addr.onModelChanged();
server_addr.currentIndex = server_addr.model.indexOf(config.lastLoginServer);
let data = config.savedPassword[config.lastLoginServer];
screenNameEdit.text = data.username;
passwordEdit.text = data.shorten_password;
if (data) {
screenNameEdit.text = data.username;
passwordEdit.text = data.shorten_password;
}
}
}

View File

@ -12,6 +12,7 @@ set(freekill_SRCS
"server/server.cpp"
"server/serverplayer.cpp"
"server/room.cpp"
"ui/qmlbackend.cpp"
"swig/freekill-wrap.cxx"
)
@ -19,7 +20,6 @@ if (NOT DEFINED FK_SERVER_ONLY)
list(APPEND freekill_SRCS
"client/client.cpp"
"client/clientplayer.cpp"
"ui/qmlbackend.cpp"
)
endif ()
@ -66,9 +66,11 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
"server/serverplayer.cpp"
"server/room.cpp"
)
set(FKP_LIB "")
set(LUA_LIB ${PROJECT_SOURCE_DIR}/lib/wasm/liblua.a)
set(CRYPTO_LIB ${PROJECT_SOURCE_DIR}/lib/wasm/libcrypto.a)
# set(LUA_LIB ${PROJECT_SOURCE_DIR}/lib/wasm/liblua.a)
# set(CRYPTO_LIB ${PROJECT_SOURCE_DIR}/lib/wasm/libcrypto.a)
# set other libs by yourself
set(IDBFS_LIB idbfs.js)
include(${FK_WASM_TOOLCHAIN})
else ()
set(LUA_LIB lua5.4)
set(SQLITE3_LIB sqlite3)
@ -89,6 +91,7 @@ target_link_libraries(FreeKill PRIVATE
${FKP_LIB}
${QT_LIB}
${GIT_LIB}
${IDBFS_LIB}
)
install(TARGETS FreeKill DESTINATION bin)

View File

@ -60,7 +60,6 @@ void Dumpstack(lua_State *L) {
}
}
#ifndef Q_OS_WASM
sqlite3 *OpenDatabase(const QString &filename, const QString &initSql) {
sqlite3 *ret;
int rc;
@ -123,6 +122,7 @@ void ExecSQL(sqlite3 *db, const QString &sql) {
void CloseDatabase(sqlite3 *db) { sqlite3_close(db); }
#ifndef Q_OS_WASM
RSA *InitServerRSA() {
RSA *rsa = RSA_new();
if (!QFile::exists("server/rsa_pub")) {
@ -222,7 +222,7 @@ QJsonDocument String2Json(const QString &str) {
QString Color(const QString &raw, fkShell::TextColor color,
fkShell::TextType type) {
#ifndef Q_OS_WIN32
#ifdef Q_OS_LINUX
static const char *suffix = "\e[0;0m";
int col = 30 + color;
int t = type == fkShell::Bold ? 1 : 0;

View File

@ -8,7 +8,6 @@
lua_State *CreateLuaState();
bool DoLuaScript(lua_State *L, const char *script);
#ifndef Q_OS_WASM
sqlite3 *OpenDatabase(const QString &filename = "./server/users.db", const QString &initSql = "./server/init.sql");
QJsonArray SelectFromDatabase(sqlite3 *db, const QString &sql);
// For Lua
@ -16,6 +15,7 @@ QString SelectFromDb(sqlite3 *db, const QString &sql);
void ExecSQL(sqlite3 *db, const QString &sql);
void CloseDatabase(sqlite3 *db);
#ifndef Q_OS_WASM
RSA *InitServerRSA();
#endif

View File

@ -4,9 +4,11 @@
#include "util.h"
using namespace fkShell;
#ifndef Q_OS_WASM
#include "packman.h"
#ifndef Q_OS_WASM
#include "server.h"
#else
#include <emscripten.h>
#endif
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
@ -80,15 +82,16 @@ static void prepareForLinux() {
// TODO: AppImage
char buf[256] = {0};
int len = readlink("/proc/self/exe", buf, 256);
const char *home = getenv("HOME");
if (!strcmp(buf, "/usr/bin/FreeKill")) {
system("mkdir -p ~/.local/share/FreeKill");
installFkAssets("/usr/share/FreeKill", "~/.local/share");
chdir(getenv("HOME"));
installFkAssets("/usr/share/FreeKill", QString("%1/.local/share").arg(home));
chdir(home);
chdir(".local/share/FreeKill");
} else if (!strcmp(buf, "/usr/local/bin/FreeKill")) {
system("mkdir -p ~/.local/share/FreeKill");
installFkAssets("/usr/local/share/FreeKill", "~/.local/share");
chdir(getenv("HOME"));
installFkAssets("/usr/local/share/FreeKill", QString("%1/.local/share").arg(home));
chdir(home);
chdir(".local/share/FreeKill");
}
}
@ -167,6 +170,10 @@ int main(int argc, char *argv[]) {
if (startServer) {
app = new QCoreApplication(argc, argv);
QTranslator translator;
Q_UNUSED(translator.load("zh_CN.qm"));
QCoreApplication::installTranslator(&translator);
bool ok = false;
if (parser.value("server").toInt(&ok) && ok)
serverPort = parser.value("server").toInt();
@ -194,6 +201,13 @@ int main(int argc, char *argv[]) {
#else
#ifdef Q_OS_WASM
EM_ASM (
FS.mkdir('/assets');
FS.mount(IDBFS, {}, '/assets');
FS.chdir('/assets');
FS.syncfs(true, function(err) {
});
);
copyPath(":/", QDir::currentPath());
#endif
@ -234,8 +248,6 @@ int main(int argc, char *argv[]) {
QQuickStyle::setStyle("Material");
#endif
// 加载 zh_CN.qm 翻译文件
// TODO: i18n
QTranslator translator;
Q_UNUSED(translator.load("zh_CN.qm"));
QCoreApplication::installTranslator(&translator);
@ -243,9 +255,7 @@ int main(int argc, char *argv[]) {
QmlBackend backend;
backend.setEngine(engine);
#ifndef Q_OS_WASM
Pacman = new PackMan;
#endif
// 向 Qml 中先定义几个全局变量
engine->rootContext()->setContextProperty("FkVersion", FK_VERSION);
@ -294,6 +304,12 @@ int main(int argc, char *argv[]) {
delete engine;
delete Pacman;
#ifdef Q_OS_WASM
EM_ASM (
FS.syncfs(function(err) {});
);
#endif
return ret;
#endif
}

View File

@ -43,6 +43,11 @@ void Router::setSocket(ClientSocket *socket) {
}
}
void Router::removeSocket() {
socket->disconnect(this);
socket = nullptr;
}
void Router::installAESKey(const QByteArray &key) {
socket->installAESKey(key);
}
@ -195,9 +200,10 @@ void Router::handlePacket(const QByteArray &rawPacket) {
auto arr = String2Json(jsonData).array();
auto name = arr[0].toString();
auto capacity = arr[1].toInt();
auto timeout = arr[2].toInt();
auto settings =
QJsonDocument(arr[2].toObject()).toJson(QJsonDocument::Compact);
ServerInstance->createRoom(sender, name, capacity, settings);
QJsonDocument(arr[3].toObject()).toJson(QJsonDocument::Compact);
ServerInstance->createRoom(sender, name, capacity, timeout, settings);
};
lobby_actions["EnterRoom"] = [](ServerPlayer *sender,
const QString &jsonData) {

View File

@ -30,6 +30,7 @@ public:
ClientSocket *getSocket() const;
void setSocket(ClientSocket *socket);
void removeSocket();
void installAESKey(const QByteArray &key);
#ifndef FK_CLIENT_ONLY

View File

@ -87,7 +87,7 @@ bool Server::listen(const QHostAddress &address, ushort port) {
}
void Server::createRoom(ServerPlayer *owner, const QString &name, int capacity,
const QByteArray &settings) {
int timeout, const QByteArray &settings) {
Room *room;
if (!idle_rooms.isEmpty()) {
room = idle_rooms.pop();
@ -106,6 +106,7 @@ void Server::createRoom(ServerPlayer *owner, const QString &name, int capacity,
room->setName(name);
room->setCapacity(capacity);
room->setTimeout(timeout);
room->setSettings(settings);
room->addPlayer(owner);
if (!room->isLobby())

View File

@ -22,7 +22,7 @@ public:
ushort port = 9527u);
void createRoom(ServerPlayer *owner, const QString &name, int capacity,
const QByteArray &settings = "{}");
int timeout = 15, const QByteArray &settings = "{}");
Room *findRoom(int id) const;
Room *lobby() const;

View File

@ -52,7 +52,9 @@ ClientSocket *ServerPlayer::getSocket() const { return socket; }
// 处理跑路玩家专用就单纯把socket置为null
// 因为后面还会用到socket所以不删除
void ServerPlayer::removeSocket() {
this->socket = nullptr;
socket->disconnect(this);
socket = nullptr;
router->removeSocket();
}
Server *ServerPlayer::getServer() const { return server; }

View File

@ -8,11 +8,13 @@
#include "clientplayer.h"
#include "room.h"
#include "util.h"
#include "qmlbackend.h"
class ClientPlayer *Self = nullptr;
%}
%include "naturalvar.i"
%include "qt.i"
%include "qml-nogui.i"
%include "player.i"
%include "server.i"
%include "sqlite3.i"

12
src/swig/qml-nogui.i Normal file
View File

@ -0,0 +1,12 @@
// SPDX-License-Identifier: GPL-3.0-or-later
%nodefaultctor QmlBackend;
%nodefaultdtor QmlBackend;
class QmlBackend : public QObject {
public:
static void cd(const QString &path);
static QStringList ls(const QString &dir);
static QString pwd();
static bool exists(const QString &file);
static bool isDir(const QString &file);
};

View File

@ -2,12 +2,15 @@
#include "qmlbackend.h"
#ifndef FK_SERVER_ONLY
#include <qaudiooutput.h>
#include <qmediaplayer.h>
#include <qrandom.h>
#include <QClipboard>
#include <QMediaPlayer>
#endif
#include <cstdlib>
#ifndef Q_OS_WASM
#include "server.h"
@ -19,15 +22,48 @@ QmlBackend *Backend = nullptr;
QmlBackend::QmlBackend(QObject *parent) : QObject(parent) {
Backend = this;
#ifndef FK_SERVER_ONLY
engine = nullptr;
rsa = RSA_new();
#endif
}
QmlBackend::~QmlBackend() {
Backend = nullptr;
#ifndef FK_SERVER_ONLY
RSA_free(rsa);
#endif
}
void QmlBackend::cd(const QString &path) { QDir::setCurrent(path); }
QStringList QmlBackend::ls(const QString &dir) {
QString d = dir;
#ifdef Q_OS_WIN
if (d.startsWith("file:///"))
d.replace(0, 8, "file://");
#endif
return QDir(QUrl(d).path())
.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
}
QString QmlBackend::pwd() { return QDir::currentPath(); }
bool QmlBackend::exists(const QString &file) {
QString s = file;
#ifdef Q_OS_WIN
if (s.startsWith("file:///"))
s.replace(0, 8, "file://");
#endif
return QFile::exists(QUrl(s).path());
}
bool QmlBackend::isDir(const QString &file) {
return QFileInfo(QUrl(file).path()).isDir();
}
#ifndef FK_SERVER_ONLY
QQmlApplicationEngine *QmlBackend::getEngine() const { return engine; }
void QmlBackend::setEngine(QQmlApplicationEngine *engine) {
@ -81,33 +117,6 @@ void QmlBackend::emitNotifyUI(const QString &command, const QString &jsonData) {
emit notifyUI(command, jsonData);
}
void QmlBackend::cd(const QString &path) { QDir::setCurrent(path); }
QStringList QmlBackend::ls(const QString &dir) {
QString d = dir;
#ifdef Q_OS_WIN
if (d.startsWith("file:///"))
d.replace(0, 8, "file://");
#endif
return QDir(QUrl(d).path())
.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
}
QString QmlBackend::pwd() { return QDir::currentPath(); }
bool QmlBackend::exists(const QString &file) {
QString s = file;
#ifdef Q_OS_WIN
if (s.startsWith("file:///"))
s.replace(0, 8, "file://");
#endif
return QFile::exists(QUrl(s).path());
}
bool QmlBackend::isDir(const QString &file) {
return QFileInfo(QUrl(file).path()).isDir();
}
QString QmlBackend::translate(const QString &src) {
if (!ClientInstance)
return src;
@ -284,3 +293,5 @@ QString QmlBackend::getAESKey() const { return aes_key; }
void QmlBackend::installAESKey() {
ClientInstance->installAESKey(aes_key.toLatin1());
}
#endif

View File

@ -6,12 +6,19 @@
#include <qtmetamacros.h>
class QmlBackend : public QObject {
Q_OBJECT
Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
public:
QmlBackend(QObject *parent = nullptr);
~QmlBackend();
// File used by both Lua and Qml
static Q_INVOKABLE void cd(const QString &path);
static Q_INVOKABLE QStringList ls(const QString &dir = "");
static Q_INVOKABLE QString pwd();
static Q_INVOKABLE bool exists(const QString &file);
static Q_INVOKABLE bool isDir(const QString &file);
#ifndef FK_SERVER_ONLY
QQmlApplicationEngine *getEngine() const;
void setEngine(QQmlApplicationEngine *engine);
@ -24,13 +31,6 @@ public:
// lua --> qml
void emitNotifyUI(const QString &command, const QString &jsonData);
// File used by both Lua and Qml
static Q_INVOKABLE void cd(const QString &path);
static Q_INVOKABLE QStringList ls(const QString &dir = "");
static Q_INVOKABLE QString pwd();
static Q_INVOKABLE bool exists(const QString &file);
static Q_INVOKABLE bool isDir(const QString &file);
// read data from lua, call lua functions
Q_INVOKABLE QString translate(const QString &src);
Q_INVOKABLE QString callLuaFunction(const QString &func_name,
@ -57,12 +57,15 @@ signals:
void volumeChanged(qreal);
private:
Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
QQmlApplicationEngine *engine;
RSA *rsa;
QString aes_key;
qreal m_volume;
void pushLuaValue(lua_State *L, QVariant v);
#endif
};
extern QmlBackend *Backend;

32
wasm/nginx.conf Normal file
View File

@ -0,0 +1,32 @@
# NGINX conf file for testing wasm build
worker_processes 1;
pid nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
error_log error.log;
access_log access.log;
server {
listen 9580;
server_name localhost;
location / {
root .;
index index.html FreeKill.html;
add_header Cross-Origin-Opener-Policy same-origin;
add_header Cross-Origin-Embedder-Policy require-corp;
}
}
}