Compare commits
15 Commits
v1.7.4-pre
...
v1.7.4
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3366d926f4 | ||
![]() |
6d7f6f63c6 | ||
![]() |
590a7829b1 | ||
![]() |
ae75fc1490 | ||
![]() |
0c645d04aa | ||
![]() |
13b3764fcf | ||
![]() |
57d4fe7cf9 | ||
![]() |
fd7b354571 | ||
![]() |
be1d53b3b1 | ||
![]() |
e0cff36819 | ||
![]() |
cea654692e | ||
![]() |
c82ffb6c97 | ||
![]() |
7400a8c040 | ||
![]() |
eda171efa1 | ||
![]() |
f881459c0b |
@@ -59,5 +59,7 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
gaseousgames/gaseousserver:latest-embeddeddb
|
||||
gaseousgames/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
ghcr.io/gaseous-project/gaseousserver:latest-embeddeddb
|
||||
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||
|
13
.github/workflows/BuildOnTestBranch.yml
vendored
13
.github/workflows/BuildOnTestBranch.yml
vendored
@@ -27,10 +27,19 @@ jobs:
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
- name: Build and push standard image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./build/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: gaseousgames/test:latest
|
||||
- name: Build and push image with embedded mariadb
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./build/Dockerfile-EmbeddedDB
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: gaseousgames/test:latest-embeddeddb
|
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@@ -24,7 +24,8 @@
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/Views": "${workspaceFolder}/Views"
|
||||
}
|
||||
},
|
||||
"enableStepFiltering": false
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
|
20
Gaseous.sln
20
Gaseous.sln
@@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 25.0.1704.4
|
||||
@@ -27,30 +27,18 @@ Global
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{08699C93-15CD-4E39-9053-D3C8056CE938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{08699C93-15CD-4E39-9053-D3C8056CE938}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{08699C93-15CD-4E39-9053-D3C8056CE938}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{08699C93-15CD-4E39-9053-D3C8056CE938}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FFCEC386-033F-4772-A45B-D33579F2E5EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FFCEC386-033F-4772-A45B-D33579F2E5EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FFCEC386-033F-4772-A45B-D33579F2E5EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FFCEC386-033F-4772-A45B-D33579F2E5EE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B07A4655-A003-416B-A790-ADAA5B548E1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B07A4655-A003-416B-A790-ADAA5B548E1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B07A4655-A003-416B-A790-ADAA5B548E1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B07A4655-A003-416B-A790-ADAA5B548E1A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {979BF092-AFBC-4F19-B55F-32E73959BD1A}
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{F1A847C7-57BC-4DA9-8F83-CD060A7F5122} = {17FA6F12-8532-420C-9489-CB8FDE42137C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {979BF092-AFBC-4F19-B55F-32E73959BD1A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
149
LICENSE
149
LICENSE
@@ -1,5 +1,5 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
@@ -7,17 +7,15 @@
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
@@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
@@ -72,7 +60,7 @@ modification follow.
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
@@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
@@ -631,44 +629,33 @@ to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
Gaseous
|
||||
Copyright (C) 2023 Gaseous
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) 2023 Gaseous
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
@@ -23,6 +23,7 @@ RUN dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime
|
||||
# RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||
# RUN wget https://cdn.emulatorjs.org/releases/4.0.12.7z
|
||||
# RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.0.12.7z
|
||||
|
||||
RUN wget --recursive --no-parent https://cdn.emulatorjs.org/latest/
|
||||
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||
RUN cp -fr cdn.emulatorjs.org/latest/* out/wwwroot/emulators/EmulatorJS
|
||||
@@ -35,10 +36,19 @@ WORKDIR /App
|
||||
COPY --from=build-env /App/out .
|
||||
|
||||
# variables
|
||||
ENV dbhost=localhost
|
||||
ENV dbuser=root
|
||||
ENV dbpass=gaseous
|
||||
ENV MARIADB_ROOT_PASSWORD=$dbpass
|
||||
ARG PUID=1000
|
||||
ARG PGID=1000
|
||||
ARG dbhost=localhost
|
||||
ARG dbuser=root
|
||||
ARG dbpass=gaseous
|
||||
ARG MARIADB_ROOT_PASSWORD=$dbpass
|
||||
|
||||
ENV PUID=${PUID}
|
||||
ENV PGID=${PGID}
|
||||
ENV dbhost=${dbhost}
|
||||
ENV dbuser=${dbuser}
|
||||
ENV dbpass=${dbpass}
|
||||
ENV MARIADB_ROOT_PASSWORD=${dbpass}
|
||||
|
||||
# install mariadb
|
||||
RUN DEBIAN_FRONTEND=noninteractive && \
|
||||
@@ -50,12 +60,18 @@ RUN chmod +x /usr/sbin/start-mariadb.sh
|
||||
# install supervisord
|
||||
RUN apt-get install -y supervisor
|
||||
COPY ../build/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
RUN mkdir -p /var/run/supervisord
|
||||
RUN mkdir -p /var/log/supervisord
|
||||
|
||||
# clean up apt-get
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists
|
||||
|
||||
# copy entrypoint
|
||||
COPY ../build/entrypoint.sh /usr/sbin/entrypoint.sh
|
||||
RUN chmod +x /usr/sbin/entrypoint.sh
|
||||
|
||||
# volumes
|
||||
VOLUME /root/.gaseous-server /var/lib/mysql
|
||||
VOLUME /home/gaseous/.gaseous-server /var/lib/mysql
|
||||
|
||||
# start services
|
||||
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
ENTRYPOINT [ "/usr/sbin/entrypoint.sh" ]
|
||||
|
13
build/entrypoint.sh
Normal file
13
build/entrypoint.sh
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
# create the user
|
||||
echo "Creating user gaseous with UID ${PUID} and GID ${PGID}"
|
||||
groupadd -g ${PGID} gaseous
|
||||
useradd -u ${PUID} -g ${PGID} -m gaseous -d /home/gaseous -G sudo
|
||||
usermod -p "*" gaseous
|
||||
mkdir -p /home/gaseous/.gaseous-server /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
chown -R ${PUID} /App /home/gaseous/.gaseous-server /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
chgrp -R ${PGID} /App /home/gaseous/.gaseous-server /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
|
||||
# Start supervisord and services
|
||||
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
@@ -1,9 +1,20 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# Wait for the service to start
|
||||
while ! mysqladmin ping -h localhost --silent; do
|
||||
sleep 1
|
||||
done
|
||||
# install the database
|
||||
/usr/bin/mariadb-install-db --datadir=/var/lib/mysql --user=gaseous
|
||||
|
||||
# Set the root password
|
||||
mariadb -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '$MARIADB_ROOT_PASSWORD';"
|
||||
# start the database server without network or grant tables
|
||||
/usr/sbin/mariadbd --datadir=/var/lib/mysql --skip-grant-tables --skip-networking &
|
||||
|
||||
# wait for the server to start
|
||||
sleep 5
|
||||
|
||||
# change the root password
|
||||
mariadb -u root -e "FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY '$MARIADB_ROOT_PASSWORD'; ALTER USER 'gaseous'@'localhost' IDENTIFIED BY '$MARIADB_ROOT_PASSWORD'; FLUSH PRIVILEGES; SHUTDOWN;"
|
||||
|
||||
# stop the server
|
||||
sleep 5
|
||||
killall mariadbd
|
||||
|
||||
# start the server normally
|
||||
/usr/sbin/mariadbd --datadir=/var/lib/mysql
|
||||
|
@@ -1,31 +1,37 @@
|
||||
[supervisord]
|
||||
user=root
|
||||
nodaemon=true
|
||||
logfile=/dev/null
|
||||
logfile_maxbytes=0
|
||||
pidfile=/var/run/supervisord.pid
|
||||
loglevel = INFO
|
||||
logfile=/var/log/supervisord/supervisord.log
|
||||
logfile_maxbytes=50
|
||||
logfile_backups=5
|
||||
pidfile=/var/run/supervisord/supervisord.pid
|
||||
loglevel = info
|
||||
|
||||
[unix_http_server]
|
||||
file=/var/run/supervisord/supervisor.sock
|
||||
chmod=0700
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///var/run/supervisord/supervisor.sock
|
||||
|
||||
[program:mariadb]
|
||||
command=/usr/sbin/mariadbd --user=root
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
|
||||
[program:mariadb-setup]
|
||||
user=gaseous
|
||||
command=bash -c "/usr/sbin/start-mariadb.sh"
|
||||
autostart=true
|
||||
autorestart=false
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
|
||||
[program:gaseous-server]
|
||||
user=gaseous
|
||||
command=dotnet /App/gaseous-server.dll
|
||||
environment=HOME="/home/gaseous",USER="gaseous"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stdout_logfile_maxbytes=0
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.IO.Compression;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
|
@@ -80,7 +80,8 @@ namespace gaseous_server.Classes
|
||||
get
|
||||
{
|
||||
string logPath = Path.Combine(ConfigurationPath, "Logs");
|
||||
if (!Directory.Exists(logPath)) {
|
||||
if (!Directory.Exists(logPath))
|
||||
{
|
||||
Directory.CreateDirectory(logPath);
|
||||
}
|
||||
return logPath;
|
||||
@@ -92,7 +93,7 @@ namespace gaseous_server.Classes
|
||||
get
|
||||
{
|
||||
string logFileExtension = "txt";
|
||||
|
||||
|
||||
string logPathName = Path.Combine(LogPath, "Server Log " + DateTime.Now.ToUniversalTime().ToString("yyyyMMdd") + "." + logFileExtension);
|
||||
return logPathName;
|
||||
}
|
||||
@@ -131,7 +132,7 @@ namespace gaseous_server.Classes
|
||||
_config.DatabaseConfiguration.DatabaseName = (string)Common.GetEnvVar("dbname", _config.DatabaseConfiguration.DatabaseName);
|
||||
_config.DatabaseConfiguration.Port = int.Parse((string)Common.GetEnvVar("dbport", _config.DatabaseConfiguration.Port.ToString()));
|
||||
_config.MetadataConfiguration.MetadataSource = (HasheousClient.Models.MetadataModel.MetadataSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.MetadataSources), (string)Common.GetEnvVar("metadatasource", _config.MetadataConfiguration.MetadataSource.ToString()));
|
||||
_config.MetadataConfiguration.SignatureSource = (HasheousClient.Models.MetadataModel.SignatureSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.SignatureSources), (string)Common.GetEnvVar("signaturesource", _config.MetadataConfiguration.SignatureSource.ToString()));;
|
||||
_config.MetadataConfiguration.SignatureSource = (HasheousClient.Models.MetadataModel.SignatureSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.SignatureSources), (string)Common.GetEnvVar("signaturesource", _config.MetadataConfiguration.SignatureSource.ToString())); ;
|
||||
_config.MetadataConfiguration.MaxLibraryScanWorkers = int.Parse((string)Common.GetEnvVar("maxlibraryscanworkers", _config.MetadataConfiguration.MaxLibraryScanWorkers.ToString()));
|
||||
_config.MetadataConfiguration.HasheousHost = (string)Common.GetEnvVar("hasheoushost", _config.MetadataConfiguration.HasheousHost);
|
||||
_config.IGDBConfiguration.ClientId = (string)Common.GetEnvVar("igdbclientid", _config.IGDBConfiguration.ClientId);
|
||||
@@ -205,9 +206,9 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
AppSettings.Remove(SettingName);
|
||||
}
|
||||
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Load Settings", "Loading setting " + SettingName + " from database");
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
if (Database.schema_version >= 1016)
|
||||
@@ -275,7 +276,7 @@ namespace gaseous_server.Classes
|
||||
if (Database.schema_version >= 1016)
|
||||
{
|
||||
sql = "SELECT Value, ValueDate FROM Settings WHERE Setting = @SettingName";
|
||||
|
||||
|
||||
dbResponse = db.ExecuteCMD(sql, dbDict);
|
||||
Type type = typeof(T);
|
||||
if (dbResponse.Rows.Count == 0)
|
||||
@@ -301,7 +302,7 @@ namespace gaseous_server.Classes
|
||||
else
|
||||
{
|
||||
sql = "SELECT Value FROM Settings WHERE Setting = @SettingName";
|
||||
|
||||
|
||||
dbResponse = db.ExecuteCMD(sql, dbDict);
|
||||
Type type = typeof(T);
|
||||
if (dbResponse.Rows.Count == 0)
|
||||
@@ -355,7 +356,7 @@ namespace gaseous_server.Classes
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql;
|
||||
Dictionary<string, object> dbDict;
|
||||
|
||||
|
||||
if (Database.schema_version >= 1016)
|
||||
{
|
||||
sql = "REPLACE INTO Settings (Setting, ValueType, Value, ValueDate) VALUES (@SettingName, @ValueType, @Value, @ValueDate)";
|
||||
@@ -427,7 +428,8 @@ namespace gaseous_server.Classes
|
||||
|
||||
public class Database
|
||||
{
|
||||
private static string _DefaultHostName {
|
||||
private static string _DefaultHostName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("dbhost")))
|
||||
|
@@ -4,11 +4,11 @@ using System.Reflection;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public static class DatabaseMigration
|
||||
{
|
||||
public static class DatabaseMigration
|
||||
{
|
||||
public static List<int> BackgroundUpgradeTargetSchemaVersions = new List<int>();
|
||||
|
||||
public static void PreUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
||||
public static void PreUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
||||
{
|
||||
// load resources
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
@@ -20,14 +20,14 @@ namespace gaseous_server.Classes
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Database", "Checking for pre-upgrade for schema version " + TargetSchemaVersion);
|
||||
|
||||
switch(DatabaseType)
|
||||
switch (DatabaseType)
|
||||
{
|
||||
case Database.databaseType.MySql:
|
||||
switch (TargetSchemaVersion)
|
||||
{
|
||||
case 1005:
|
||||
Logging.Log(Logging.LogType.Information, "Database", "Running pre-upgrade for schema version " + TargetSchemaVersion);
|
||||
|
||||
|
||||
// there was a mistake at dbschema version 1004-1005
|
||||
// the first preview release of v1.7 reused dbschema version 1004
|
||||
// if table "Relation_Game_AgeRatings" exists - then we need to apply the gaseous-fix-1005.sql script before applying the standard 1005 script
|
||||
@@ -62,14 +62,14 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public static void PostUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
||||
public static void PostUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
DataTable data;
|
||||
|
||||
switch(DatabaseType)
|
||||
switch (DatabaseType)
|
||||
{
|
||||
case Database.databaseType.MySql:
|
||||
switch (TargetSchemaVersion)
|
||||
@@ -78,7 +78,7 @@ namespace gaseous_server.Classes
|
||||
// this is a safe background task
|
||||
BackgroundUpgradeTargetSchemaVersions.Add(1002);
|
||||
break;
|
||||
|
||||
|
||||
case 1004:
|
||||
// needs to run on start up
|
||||
|
||||
@@ -121,7 +121,8 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public static void MySql_1002_MigrateMetadataVersion() {
|
||||
public static void MySql_1002_MigrateMetadataVersion()
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
@@ -134,7 +135,7 @@ namespace gaseous_server.Classes
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingestor - Database Update", "Updating " + data.Rows.Count + " database entries");
|
||||
int Counter = 0;
|
||||
int LastCounterCheck = 0;
|
||||
foreach (DataRow row in data.Rows)
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
List<string> Flags = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>((string)Common.ReturnValueIfNull(row["flags"], "[]"));
|
||||
List<KeyValuePair<string, object>> Attributes = new List<KeyValuePair<string, object>>();
|
||||
@@ -207,7 +208,7 @@ namespace gaseous_server.Classes
|
||||
dbDict.Add("id", (int)row["Id"]);
|
||||
db.ExecuteCMD(updateSQL, dbDict);
|
||||
|
||||
if ((Counter - LastCounterCheck) > 10)
|
||||
if ((Counter - LastCounterCheck) > 10)
|
||||
{
|
||||
LastCounterCheck = Counter;
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingestor - Database Update", "Updating " + Counter + " / " + data.Rows.Count + " database entries");
|
||||
|
@@ -31,7 +31,7 @@ namespace gaseous_server.Classes
|
||||
if (!Directory.Exists(ExtractPath)) { Directory.CreateDirectory(ExtractPath); }
|
||||
try
|
||||
{
|
||||
switch(ImportedFileExtension)
|
||||
switch (ImportedFileExtension)
|
||||
{
|
||||
case ".zip":
|
||||
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing using zip");
|
||||
@@ -105,7 +105,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Get Signature", "Processing decompressed files for signature matches");
|
||||
// loop through contents until we find the first signature match
|
||||
List<ArchiveData> archiveFiles = new List<ArchiveData>();
|
||||
@@ -116,12 +116,13 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
FileInfo zfi = new FileInfo(file);
|
||||
Common.hashObject zhash = new Common.hashObject(file);
|
||||
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Get Signature", "Checking signature of decompressed file " + file);
|
||||
|
||||
if (zfi != null)
|
||||
{
|
||||
ArchiveData archiveData = new ArchiveData{
|
||||
ArchiveData archiveData = new ArchiveData
|
||||
{
|
||||
FileName = Path.GetFileName(file),
|
||||
FilePath = zfi.Directory.FullName.Replace(ExtractPath, ""),
|
||||
Size = zfi.Length,
|
||||
@@ -138,7 +139,7 @@ namespace gaseous_server.Classes
|
||||
if (zDiscoveredSignature.Score > discoveredSignature.Score)
|
||||
{
|
||||
if (
|
||||
zDiscoveredSignature.Rom.SignatureSource == gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType.MAMEArcade ||
|
||||
zDiscoveredSignature.Rom.SignatureSource == gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType.MAMEArcade ||
|
||||
zDiscoveredSignature.Rom.SignatureSource == gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType.MAMEMess
|
||||
)
|
||||
{
|
||||
@@ -195,7 +196,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
// signature retrieved from Hasheous
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature retrieved from Hasheous for game: " + dbSignature.Game.Name);
|
||||
|
||||
|
||||
discoveredSignature = dbSignature;
|
||||
}
|
||||
else
|
||||
@@ -203,7 +204,7 @@ namespace gaseous_server.Classes
|
||||
// construct a signature from file data
|
||||
dbSignature = _GetFileSignatureFromFileData(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature generated from provided file for game: " + dbSignature.Game.Name);
|
||||
|
||||
|
||||
discoveredSignature = dbSignature;
|
||||
}
|
||||
}
|
||||
@@ -216,8 +217,8 @@ namespace gaseous_server.Classes
|
||||
return discoveredSignature;
|
||||
}
|
||||
|
||||
private gaseous_server.Models.Signatures_Games? _GetFileSignatureFromDatabase(Common.hashObject hash, string ImageName, string ImageExtension, long ImageSize, string GameFileImportPath)
|
||||
{
|
||||
private gaseous_server.Models.Signatures_Games? _GetFileSignatureFromDatabase(Common.hashObject hash, string ImageName, string ImageExtension, long ImageSize, string GameFileImportPath)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Get Signature", "Checking local database for MD5: " + hash.md5hash);
|
||||
|
||||
// check 1: do we have a signature for it?
|
||||
|
@@ -16,48 +16,49 @@ using HasheousClient.Models;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public class ImportGame : QueueItemStatus
|
||||
{
|
||||
public class ImportGame : QueueItemStatus
|
||||
{
|
||||
public void ProcessDirectory(string ImportPath)
|
||||
{
|
||||
if (Directory.Exists(ImportPath))
|
||||
{
|
||||
string[] importContents = Directory.GetFiles(ImportPath, "*.*", SearchOption.AllDirectories);
|
||||
{
|
||||
string[] importContents = Directory.GetFiles(ImportPath, "*.*", SearchOption.AllDirectories);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Import Games", "Found " + importContents.Length + " files to process in import directory: " + ImportPath);
|
||||
|
||||
// import files first
|
||||
// import files first
|
||||
int importCount = 1;
|
||||
foreach (string importContent in importContents) {
|
||||
foreach (string importContent in importContents)
|
||||
{
|
||||
SetStatus(importCount, importContents.Length, "Importing file: " + importContent);
|
||||
|
||||
ImportGameFile(importContent, null);
|
||||
ImportGameFile(importContent, null);
|
||||
|
||||
importCount += 1;
|
||||
}
|
||||
}
|
||||
ClearStatus();
|
||||
|
||||
DeleteOrphanedDirectories(ImportPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Import Games", "The import directory " + ImportPath + " does not exist.");
|
||||
throw new DirectoryNotFoundException("Invalid path: " + ImportPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Import Games", "The import directory " + ImportPath + " does not exist.");
|
||||
throw new DirectoryNotFoundException("Invalid path: " + ImportPath);
|
||||
}
|
||||
}
|
||||
|
||||
public void ImportGameFile(string GameFileImportPath, IGDB.Models.Platform? OverridePlatform)
|
||||
{
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
|
||||
if (Common.SkippableFiles.Contains<string>(Path.GetFileName(GameFileImportPath), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
{
|
||||
Logging.Log(Logging.LogType.Debug, "Import Game", "Skipping item " + GameFileImportPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
else
|
||||
{
|
||||
FileInfo fi = new FileInfo(GameFileImportPath);
|
||||
Common.hashObject hash = new Common.hashObject(GameFileImportPath);
|
||||
|
||||
@@ -87,7 +88,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
File.Move(GameFileImportPath, targetPathWithFileName, true);
|
||||
}
|
||||
|
||||
|
||||
// import source was the upload directory
|
||||
if (GameFileImportPath.StartsWith(Config.LibraryConfiguration.LibraryUploadDirectory))
|
||||
{
|
||||
@@ -146,8 +147,8 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IGDB.Models.Game SearchForGame(gaseous_server.Models.Signatures_Games Signature, long PlatformId, bool FullDownload)
|
||||
{
|
||||
@@ -173,7 +174,7 @@ namespace gaseous_server.Classes
|
||||
string GameName = Signature.Game.Name;
|
||||
|
||||
List<string> SearchCandidates = GetSearchCandidates(GameName);
|
||||
|
||||
|
||||
foreach (string SearchCandidate in SearchCandidates)
|
||||
{
|
||||
bool GameFound = false;
|
||||
@@ -197,8 +198,10 @@ namespace gaseous_server.Classes
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", " " + games.Length + " search results found");
|
||||
|
||||
// quite likely we've found sequels and alternate types
|
||||
foreach (Game game in games) {
|
||||
if (game.Name == SearchCandidate) {
|
||||
foreach (Game game in games)
|
||||
{
|
||||
if (game.Name == SearchCandidate)
|
||||
{
|
||||
// found game title matches the search candidate
|
||||
determinedGame = Metadata.Games.GetGame((long)games[0].Id, false, false, false);
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Found exact match!");
|
||||
@@ -273,7 +276,8 @@ namespace gaseous_server.Classes
|
||||
|
||||
// assumption: no games have () in their titles so we'll remove them
|
||||
int idx = GameName.IndexOf('(');
|
||||
if (idx >= 0) {
|
||||
if (idx >= 0)
|
||||
{
|
||||
GameName = GameName.Substring(0, idx);
|
||||
}
|
||||
|
||||
@@ -305,7 +309,8 @@ namespace gaseous_server.Classes
|
||||
if (UpdateId == 0)
|
||||
{
|
||||
sql = "INSERT INTO Games_Roms (PlatformId, GameId, Name, Size, CRC, MD5, SHA1, DevelopmentStatus, Attributes, RomType, RomTypeMedia, MediaLabel, Path, MetadataSource, MetadataGameName, MetadataVersion, LibraryId) VALUES (@platformid, @gameid, @name, @size, @crc, @md5, @sha1, @developmentstatus, @Attributes, @romtype, @romtypemedia, @medialabel, @path, @metadatasource, @metadatagamename, @metadataversion, @libraryid); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = "UPDATE Games_Roms SET PlatformId=@platformid, GameId=@gameid, Name=@name, Size=@size, DevelopmentStatus=@developmentstatus, Attributes=@Attributes, RomType=@romtype, RomTypeMedia=@romtypemedia, MediaLabel=@medialabel, MetadataSource=@metadatasource, MetadataGameName=@metadatagamename, MetadataVersion=@metadataversion WHERE Id=@id;";
|
||||
dbDict.Add("id", UpdateId);
|
||||
@@ -348,7 +353,8 @@ namespace gaseous_server.Classes
|
||||
if (UpdateId == 0)
|
||||
{
|
||||
romId = (long)romInsert.Rows[0][0];
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
romId = UpdateId;
|
||||
}
|
||||
@@ -362,73 +368,73 @@ namespace gaseous_server.Classes
|
||||
return romId;
|
||||
}
|
||||
|
||||
public static string ComputeROMPath(long RomId)
|
||||
{
|
||||
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||
|
||||
// get metadata
|
||||
IGDB.Models.Platform platform = gaseous_server.Classes.Metadata.Platforms.GetPlatform(rom.PlatformId);
|
||||
IGDB.Models.Game game = gaseous_server.Classes.Metadata.Games.GetGame(rom.GameId, false, false, false);
|
||||
|
||||
// build path
|
||||
string platformSlug = "Unknown Platform";
|
||||
if (platform != null)
|
||||
{
|
||||
platformSlug = platform.Slug;
|
||||
}
|
||||
string gameSlug = "Unknown Title";
|
||||
if (game != null)
|
||||
{
|
||||
gameSlug = game.Slug;
|
||||
}
|
||||
string DestinationPath = Path.Combine(GameLibrary.GetDefaultLibrary.Path, gameSlug, platformSlug);
|
||||
if (!Directory.Exists(DestinationPath))
|
||||
{
|
||||
Directory.CreateDirectory(DestinationPath);
|
||||
}
|
||||
|
||||
string DestinationPathName = Path.Combine(DestinationPath, rom.Name);
|
||||
|
||||
return DestinationPathName;
|
||||
}
|
||||
|
||||
public static bool MoveGameFile(long RomId)
|
||||
{
|
||||
public static string ComputeROMPath(long RomId)
|
||||
{
|
||||
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||
string romPath = rom.Path;
|
||||
|
||||
// get metadata
|
||||
IGDB.Models.Platform platform = gaseous_server.Classes.Metadata.Platforms.GetPlatform(rom.PlatformId);
|
||||
IGDB.Models.Game game = gaseous_server.Classes.Metadata.Games.GetGame(rom.GameId, false, false, false);
|
||||
|
||||
// build path
|
||||
string platformSlug = "Unknown Platform";
|
||||
if (platform != null)
|
||||
{
|
||||
platformSlug = platform.Slug;
|
||||
}
|
||||
string gameSlug = "Unknown Title";
|
||||
if (game != null)
|
||||
{
|
||||
gameSlug = game.Slug;
|
||||
}
|
||||
string DestinationPath = Path.Combine(GameLibrary.GetDefaultLibrary.Path, gameSlug, platformSlug);
|
||||
if (!Directory.Exists(DestinationPath))
|
||||
{
|
||||
Directory.CreateDirectory(DestinationPath);
|
||||
}
|
||||
|
||||
string DestinationPathName = Path.Combine(DestinationPath, rom.Name);
|
||||
|
||||
return DestinationPathName;
|
||||
}
|
||||
|
||||
public static bool MoveGameFile(long RomId)
|
||||
{
|
||||
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||
string romPath = rom.Path;
|
||||
|
||||
if (File.Exists(romPath))
|
||||
{
|
||||
string DestinationPath = ComputeROMPath(RomId);
|
||||
|
||||
if (romPath == DestinationPath)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Debug, "Move Game ROM", "Destination path is the same as the current path - aborting");
|
||||
if (romPath == DestinationPath)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Debug, "Move Game ROM", "Destination path is the same as the current path - aborting");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Move Game ROM", "Moving " + romPath + " to " + DestinationPath);
|
||||
if (File.Exists(DestinationPath))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Move Game ROM", "A file with the same name exists at the destination - aborting");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Move Game ROM", "Moving " + romPath + " to " + DestinationPath);
|
||||
if (File.Exists(DestinationPath))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Move Game ROM", "A file with the same name exists at the destination - aborting");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
File.Move(romPath, DestinationPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
File.Move(romPath, DestinationPath);
|
||||
|
||||
// update the db
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "UPDATE Games_Roms SET Path=@path WHERE Id=@id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", RomId);
|
||||
dbDict.Add("path", DestinationPath);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
// update the db
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "UPDATE Games_Roms SET Path=@path WHERE Id=@id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", RomId);
|
||||
dbDict.Add("path", DestinationPath);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -437,8 +443,8 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public void OrganiseLibrary()
|
||||
{
|
||||
public void OrganiseLibrary()
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Organise Library", "Starting default library organisation");
|
||||
|
||||
GameLibrary.LibraryItem library = GameLibrary.GetDefaultLibrary;
|
||||
@@ -451,19 +457,19 @@ namespace gaseous_server.Classes
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (romDT.Rows.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < romDT.Rows.Count; i++)
|
||||
{
|
||||
{
|
||||
for (int i = 0; i < romDT.Rows.Count; i++)
|
||||
{
|
||||
SetStatus(i, romDT.Rows.Count, "Processing file " + romDT.Rows[i]["name"]);
|
||||
Logging.Log(Logging.LogType.Information, "Organise Library", "(" + i + "/" + romDT.Rows.Count + ") Processing ROM " + romDT.Rows[i]["name"]);
|
||||
Logging.Log(Logging.LogType.Information, "Organise Library", "(" + i + "/" + romDT.Rows.Count + ") Processing ROM " + romDT.Rows[i]["name"]);
|
||||
long RomId = (long)romDT.Rows[i]["id"];
|
||||
MoveGameFile(RomId);
|
||||
}
|
||||
}
|
||||
MoveGameFile(RomId);
|
||||
}
|
||||
}
|
||||
ClearStatus();
|
||||
|
||||
// clean up empty directories
|
||||
DeleteOrphanedDirectories(GameLibrary.GetDefaultLibrary.Path);
|
||||
// clean up empty directories
|
||||
DeleteOrphanedDirectories(GameLibrary.GetDefaultLibrary.Path);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Organise Library", "Finsihed default library organisation");
|
||||
}
|
||||
@@ -476,7 +482,7 @@ namespace gaseous_server.Classes
|
||||
|
||||
string[] files = Directory.GetFiles(directory);
|
||||
string[] directories = Directory.GetDirectories(directory);
|
||||
|
||||
|
||||
if (files.Length == 0 &&
|
||||
directories.Length == 0)
|
||||
{
|
||||
@@ -563,7 +569,7 @@ namespace gaseous_server.Classes
|
||||
|
||||
public void LibrarySpecificScan(GameLibrary.LibraryItem library)
|
||||
{
|
||||
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Starting scan of library: " + library.Name);
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
@@ -632,7 +638,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
// file is not in database - process it
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Orphaned file found in library: " + LibraryFile);
|
||||
|
||||
|
||||
Common.hashObject hash = new Common.hashObject(LibraryFile);
|
||||
FileInfo fi = new FileInfo(LibraryFile);
|
||||
|
||||
@@ -644,8 +650,8 @@ namespace gaseous_server.Classes
|
||||
// get discovered platform
|
||||
long PlatformId;
|
||||
IGDB.Models.Platform determinedPlatform;
|
||||
|
||||
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0 )
|
||||
|
||||
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0)
|
||||
{
|
||||
// no platform discovered in the signature
|
||||
PlatformId = library.DefaultPlatformId;
|
||||
@@ -770,8 +776,8 @@ namespace gaseous_server.Classes
|
||||
// get discovered platform
|
||||
long PlatformId;
|
||||
IGDB.Models.Platform determinedPlatform;
|
||||
|
||||
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0 )
|
||||
|
||||
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0)
|
||||
{
|
||||
// no platform discovered in the signature
|
||||
PlatformId = library.DefaultPlatformId;
|
||||
|
@@ -38,10 +38,10 @@ namespace gaseous_server.Classes
|
||||
long deletedCount = 1;
|
||||
long deletedEventCount = 0;
|
||||
long maxLoops = 1000;
|
||||
sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRetentionDate LIMIT 1000; SELECT ROW_COUNT() AS Count;";
|
||||
dbDict.Add("EventRetentionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
|
||||
while (deletedCount > 0)
|
||||
{
|
||||
sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRetentionDate LIMIT 1000; SELECT ROW_COUNT() AS Count;";
|
||||
dbDict.Add("EventRetentionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
|
||||
DataTable deletedCountTable = db.ExecuteCMD(sql, dbDict);
|
||||
deletedCount = (long)deletedCountTable.Rows[0][0];
|
||||
deletedEventCount += deletedCount;
|
||||
|
@@ -78,15 +78,17 @@ namespace gaseous_server.Classes.Metadata
|
||||
if (cacheStatus == Storage.CacheStatus.Current) { cacheStatus = Storage.CacheStatus.Expired; }
|
||||
}
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
string searchField = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
searchField = "id";
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
WhereClause = "where slug = \"" + searchValue + "\"";
|
||||
searchField = "slug";
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
@@ -110,11 +112,11 @@ namespace gaseous_server.Classes.Metadata
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
returnValue = Storage.GetCacheValue<Game>(returnValue, "id", (long)searchValue);
|
||||
returnValue = Storage.GetCacheValue<Game>(returnValue, searchField, searchValue);
|
||||
}
|
||||
return returnValue;
|
||||
case Storage.CacheStatus.Current:
|
||||
returnValue = Storage.GetCacheValue<Game>(returnValue, "id", (long)searchValue);
|
||||
returnValue = Storage.GetCacheValue<Game>(returnValue, searchField, searchValue);
|
||||
UpdateSubClasses(returnValue, false, false, false);
|
||||
return returnValue;
|
||||
default:
|
||||
|
@@ -78,13 +78,16 @@ namespace gaseous_server.Classes.Metadata
|
||||
|
||||
// set up where clause
|
||||
string WhereClause = "";
|
||||
string searchField = "";
|
||||
switch (searchUsing)
|
||||
{
|
||||
case SearchUsing.id:
|
||||
WhereClause = "where id = " + searchValue;
|
||||
searchField = "id";
|
||||
break;
|
||||
case SearchUsing.slug:
|
||||
WhereClause = "where slug = " + searchValue;
|
||||
WhereClause = "where slug = \"" + searchValue + "\"";
|
||||
searchField = "slug";
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid search type");
|
||||
@@ -111,10 +114,10 @@ namespace gaseous_server.Classes.Metadata
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
return Storage.GetCacheValue<Platform>(returnValue, "id", (long)searchValue);
|
||||
return Storage.GetCacheValue<Platform>(returnValue, searchField, searchValue);
|
||||
}
|
||||
case Storage.CacheStatus.Current:
|
||||
return Storage.GetCacheValue<Platform>(returnValue, "id", (long)searchValue);
|
||||
return Storage.GetCacheValue<Platform>(returnValue, searchField, searchValue);
|
||||
default:
|
||||
throw new Exception("How did you get here?");
|
||||
}
|
||||
|
@@ -235,5 +235,4 @@ namespace gaseous_server.Classes
|
||||
public GameLibrary.LibraryItem Library { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -104,7 +104,7 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
|
||||
// set up game dictionary
|
||||
dbDict = new Dictionary<string, object>();
|
||||
if (flipNameAndDescription.Contains(Object.SourceType))
|
||||
if (flipNameAndDescription.Contains(Object.SourceType))
|
||||
{
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(gameObject.Description, ""));
|
||||
dbDict.Add("description", Common.ReturnValueIfNull(gameObject.Name, ""));
|
||||
|
@@ -10,7 +10,8 @@ namespace gaseous_server.Classes
|
||||
if (md5.Length > 0)
|
||||
{
|
||||
return _GetSignature("Signatures_Roms.md5 = @searchstring", md5);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
return _GetSignature("Signatures_Roms.sha1 = @searchstring", sha1);
|
||||
}
|
||||
@@ -21,7 +22,8 @@ namespace gaseous_server.Classes
|
||||
if (TosecName.Length > 0)
|
||||
{
|
||||
return _GetSignature("Signatures_Roms.name = @searchstring", TosecName);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@@ -4,11 +4,11 @@ using gaseous_signature_parser.models.RomSignatureObject;
|
||||
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class Signatures_Games : HasheousClient.Models.LookupResponseModel
|
||||
{
|
||||
public Signatures_Games()
|
||||
{
|
||||
}
|
||||
public class Signatures_Games : HasheousClient.Models.LookupResponseModel
|
||||
{
|
||||
public Signatures_Games()
|
||||
{
|
||||
}
|
||||
|
||||
public SignatureFlags Flags = new SignatureFlags();
|
||||
|
||||
@@ -20,4 +20,3 @@ namespace gaseous_server.Models
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -9,8 +9,8 @@ using NuGet.Packaging;
|
||||
|
||||
namespace gaseous_server
|
||||
{
|
||||
public static class ProcessQueue
|
||||
{
|
||||
public static class ProcessQueue
|
||||
{
|
||||
public static List<QueueItem> QueueItems = new List<QueueItem>();
|
||||
|
||||
public class QueueItem
|
||||
@@ -115,8 +115,8 @@ namespace gaseous_server
|
||||
};
|
||||
private List<QueueItemType> _Blocks = new List<QueueItemType>();
|
||||
|
||||
public List<DayOfWeek> AllowedDays
|
||||
{
|
||||
public List<DayOfWeek> AllowedDays
|
||||
{
|
||||
get
|
||||
{
|
||||
return _AllowedDays;
|
||||
@@ -124,7 +124,7 @@ namespace gaseous_server
|
||||
set
|
||||
{
|
||||
_AllowedDays = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
public int AllowedStartHours { get; set; } = 0;
|
||||
public int AllowedStartMinutes { get; set; } = 0;
|
||||
@@ -135,7 +135,7 @@ namespace gaseous_server
|
||||
public DateTime LastRunTime => _LastRunTime;
|
||||
public DateTime LastFinishTime => _LastFinishTime;
|
||||
public double LastRunDuration => _LastRunDuration;
|
||||
public DateTime NextRunTime
|
||||
public DateTime NextRunTime
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -247,13 +247,13 @@ namespace gaseous_server
|
||||
|
||||
Logging.Log(Logging.LogType.Debug, "Signature Import", "Processing TOSEC files");
|
||||
tIngest.Import(Path.Combine(Config.LibraryConfiguration.LibrarySignatureImportDirectory, "TOSEC"), gaseous_signature_parser.parser.SignatureParser.TOSEC);
|
||||
|
||||
|
||||
Logging.Log(Logging.LogType.Debug, "Signature Import", "Processing MAME Arcade files");
|
||||
tIngest.Import(Path.Combine(Config.LibraryConfiguration.LibrarySignatureImportDirectory, "MAME Arcade"), gaseous_signature_parser.parser.SignatureParser.MAMEArcade);
|
||||
|
||||
Logging.Log(Logging.LogType.Debug, "Signature Import", "Processing MAME MESS files");
|
||||
tIngest.Import(Path.Combine(Config.LibraryConfiguration.LibrarySignatureImportDirectory, "MAME MESS"), gaseous_signature_parser.parser.SignatureParser.MAMEMess);
|
||||
|
||||
|
||||
_SaveLastRunTime = true;
|
||||
|
||||
break;
|
||||
@@ -350,7 +350,8 @@ namespace gaseous_server
|
||||
|
||||
case QueueItemType.DailyMaintainer:
|
||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Daily Maintenance");
|
||||
Classes.Maintenance maintenance = new Maintenance{
|
||||
Classes.Maintenance maintenance = new Maintenance
|
||||
{
|
||||
CallingQueueItem = this
|
||||
};
|
||||
maintenance.RunDailyMaintenance();
|
||||
@@ -361,7 +362,8 @@ namespace gaseous_server
|
||||
|
||||
case QueueItemType.WeeklyMaintainer:
|
||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Weekly Maintenance");
|
||||
Classes.Maintenance weeklyMaintenance = new Maintenance{
|
||||
Classes.Maintenance weeklyMaintenance = new Maintenance
|
||||
{
|
||||
CallingQueueItem = this
|
||||
};
|
||||
weeklyMaintenance.RunWeeklyMaintenance();
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -5,15 +5,17 @@
|
||||
<table style="width: 100%;">
|
||||
<tr>
|
||||
<th style="width: 20%;">Home Page</th>
|
||||
<td><a href="https://github.com/gaseous-project/gaseous-server" class="romlink">https://github.com/gaseous-project/gaseous-server</a></td>
|
||||
<td><a href="https://github.com/gaseous-project/gaseous-server"
|
||||
class="romlink">https://github.com/gaseous-project/gaseous-server</a></td>
|
||||
<td rowspan="5" style="text-align: center; width: 128px;">
|
||||
<img src="/images/logo.png" style="display: block; margin: 20px auto; width: 100px;" />
|
||||
<span style="display: block;">The Gaseous logo was designed by Tom2.0</span>
|
||||
<span style="display: block;">The Gaseous logo was designed by Tom1243</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Bugs and Feature Requests</th>
|
||||
<td><a href="https://github.com/gaseous-project/gaseous-server/issues" class="romlink">https://github.com/gaseous-project/gaseous-server/issues</a></td>
|
||||
<td><a href="https://github.com/gaseous-project/gaseous-server/issues"
|
||||
class="romlink">https://github.com/gaseous-project/gaseous-server/issues</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Join our Discord</th>
|
||||
@@ -33,21 +35,24 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;"><a href="https://github.com/EmulatorJS/EmulatorJS" target="_blank"><img src="/images/EmulatorJS.png" style="height: 36px;" /></a></td>
|
||||
<td style="text-align: center;"><a href="https://github.com/EmulatorJS/EmulatorJS" target="_blank"><img
|
||||
src="/images/EmulatorJS.png" style="height: 36px;" /></a></td>
|
||||
<td colspan="3">
|
||||
The EmulatorJS Project<br />
|
||||
<a href="https://github.com/EmulatorJS/EmulatorJS" target="_blank" class="romlink">https://github.com/EmulatorJS/EmulatorJS</a>
|
||||
<a href="https://github.com/EmulatorJS/EmulatorJS" target="_blank"
|
||||
class="romlink">https://github.com/EmulatorJS/EmulatorJS</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<h3>Data Sources</h2>
|
||||
<h4>Game data</h4>
|
||||
<h4>Game data</h4>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;">
|
||||
<a href="https://www.igdb.com/" target="_blank"><img src="/images/IGDB_logo.svg" style="filter: invert(100%); height: 36px;" /></a>
|
||||
<a href="https://www.igdb.com/" target="_blank"><img src="/images/IGDB_logo.svg"
|
||||
style="filter: invert(100%); height: 36px;" /></a>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
The Internet Game Database<br />
|
||||
@@ -61,7 +66,8 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;">
|
||||
<a href="https://www.tosecdev.org/" target="_blank"><img src="/images/TOSEC_logo.gif" style="height: 36px;" /></a>
|
||||
<a href="https://www.tosecdev.org/" target="_blank"><img src="/images/TOSEC_logo.gif"
|
||||
style="height: 36px;" /></a>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
The Old School Emulation Center<br />
|
||||
@@ -70,11 +76,13 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;">
|
||||
<a href="https://www.progettosnaps.net/index.php" target="_blank"><img src="/images/ProgettoSnaps.gif" style="height: 36px;" /></a>
|
||||
<a href="https://www.progettosnaps.net/index.php" target="_blank"><img src="/images/ProgettoSnaps.gif"
|
||||
style="height: 36px;" /></a>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
Progetto-Snaps<br />
|
||||
<a href="https://www.progettosnaps.net/index.php" target="_blank" class="romlink">https://www.progettosnaps.net/index.php</a>
|
||||
<a href="https://www.progettosnaps.net/index.php" target="_blank"
|
||||
class="romlink">https://www.progettosnaps.net/index.php</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
Reference in New Issue
Block a user