Compare commits
10 Commits
v1.7.5
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
![]() |
bec461259c | ||
![]() |
bb86cb52f6 | ||
![]() |
c615b804fa | ||
![]() |
7dfb0b54eb | ||
![]() |
f0783fcae8 | ||
![]() |
68be24d514 | ||
![]() |
a5da1a9033 | ||
![]() |
fc09681cdd | ||
![]() |
6185912151 | ||
![]() |
deef919d5b |
@@ -1,4 +0,0 @@
|
||||
DATABASE_HOST=mariadb
|
||||
DATABASE_USER=root
|
||||
DATABASE_PASSWORD=gaseous
|
||||
DATABASE_DB=gaseous
|
@@ -2,5 +2,5 @@ FROM mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm
|
||||
|
||||
RUN apt-get update && apt-get install -y p7zip-full
|
||||
RUN mkdir -p /workspace/gaseous-server/wwwroot/emulators/EmulatorJS
|
||||
RUN wget https://cdn.emulatorjs.org/releases/4.0.11.7z
|
||||
RUN 7z x -y -o/workspace/gaseous-server/wwwroot/emulators/EmulatorJS 4.0.11.7z
|
||||
RUN wget https://cdn.emulatorjs.org/releases/4.0.12.7z
|
||||
RUN 7z x -y -o/workspace/gaseous-server/wwwroot/emulators/EmulatorJS 4.0.12.7z
|
@@ -36,7 +36,9 @@
|
||||
"AndersEAndersen.html-class-suggestions",
|
||||
"george-alisson.html-preview-vscode",
|
||||
"ms-dotnettools.vscodeintellicode-csharp",
|
||||
"Zignd.html-css-class-completion"
|
||||
"Zignd.html-css-class-completion",
|
||||
"PWABuilder.pwa-studio",
|
||||
"ms-azuretools.vscode-docker"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@@ -11,11 +11,13 @@ services:
|
||||
- dbhost=${DATABASE_HOST}
|
||||
- dbuser=${DATABASE_USER}
|
||||
- dbpass=${DATABASE_PASSWORD}
|
||||
- igdbclientid=<clientid>
|
||||
- igdbclientsecret=<clientsecret>
|
||||
- igdbclientid=${IGDB_CLIENT_ID}
|
||||
- igdbclientsecret=${IGDB_CLIENT_SECRET}
|
||||
mariadb:
|
||||
hostname: mariadb
|
||||
image: mariadb:latest
|
||||
ports:
|
||||
- 3306:3306
|
||||
environment:
|
||||
- MARIADB_ROOT_PASSWORD=${DATABASE_PASSWORD}
|
||||
- MARIADB_DATABASE=${DATABASE_DB}
|
||||
|
@@ -59,7 +59,5 @@ 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
@@ -27,19 +27,10 @@ jobs:
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push standard image
|
||||
uses: docker/build-push-action@v6
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
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
|
85
.github/workflows/codeql.yml
vendored
@@ -1,85 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main", "branch-v*.*.*" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "main" ]
|
||||
schedule:
|
||||
- cron: '21 11 * * 2'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
||||
# - https://gh.io/supported-runners-and-hardware-resources
|
||||
# - https://gh.io/using-larger-runners
|
||||
# Consider using larger runners for possible analysis time improvements.
|
||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
||||
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'csharp', 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ]
|
||||
# Use only 'java' to analyze code written in Java, Kotlin or both
|
||||
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Sign in to Nuget
|
||||
run: dotnet nuget add source --username michael-j-green --password ${{ secrets.NUGETKEY }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/gaseous-project/index.json"
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
3
.gitignore
vendored
@@ -404,4 +404,7 @@ ASALocalRun/
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
gaseous-server/.DS_Store
|
||||
gaseous-server/wwwroot/.DS_Store
|
||||
gaseous-server/wwwroot/emulators/EmulatorJS
|
||||
.devcontainer/.env
|
||||
.mono/
|
||||
|
@@ -21,6 +21,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "screenshots", "screenshots"
|
||||
screenshots\Game.png = screenshots\Game.png
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gaseous-cli", "gaseous-cli\gaseous-cli.csproj", "{419CC4E4-8932-4E4A-B027-5521AA0CBA85}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -31,6 +33,10 @@ Global
|
||||
{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
|
||||
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@@ -16,9 +16,9 @@ Version 1.7.0 and later contain user authentication, and can be exposed to the i
|
||||
While we do our best to stay on top of server security, if you expose the server to the internet **you do so at your own risk**.
|
||||
|
||||
## Screenshots
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
|
||||
## Requirements
|
||||
|
@@ -9,24 +9,27 @@ RUN echo "Build: $BUILDPLATFORM"
|
||||
|
||||
# Copy everything
|
||||
COPY .. ./
|
||||
|
||||
# Build Gaseous Web Server
|
||||
# Restore as distinct layers
|
||||
RUN dotnet restore "gaseous-server/gaseous-server.csproj" -a $TARGETARCH
|
||||
# Build and publish a release
|
||||
RUN dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime --self-contained true -c Release -o out -a $TARGETARCH
|
||||
|
||||
# disabled for 1.7.4 as the next version EmulatorJS is not yet available
|
||||
# # update apt-get
|
||||
# RUN apt-get update
|
||||
# Build Gaseous CLI
|
||||
# Restore as distinct layers
|
||||
RUN dotnet restore "gaseous-cli/gaseous-cli.csproj" -a $TARGETARCH
|
||||
# Build and publish a release
|
||||
RUN dotnet publish "gaseous-cli/gaseous-cli.csproj" --use-current-runtime --self-contained true -c Release -o out -a $TARGETARCH
|
||||
|
||||
# update apt-get
|
||||
RUN apt-get update
|
||||
|
||||
# # download and unzip EmulatorJS from CDN
|
||||
# RUN apt-get install -y p7zip-full
|
||||
# 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 apt-get install -y p7zip-full
|
||||
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||
RUN cp -fr cdn.emulatorjs.org/latest/* out/wwwroot/emulators/EmulatorJS
|
||||
RUN rm -Rf cdn.emulatorjs.org
|
||||
RUN wget https://cdn.emulatorjs.org/releases/4.0.12.7z
|
||||
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.0.12.7z
|
||||
|
||||
# clean up apt-get
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists
|
||||
@@ -37,5 +40,34 @@ ENV INDOCKER=1
|
||||
WORKDIR /App
|
||||
COPY --from=build-env /App/out .
|
||||
|
||||
# start gaseous-server
|
||||
ENTRYPOINT ["dotnet", "gaseous-server.dll"]
|
||||
# variables
|
||||
ARG PUID=1000
|
||||
ARG PGID=1000
|
||||
ARG dbhost=localhost
|
||||
ARG dbuser=root
|
||||
ARG dbpass=gaseous
|
||||
|
||||
ENV PUID=${PUID}
|
||||
ENV PGID=${PGID}
|
||||
ENV dbhost=${dbhost}
|
||||
ENV dbuser=${dbuser}
|
||||
ENV dbpass=${dbpass}
|
||||
|
||||
# install supervisord
|
||||
RUN apt-get update && apt-get install -y supervisor
|
||||
COPY ../build/standard/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/standard/entrypoint.sh /usr/sbin/entrypoint.sh
|
||||
RUN chmod +x /usr/sbin/entrypoint.sh
|
||||
|
||||
# volumes
|
||||
VOLUME /home/gaseous/.gaseous-server
|
||||
|
||||
# start services
|
||||
ENTRYPOINT [ "/usr/sbin/entrypoint.sh" ]
|
@@ -9,25 +9,27 @@ RUN echo "Build: $BUILDPLATFORM"
|
||||
|
||||
# Copy everything
|
||||
COPY .. ./
|
||||
|
||||
# Build Gaseous Web Server
|
||||
# Restore as distinct layers
|
||||
RUN dotnet restore "gaseous-server/gaseous-server.csproj" -a $TARGETARCH
|
||||
# Build and publish a release
|
||||
RUN dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime --self-contained true -c Release -o out -a $TARGETARCH
|
||||
|
||||
# disabled for 1.7.4 as the next version EmulatorJS is not yet available
|
||||
# # update apt-get
|
||||
# RUN apt-get update
|
||||
# Build Gaseous CLI
|
||||
# Restore as distinct layers
|
||||
RUN dotnet restore "gaseous-cli/gaseous-cli.csproj" -a $TARGETARCH
|
||||
# Build and publish a release
|
||||
RUN dotnet publish "gaseous-cli/gaseous-cli.csproj" --use-current-runtime --self-contained true -c Release -o out -a $TARGETARCH
|
||||
|
||||
# update apt-get
|
||||
RUN apt-get update
|
||||
|
||||
# # download and unzip EmulatorJS from CDN
|
||||
# RUN apt-get install -y p7zip-full
|
||||
# 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 apt-get install -y p7zip-full
|
||||
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||
RUN cp -fr cdn.emulatorjs.org/latest/* out/wwwroot/emulators/EmulatorJS
|
||||
RUN rm -Rf cdn.emulatorjs.org
|
||||
RUN wget https://cdn.emulatorjs.org/releases/4.0.12.7z
|
||||
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.0.12.7z
|
||||
|
||||
# Build runtime image
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
@@ -54,12 +56,12 @@ ENV MARIADB_ROOT_PASSWORD=${dbpass}
|
||||
RUN DEBIAN_FRONTEND=noninteractive && \
|
||||
apt-get update && apt-get install -y mariadb-server
|
||||
RUN mkdir -p /run/mysqld
|
||||
COPY ../build/mariadb.sh /usr/sbin/start-mariadb.sh
|
||||
COPY ../build/embeddeddb/mariadb.sh /usr/sbin/start-mariadb.sh
|
||||
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
|
||||
COPY ../build/embeddeddb/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
RUN mkdir -p /var/run/supervisord
|
||||
RUN mkdir -p /var/log/supervisord
|
||||
|
||||
@@ -67,7 +69,7 @@ RUN mkdir -p /var/log/supervisord
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists
|
||||
|
||||
# copy entrypoint
|
||||
COPY ../build/entrypoint.sh /usr/sbin/entrypoint.sh
|
||||
COPY ../build/embeddeddb/entrypoint.sh /usr/sbin/entrypoint.sh
|
||||
RUN chmod +x /usr/sbin/entrypoint.sh
|
||||
|
||||
# volumes
|
||||
|
18
build/embeddeddb/entrypoint.sh
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/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
|
||||
chown -R ${PUID} /App /home/gaseous/.gaseous-server
|
||||
chgrp -R ${PGID} /App /home/gaseous/.gaseous-server
|
||||
|
||||
# Set MariaDB permissions
|
||||
mkdir -p /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
chown -R ${PUID} /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
chgrp -R ${PGID} /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||
|
||||
# Start supervisord and services
|
||||
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
@@ -1,20 +1,25 @@
|
||||
#!/bin/sh
|
||||
|
||||
# install the database
|
||||
echo "Installing MariaDB"
|
||||
/usr/bin/mariadb-install-db --datadir=/var/lib/mysql --user=gaseous
|
||||
|
||||
# start the database server without network or grant tables
|
||||
echo "Starting MariaDB"
|
||||
/usr/sbin/mariadbd --datadir=/var/lib/mysql --skip-grant-tables --skip-networking &
|
||||
|
||||
# wait for the server to start
|
||||
sleep 5
|
||||
|
||||
# change the root password
|
||||
echo "Setting MariaDB 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
|
||||
echo "Stopping MariaDB"
|
||||
killall mariadbd
|
||||
|
||||
# start the server normally
|
||||
/usr/sbin/mariadbd --datadir=/var/lib/mysql
|
||||
echo "Starting MariaDB"
|
||||
/usr/sbin/mariadbd --datadir=/var/lib/mysql --user=gaseous
|
@@ -1,13 +0,0 @@
|
||||
#!/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
|
13
build/standard/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
|
||||
chown -R ${PUID} /App /home/gaseous/.gaseous-server
|
||||
chgrp -R ${PGID} /App /home/gaseous/.gaseous-server
|
||||
|
||||
# Start supervisord and services
|
||||
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
28
build/standard/supervisord.conf
Normal file
@@ -0,0 +1,28 @@
|
||||
[supervisord]
|
||||
user=root
|
||||
nodaemon=true
|
||||
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: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
|
@@ -4,6 +4,7 @@ services:
|
||||
container_name: gaseous-server
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: ./build/Dockerfile
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- gaseous
|
||||
@@ -12,7 +13,7 @@ services:
|
||||
ports:
|
||||
- 5198:80
|
||||
volumes:
|
||||
- gs:/root/.gaseous-server
|
||||
- gs:/home/gaseous/.gaseous-server
|
||||
environment:
|
||||
- TZ=Australia/Sydney
|
||||
- dbhost=gsdb
|
||||
|
@@ -11,7 +11,7 @@ services:
|
||||
ports:
|
||||
- 5198:80
|
||||
volumes:
|
||||
- gs:/root/.gaseous-server
|
||||
- gs:/home/gaseous/.gaseous-server
|
||||
environment:
|
||||
- TZ=Australia/Sydney
|
||||
- dbhost=gsdb
|
||||
|
354
gaseous-cli/Program.cs
Normal file
@@ -0,0 +1,354 @@
|
||||
using System;
|
||||
using Authentication;
|
||||
using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
/* ------------------------------------------------- */
|
||||
/* This tool is a CLI tool that is used to manage */
|
||||
/* the Gaseous Server. */
|
||||
/* Functions such as user management, and backups */
|
||||
/* are available. */
|
||||
/* ------------------------------------------------- */
|
||||
|
||||
// load app settings
|
||||
Config.InitSettings();
|
||||
|
||||
// set up database connection
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
// set up identity
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
|
||||
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
|
||||
{
|
||||
options.Password.RequireDigit = true;
|
||||
options.Password.RequireLowercase = true;
|
||||
options.Password.RequireNonAlphanumeric = false;
|
||||
options.Password.RequireUppercase = true;
|
||||
options.Password.RequiredLength = 10;
|
||||
options.User.AllowedUserNameCharacters = null;
|
||||
options.User.RequireUniqueEmail = true;
|
||||
options.SignIn.RequireConfirmedPhoneNumber = false;
|
||||
options.SignIn.RequireConfirmedEmail = false;
|
||||
options.SignIn.RequireConfirmedAccount = false;
|
||||
})
|
||||
.AddUserStore<UserStore>()
|
||||
.AddRoleStore<RoleStore>()
|
||||
;
|
||||
services.AddScoped<UserStore>();
|
||||
services.AddScoped<RoleStore>();
|
||||
|
||||
services.AddTransient<IUserStore<ApplicationUser>, UserStore>();
|
||||
services.AddTransient<IRoleStore<ApplicationRole>, RoleStore>();
|
||||
var userManager = services.BuildServiceProvider().GetService<UserManager<ApplicationUser>>();
|
||||
|
||||
// load the command line arguments
|
||||
string[] cmdArgs = Environment.GetCommandLineArgs();
|
||||
|
||||
// check if the user has entered any arguments
|
||||
if (cmdArgs.Length == 1)
|
||||
{
|
||||
// no arguments were entered
|
||||
Console.WriteLine("Gaseous CLI - A tool for managing the Gaseous Server");
|
||||
Console.WriteLine("Usage: gaseous-cli [command] [options]");
|
||||
Console.WriteLine("Commands:");
|
||||
Console.WriteLine(" user [command] [options] - Manage users");
|
||||
Console.WriteLine(" role [command] [options] - Manage roles");
|
||||
// Console.WriteLine(" backup [command] [options] - Manage backups");
|
||||
// Console.WriteLine(" restore [command] [options] - Restore backups");
|
||||
Console.WriteLine(" help - Display this help message");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the help command
|
||||
if (cmdArgs[1] == "help")
|
||||
{
|
||||
// display the help message
|
||||
Console.WriteLine("Gaseous CLI - A tool for managing the Gaseous Server");
|
||||
Console.WriteLine("Usage: gaseous-cli [command] [options]");
|
||||
Console.WriteLine("Commands:");
|
||||
Console.WriteLine(" user [command] [options] - Manage users");
|
||||
Console.WriteLine(" role [command] [options] - Manage roles");
|
||||
// Console.WriteLine(" backup [command] [options] - Manage backups");
|
||||
// Console.WriteLine(" restore [command] [options] - Restore backups");
|
||||
Console.WriteLine(" help - Display this help message");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the user command
|
||||
if (cmdArgs[1] == "user")
|
||||
{
|
||||
// check if the user has entered any arguments
|
||||
if (cmdArgs.Length == 2)
|
||||
{
|
||||
// no arguments were entered
|
||||
Console.WriteLine("User Management");
|
||||
Console.WriteLine("Usage: gaseous-cli user [command] [options]");
|
||||
Console.WriteLine("Commands:");
|
||||
Console.WriteLine(" add [username] [password] - Add a new user");
|
||||
Console.WriteLine(" delete [username] - Delete a user");
|
||||
Console.WriteLine(" resetpassword [username] [password] - Reset a user's password");
|
||||
Console.WriteLine(" list - List all users");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the add command
|
||||
if (cmdArgs[2] == "add")
|
||||
{
|
||||
// check if the user has entered the username and password
|
||||
if (cmdArgs.Length < 5)
|
||||
{
|
||||
// the username and password were not entered
|
||||
Console.WriteLine("Error: Please enter a username and password");
|
||||
return;
|
||||
}
|
||||
|
||||
// add a new user
|
||||
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||
if (userTable.GetUserByEmail(cmdArgs[3]) != null)
|
||||
{
|
||||
Console.WriteLine("Error: User already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
// create the user object
|
||||
ApplicationUser user = new ApplicationUser
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
Email = cmdArgs[3],
|
||||
NormalizedEmail = cmdArgs[3].ToUpper(),
|
||||
EmailConfirmed = true,
|
||||
UserName = cmdArgs[3],
|
||||
NormalizedUserName = cmdArgs[3].ToUpper()
|
||||
};
|
||||
|
||||
// create the password
|
||||
PasswordHasher<ApplicationUser> passwordHasher = new PasswordHasher<ApplicationUser>();
|
||||
user.PasswordHash = passwordHasher.HashPassword(user, cmdArgs[4]);
|
||||
|
||||
await userManager.CreateAsync(user);
|
||||
await userManager.AddToRoleAsync(user, "Player");
|
||||
|
||||
Console.WriteLine("User created successfully with default role: Player");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the delete command
|
||||
if (cmdArgs[2] == "delete")
|
||||
{
|
||||
// check if the user has entered the username
|
||||
if (cmdArgs.Length < 4)
|
||||
{
|
||||
// the username was not entered
|
||||
Console.WriteLine("Error: Please enter a username");
|
||||
return;
|
||||
}
|
||||
|
||||
// delete the user
|
||||
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||
ApplicationUser user = userTable.GetUserByEmail(cmdArgs[3]);
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine("Error: User not found");
|
||||
return;
|
||||
}
|
||||
|
||||
await userManager.DeleteAsync(user);
|
||||
|
||||
Console.WriteLine("User deleted successfully");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the resetpassword command
|
||||
if (cmdArgs[2] == "resetpassword")
|
||||
{
|
||||
// check if the user has entered the username and password
|
||||
if (cmdArgs.Length < 5)
|
||||
{
|
||||
// the username and password were not entered
|
||||
Console.WriteLine("Error: Please enter a username and password");
|
||||
return;
|
||||
}
|
||||
|
||||
// reset the user's password
|
||||
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||
ApplicationUser user = userTable.GetUserByEmail(cmdArgs[3]);
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine("Error: User not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// create the password
|
||||
PasswordHasher<ApplicationUser> passwordHasher = new PasswordHasher<ApplicationUser>();
|
||||
user.PasswordHash = passwordHasher.HashPassword(user, cmdArgs[4]);
|
||||
|
||||
await userManager.UpdateAsync(user);
|
||||
|
||||
Console.WriteLine("Password reset successfully");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the list command
|
||||
if (cmdArgs[2] == "list")
|
||||
{
|
||||
// list all users
|
||||
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||
var userList = userTable.GetUsers();
|
||||
foreach (var user in userList)
|
||||
{
|
||||
var roles = await userManager.GetRolesAsync(user);
|
||||
Console.WriteLine(user.Email + " - " + string.Join(", ", roles));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check if the user has entered the role command
|
||||
if (cmdArgs[1] == "role")
|
||||
{
|
||||
// check if the user has entered any arguments
|
||||
if (cmdArgs.Length == 2)
|
||||
{
|
||||
// no arguments were entered
|
||||
Console.WriteLine("Role Management");
|
||||
Console.WriteLine("Usage: gaseous-cli role [command] [options]");
|
||||
Console.WriteLine("Commands:");
|
||||
Console.WriteLine(" set [username] [role] - Set the role of a user");
|
||||
Console.WriteLine(" list - List all roles");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the role command
|
||||
if (cmdArgs[2] == "set")
|
||||
{
|
||||
// check if the user has entered the username and role
|
||||
if (cmdArgs.Length < 5)
|
||||
{
|
||||
// the username and role were not entered
|
||||
Console.WriteLine("Error: Please enter a username and role");
|
||||
return;
|
||||
}
|
||||
|
||||
// set the role of the user
|
||||
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||
ApplicationUser user = userTable.GetUserByEmail(cmdArgs[3]);
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine("Error: User not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// remove all existing roles from user
|
||||
var roles = await userManager.GetRolesAsync(user);
|
||||
await userManager.RemoveFromRolesAsync(user, roles.ToArray());
|
||||
|
||||
// add the new role to the user
|
||||
await userManager.AddToRoleAsync(user, cmdArgs[4]);
|
||||
|
||||
Console.WriteLine("Role set successfully");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the user has entered the list command
|
||||
if (cmdArgs[2] == "list")
|
||||
{
|
||||
// list all roles
|
||||
string[] roles = { "Player", "Gamer", "Admin" };
|
||||
foreach (var role in roles)
|
||||
{
|
||||
Console.WriteLine(role);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// // check if the user has entered the backup command
|
||||
// if (cmdArgs[1] == "backup")
|
||||
// {
|
||||
// // check if the user has entered any arguments
|
||||
// if (cmdArgs.Length == 2)
|
||||
// {
|
||||
// // no arguments were entered
|
||||
// Console.WriteLine("Backup Management");
|
||||
// Console.WriteLine("Usage: gaseous-cli backup [command] [options]");
|
||||
// Console.WriteLine("Commands:");
|
||||
// Console.WriteLine(" create - Create a backup");
|
||||
// Console.WriteLine(" list - List all backups");
|
||||
// Console.WriteLine(" remove [backup_id] - Remove a backup");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // check if the user has entered the create command
|
||||
// if (cmdArgs[2] == "create")
|
||||
// {
|
||||
// // create a backup
|
||||
// Backup.CreateBackup();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // check if the user has entered the list command
|
||||
// if (cmdArgs[2] == "list")
|
||||
// {
|
||||
// // list all backups
|
||||
// Backup.ListBackups();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // check if the user has entered the remove command
|
||||
// if (cmdArgs[2] == "remove")
|
||||
// {
|
||||
// // check if the user has entered the backup id
|
||||
// if (cmdArgs.Length < 4)
|
||||
// {
|
||||
// // the backup id was not entered
|
||||
// Console.WriteLine("Error: Please enter a backup id");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // remove the backup
|
||||
// Backup.RemoveBackup(cmdArgs[3]);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // check if the user has entered the restore command
|
||||
// if (cmdArgs[1] == "restore")
|
||||
// {
|
||||
// // check if the user has entered any arguments
|
||||
// if (cmdArgs.Length == 2)
|
||||
// {
|
||||
// // no arguments were entered
|
||||
// Console.WriteLine("Restore Management");
|
||||
// Console.WriteLine("Usage: gaseous-cli restore [command] [options]");
|
||||
// Console.WriteLine("Commands:");
|
||||
// Console.WriteLine(" restore [backup_id] - Restore a backup");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // check if the user has entered the restore command
|
||||
// if (cmdArgs[2] == "restore")
|
||||
// {
|
||||
// // check if the user has entered the backup id
|
||||
// if (cmdArgs.Length < 4)
|
||||
// {
|
||||
// // the backup id was not entered
|
||||
// Console.WriteLine("Error: Please enter a backup id");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // restore the backup
|
||||
// Restore.RestoreBackup(cmdArgs[3]);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// the user entered an invalid command
|
||||
Console.WriteLine("Error: Invalid command");
|
28
gaseous-cli/gaseous-cli.csproj
Normal file
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>gaseous_cli</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\net8.0\gaseous-cli.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Release\net8.0\gaseous-cli.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.3.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\gaseous-server\gaseous-server.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
BIN
gaseous-server/.DS_Store
vendored
@@ -12,6 +12,6 @@ namespace Authentication
|
||||
{
|
||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||
public List<UserPreferenceViewModel> UserPreferences { get; set; }
|
||||
public Guid Avatar { get; set; }
|
||||
public Guid ProfileId { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -104,7 +104,7 @@ namespace Authentication
|
||||
var roleName = GetRoleName(roleId);
|
||||
ApplicationRole? role = null;
|
||||
|
||||
if(roleName != null)
|
||||
if (roleName != null)
|
||||
{
|
||||
role = new ApplicationRole();
|
||||
role.Id = roleId;
|
||||
@@ -153,7 +153,7 @@ namespace Authentication
|
||||
string commandText = "Select Name from Roles";
|
||||
|
||||
var rows = _database.ExecuteCMDDict(commandText);
|
||||
foreach(Dictionary<string, object> row in rows)
|
||||
foreach (Dictionary<string, object> row in rows)
|
||||
{
|
||||
ApplicationRole role = (ApplicationRole)Activator.CreateInstance(typeof(ApplicationRole));
|
||||
role.Id = (string)row["Id"];
|
||||
|
@@ -35,7 +35,7 @@ namespace Authentication
|
||||
parameters.Add("@userId", userId);
|
||||
|
||||
var rows = _database.ExecuteCMD(commandText, parameters).Rows;
|
||||
foreach(DataRow row in rows)
|
||||
foreach (DataRow row in rows)
|
||||
{
|
||||
roles.Add((string)row["Name"]);
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ namespace Authentication
|
||||
/// Class that represents the Users table in the MySQL Database
|
||||
/// </summary>
|
||||
public class UserTable<TUser>
|
||||
where TUser :ApplicationUser
|
||||
where TUser : ApplicationUser
|
||||
{
|
||||
private Database _database;
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace Authentication
|
||||
public TUser GetUserById(string userId)
|
||||
{
|
||||
TUser user = null;
|
||||
string commandText = "Select * from Users LEFT JOIN (SELECT UserId, Id AS AvatarId FROM UserAvatars) UserAvatars ON Users.Id = UserAvatars.UserId where Id = @id";
|
||||
string commandText = "Select * from Users LEFT JOIN (SELECT Id As ProfileId, UserId FROM UserProfiles) UserProfiles ON Users.Id = UserProfiles.UserId where Id = @id";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@id", userId } };
|
||||
|
||||
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
||||
@@ -89,7 +89,7 @@ namespace Authentication
|
||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true:false;
|
||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true : false;
|
||||
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
||||
@@ -97,10 +97,10 @@ namespace Authentication
|
||||
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
||||
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true : false;
|
||||
user.SecurityProfile = GetSecurityProfile(user);
|
||||
user.UserPreferences = GetPreferences(user);
|
||||
user.Avatar = string.IsNullOrEmpty((string?)row["AvatarId"]) ? Guid.Empty : Guid.Parse((string?)row["AvatarId"]);
|
||||
user.ProfileId = string.IsNullOrEmpty((string?)row["ProfileId"]) ? Guid.Empty : Guid.Parse((string?)row["ProfileId"]);
|
||||
}
|
||||
|
||||
return user;
|
||||
@@ -114,11 +114,11 @@ namespace Authentication
|
||||
public List<TUser> GetUserByName(string normalizedUserName)
|
||||
{
|
||||
List<TUser> users = new List<TUser>();
|
||||
string commandText = "Select * from Users LEFT JOIN (SELECT UserId, Id AS AvatarId FROM UserAvatars) UserAvatars ON Users.Id = UserAvatars.UserId where NormalizedEmail = @name";
|
||||
string commandText = "Select * from Users LEFT JOIN (SELECT Id As ProfileId, UserId FROM UserProfiles) UserProfiles ON Users.Id = UserProfiles.UserId where NormalizedEmail = @name";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@name", normalizedUserName } };
|
||||
|
||||
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
||||
foreach(Dictionary<string, object> row in rows)
|
||||
foreach (Dictionary<string, object> row in rows)
|
||||
{
|
||||
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
|
||||
user.Id = (string)row["Id"];
|
||||
@@ -127,7 +127,7 @@ namespace Authentication
|
||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true:false;
|
||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true : false;
|
||||
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
||||
@@ -135,10 +135,10 @@ namespace Authentication
|
||||
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
||||
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true : false;
|
||||
user.SecurityProfile = GetSecurityProfile(user);
|
||||
user.UserPreferences = GetPreferences(user);
|
||||
user.Avatar = string.IsNullOrEmpty((string?)row["AvatarId"]) ? Guid.Empty : Guid.Parse((string?)row["AvatarId"]);
|
||||
user.ProfileId = string.IsNullOrEmpty((string?)row["ProfileId"]) ? Guid.Empty : Guid.Parse((string?)row["ProfileId"]);
|
||||
users.Add(user);
|
||||
}
|
||||
|
||||
@@ -148,10 +148,10 @@ namespace Authentication
|
||||
public List<TUser> GetUsers()
|
||||
{
|
||||
List<TUser> users = new List<TUser>();
|
||||
string commandText = "Select * from Users LEFT JOIN (SELECT UserId, Id AS AvatarId FROM UserAvatars) UserAvatars ON Users.Id = UserAvatars.UserId order by NormalizedUserName";
|
||||
string commandText = "Select * from Users LEFT JOIN (SELECT Id As ProfileId, UserId FROM UserProfiles) UserProfiles ON Users.Id = UserProfiles.UserId order by NormalizedUserName";
|
||||
|
||||
var rows = _database.ExecuteCMDDict(commandText);
|
||||
foreach(Dictionary<string, object> row in rows)
|
||||
foreach (Dictionary<string, object> row in rows)
|
||||
{
|
||||
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
|
||||
user.Id = (string)row["Id"];
|
||||
@@ -160,7 +160,7 @@ namespace Authentication
|
||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true:false;
|
||||
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true : false;
|
||||
user.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
||||
@@ -168,10 +168,10 @@ namespace Authentication
|
||||
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
||||
user.AccessFailedCount = string.IsNullOrEmpty((string?)row["AccessFailedCount"]) ? 0 : int.Parse((string?)row["AccessFailedCount"]);
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true:false;
|
||||
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true : false;
|
||||
user.SecurityProfile = GetSecurityProfile(user);
|
||||
user.UserPreferences = GetPreferences(user);
|
||||
user.Avatar = string.IsNullOrEmpty((string?)row["AvatarId"]) ? Guid.Empty : Guid.Parse((string?)row["AvatarId"]);
|
||||
user.ProfileId = string.IsNullOrEmpty((string?)row["ProfileId"]) ? Guid.Empty : Guid.Parse((string?)row["ProfileId"]);
|
||||
users.Add(user);
|
||||
}
|
||||
|
||||
@@ -258,10 +258,11 @@ namespace Authentication
|
||||
/// <returns></returns>
|
||||
public int Insert(TUser user)
|
||||
{
|
||||
string commandText = @"Insert into Users (UserName, Id, PasswordHash, SecurityStamp, ConcurrencyStamp, Email, EmailConfirmed, PhoneNumber, PhoneNumberConfirmed, NormalizedEmail, NormalizedUserName, AccessFailedCount, LockoutEnabled, LockoutEnd, TwoFactorEnabled) values (@name, @id, @pwdHash, @SecStamp, @concurrencystamp, @email ,@emailconfirmed ,@phonenumber, @phonenumberconfirmed, @normalizedemail, @normalizedusername, @accesscount, @lockoutenabled, @lockoutenddate, @twofactorenabled);";
|
||||
string commandText = @"Insert into Users (UserName, Id, PasswordHash, SecurityStamp, ConcurrencyStamp, Email, EmailConfirmed, PhoneNumber, PhoneNumberConfirmed, NormalizedEmail, NormalizedUserName, AccessFailedCount, LockoutEnabled, LockoutEnd, TwoFactorEnabled) values (@name, @id, @pwdHash, @SecStamp, @concurrencystamp, @email ,@emailconfirmed ,@phonenumber, @phonenumberconfirmed, @normalizedemail, @normalizedusername, @accesscount, @lockoutenabled, @lockoutenddate, @twofactorenabled); Insert into UserProfiles (Id, UserId, DisplayName, Quip, UnstructuredData) values (@profileId, @id, @email, '', '{}');";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@name", user.UserName);
|
||||
parameters.Add("@id", user.Id);
|
||||
parameters.Add("@profileId", Guid.NewGuid());
|
||||
parameters.Add("@pwdHash", user.PasswordHash);
|
||||
parameters.Add("@SecStamp", user.SecurityStamp);
|
||||
parameters.Add("@concurrencystamp", user.ConcurrencyStamp);
|
||||
@@ -292,7 +293,7 @@ namespace Authentication
|
||||
/// <returns></returns>
|
||||
private int Delete(string userId)
|
||||
{
|
||||
string commandText = "Delete from Users where Id = @userId; Delete from User_Settings where Id = @userId; Delete from GameState where UserId = @userId;";
|
||||
string commandText = "Delete from Users where Id = @userId; Delete from User_Settings where Id = @userId; Delete from UserProfiles where UserId = @userId; Delete from GameState where UserId = @userId;";
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("@userId", userId);
|
||||
|
||||
|
@@ -8,8 +8,9 @@ namespace Authentication
|
||||
public List<String> Roles { get; set; }
|
||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||
public List<UserPreferenceViewModel> UserPreferences { get; set; }
|
||||
public Guid Avatar { get; set; }
|
||||
public string HighestRole {
|
||||
public Guid ProfileId { get; set; }
|
||||
public string HighestRole
|
||||
{
|
||||
get
|
||||
{
|
||||
string _highestRole = "";
|
||||
|
@@ -8,11 +8,14 @@ namespace Authentication
|
||||
public DateTimeOffset? LockoutEnd { get; set; }
|
||||
public List<string> Roles { get; set; }
|
||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||
public Guid Avatar { get; set; }
|
||||
public string HighestRole {
|
||||
public Guid ProfileId { get; set; }
|
||||
public string HighestRole
|
||||
{
|
||||
get
|
||||
{
|
||||
string _highestRole = "";
|
||||
if (Roles != null)
|
||||
{
|
||||
foreach (string role in Roles)
|
||||
{
|
||||
switch (role)
|
||||
@@ -40,6 +43,11 @@ namespace Authentication
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_highestRole = "Player";
|
||||
}
|
||||
|
||||
return _highestRole;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.IO.Compression;
|
||||
@@ -159,6 +159,50 @@ namespace gaseous_server.Classes
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetLookupByCode(LookupTypes LookupType, string Code)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Id FROM " + LookupType.ToString() + " WHERE Code = @code";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "code", Code }
|
||||
};
|
||||
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
if (data.Rows.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)data.Rows[0]["Id"];
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetLookupByValue(LookupTypes LookupType, string Value)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Id FROM " + LookupType.ToString() + " WHERE Value = @value";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "value", Value }
|
||||
};
|
||||
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
if (data.Rows.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)data.Rows[0]["Id"];
|
||||
}
|
||||
}
|
||||
|
||||
public enum LookupTypes
|
||||
{
|
||||
Country,
|
||||
Language
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -154,8 +154,8 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Using configuration:");
|
||||
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(_config, Formatting.Indented));
|
||||
// Console.WriteLine("Using configuration:");
|
||||
// Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(_config, Formatting.Indented));
|
||||
}
|
||||
|
||||
public static void UpdateConfig()
|
||||
@@ -197,17 +197,12 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
string SettingName = (string)dataRow["Setting"];
|
||||
|
||||
if (SettingName.StartsWith("LastRun_"))
|
||||
{
|
||||
Console.WriteLine("Break");
|
||||
}
|
||||
|
||||
if (AppSettings.ContainsKey(SettingName))
|
||||
{
|
||||
AppSettings.Remove(SettingName);
|
||||
}
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Load Settings", "Loading setting " + SettingName + " from database");
|
||||
// Logging.Log(Logging.LogType.Information, "Load Settings", "Loading setting " + SettingName + " from database");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -645,7 +640,7 @@ namespace gaseous_server.Classes
|
||||
return MetadataPath;
|
||||
}
|
||||
|
||||
public string LibrarySignatureImportDirectory
|
||||
public string LibrarySignaturesDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -653,6 +648,14 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public string LibrarySignaturesProcessedDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(LibraryRootDirectory, "Signatures - Processed");
|
||||
}
|
||||
}
|
||||
|
||||
public void InitLibrary()
|
||||
{
|
||||
if (!Directory.Exists(LibraryRootDirectory)) { Directory.CreateDirectory(LibraryRootDirectory); }
|
||||
@@ -662,7 +665,8 @@ namespace gaseous_server.Classes
|
||||
if (!Directory.Exists(LibraryMetadataDirectory)) { Directory.CreateDirectory(LibraryMetadataDirectory); }
|
||||
if (!Directory.Exists(LibraryTempDirectory)) { Directory.CreateDirectory(LibraryTempDirectory); }
|
||||
if (!Directory.Exists(LibraryCollectionsDirectory)) { Directory.CreateDirectory(LibraryCollectionsDirectory); }
|
||||
if (!Directory.Exists(LibrarySignatureImportDirectory)) { Directory.CreateDirectory(LibrarySignatureImportDirectory); }
|
||||
if (!Directory.Exists(LibrarySignaturesDirectory)) { Directory.CreateDirectory(LibrarySignaturesDirectory); }
|
||||
if (!Directory.Exists(LibrarySignaturesProcessedDirectory)) { Directory.CreateDirectory(LibrarySignaturesProcessedDirectory); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -698,6 +702,10 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
private static bool _HasheousSubmitFixes { get; set; } = false;
|
||||
|
||||
private static string _HasheousAPIKey { get; set; } = "";
|
||||
|
||||
private static int _MaxLibraryScanWorkers
|
||||
{
|
||||
get
|
||||
@@ -732,6 +740,10 @@ namespace gaseous_server.Classes
|
||||
|
||||
public HasheousClient.Models.MetadataModel.SignatureSources SignatureSource = _SignatureSource;
|
||||
|
||||
public bool HasheousSubmitFixes = _HasheousSubmitFixes;
|
||||
|
||||
public string HasheousAPIKey = _HasheousAPIKey;
|
||||
|
||||
public int MaxLibraryScanWorkers = _MaxLibraryScanWorkers;
|
||||
|
||||
public string HasheousHost = _HasheousHost;
|
||||
|
@@ -73,6 +73,8 @@ namespace gaseous_server.Classes
|
||||
// load resources
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
DatabaseMemoryCacheOptions? CacheOptions = new DatabaseMemoryCacheOptions(false);
|
||||
|
||||
switch (_ConnectorType)
|
||||
{
|
||||
case databaseType.MySql:
|
||||
@@ -80,22 +82,22 @@ namespace gaseous_server.Classes
|
||||
string sql = "CREATE DATABASE IF NOT EXISTS `" + Config.DatabaseConfiguration.DatabaseName + "`;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
Logging.Log(Logging.LogType.Information, "Database", "Creating database if it doesn't exist");
|
||||
ExecuteCMD(sql, dbDict, 30, "server=" + Config.DatabaseConfiguration.HostName + ";port=" + Config.DatabaseConfiguration.Port + ";userid=" + Config.DatabaseConfiguration.UserName + ";password=" + Config.DatabaseConfiguration.Password);
|
||||
ExecuteCMD(sql, dbDict, CacheOptions, 30, "server=" + Config.DatabaseConfiguration.HostName + ";port=" + Config.DatabaseConfiguration.Port + ";userid=" + Config.DatabaseConfiguration.UserName + ";password=" + Config.DatabaseConfiguration.Password);
|
||||
|
||||
// check if schema version table is in place - if not, create the schema version table
|
||||
sql = "SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = '" + Config.DatabaseConfiguration.DatabaseName + "' AND TABLE_NAME = 'schema_version';";
|
||||
DataTable SchemaVersionPresent = ExecuteCMD(sql, dbDict);
|
||||
DataTable SchemaVersionPresent = ExecuteCMD(sql, dbDict, CacheOptions);
|
||||
if (SchemaVersionPresent.Rows.Count == 0)
|
||||
{
|
||||
// no schema table present - create it
|
||||
Logging.Log(Logging.LogType.Information, "Database", "Schema version table doesn't exist. Creating it.");
|
||||
sql = "CREATE TABLE `schema_version` (`schema_version` INT NOT NULL, PRIMARY KEY (`schema_version`)); INSERT INTO `schema_version` (`schema_version`) VALUES (0);";
|
||||
ExecuteCMD(sql, dbDict);
|
||||
ExecuteCMD(sql, dbDict, CacheOptions);
|
||||
}
|
||||
|
||||
sql = "SELECT schema_version FROM schema_version;";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
DataTable SchemaVersion = ExecuteCMD(sql, dbDict);
|
||||
DataTable SchemaVersion = ExecuteCMD(sql, dbDict, CacheOptions);
|
||||
int OuterSchemaVer = (int)SchemaVersion.Rows[0][0];
|
||||
if (OuterSchemaVer == 0)
|
||||
{
|
||||
@@ -118,7 +120,7 @@ namespace gaseous_server.Classes
|
||||
// apply script
|
||||
sql = "SELECT schema_version FROM schema_version;";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
SchemaVersion = ExecuteCMD(sql, dbDict);
|
||||
SchemaVersion = ExecuteCMD(sql, dbDict, CacheOptions);
|
||||
if (SchemaVersion.Rows.Count == 0)
|
||||
{
|
||||
// something is broken here... where's the table?
|
||||
@@ -140,12 +142,12 @@ namespace gaseous_server.Classes
|
||||
|
||||
// apply schema!
|
||||
Logging.Log(Logging.LogType.Information, "Database", "Updating schema to version " + i);
|
||||
ExecuteCMD(dbScript, dbDict, 180);
|
||||
ExecuteCMD(dbScript, dbDict, CacheOptions, 180);
|
||||
|
||||
sql = "UPDATE schema_version SET schema_version=@schemaver";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("schemaver", i);
|
||||
ExecuteCMD(sql, dbDict);
|
||||
ExecuteCMD(sql, dbDict, CacheOptions);
|
||||
|
||||
// run post-upgrade code
|
||||
DatabaseMigration.PostUpgradeScript(i, _ConnectorType);
|
||||
@@ -170,39 +172,83 @@ namespace gaseous_server.Classes
|
||||
|
||||
public DataTable ExecuteCMD(string Command)
|
||||
{
|
||||
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
return _ExecuteCMD(Command, dbDict, 30, "");
|
||||
return _ExecuteCMD(Command, dbDict, CacheOptions, 30, "");
|
||||
}
|
||||
|
||||
public DataTable ExecuteCMD(string Command, DatabaseMemoryCacheOptions? CacheOptions)
|
||||
{
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
return _ExecuteCMD(Command, dbDict, CacheOptions, 30, "");
|
||||
}
|
||||
|
||||
public DataTable ExecuteCMD(string Command, Dictionary<string, object> Parameters)
|
||||
{
|
||||
return _ExecuteCMD(Command, Parameters, 30, "");
|
||||
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||
|
||||
return _ExecuteCMD(Command, Parameters, CacheOptions, 30, "");
|
||||
}
|
||||
|
||||
public DataTable ExecuteCMD(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions)
|
||||
{
|
||||
return _ExecuteCMD(Command, Parameters, CacheOptions, 30, "");
|
||||
}
|
||||
|
||||
public DataTable ExecuteCMD(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
return _ExecuteCMD(Command, Parameters, Timeout, ConnectionString);
|
||||
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||
|
||||
return _ExecuteCMD(Command, Parameters, CacheOptions, Timeout, ConnectionString);
|
||||
}
|
||||
|
||||
public DataTable ExecuteCMD(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
return _ExecuteCMD(Command, Parameters, CacheOptions, Timeout, ConnectionString);
|
||||
}
|
||||
|
||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command)
|
||||
{
|
||||
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
return _ExecuteCMDDict(Command, dbDict, 30, "");
|
||||
return _ExecuteCMDDict(Command, dbDict, CacheOptions, 30, "");
|
||||
}
|
||||
|
||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, DatabaseMemoryCacheOptions? CacheOptions)
|
||||
{
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
return _ExecuteCMDDict(Command, dbDict, CacheOptions, 30, "");
|
||||
}
|
||||
|
||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters)
|
||||
{
|
||||
return _ExecuteCMDDict(Command, Parameters, 30, "");
|
||||
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||
|
||||
return _ExecuteCMDDict(Command, Parameters, CacheOptions, 30, "");
|
||||
}
|
||||
|
||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions)
|
||||
{
|
||||
return _ExecuteCMDDict(Command, Parameters, CacheOptions, 30, "");
|
||||
}
|
||||
|
||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
return _ExecuteCMDDict(Command, Parameters, Timeout, ConnectionString);
|
||||
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||
|
||||
return _ExecuteCMDDict(Command, Parameters, CacheOptions, Timeout, ConnectionString);
|
||||
}
|
||||
|
||||
private List<Dictionary<string, object>> _ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
public List<Dictionary<string, object>> ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
DataTable dataTable = _ExecuteCMD(Command, Parameters, Timeout, ConnectionString);
|
||||
return _ExecuteCMDDict(Command, Parameters, CacheOptions, Timeout, ConnectionString);
|
||||
}
|
||||
|
||||
private List<Dictionary<string, object>> _ExecuteCMDDict(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
DataTable dataTable = _ExecuteCMD(Command, Parameters, CacheOptions, Timeout, ConnectionString);
|
||||
|
||||
// convert datatable to dictionary
|
||||
List<Dictionary<string, object?>> rows = new List<Dictionary<string, object?>>();
|
||||
@@ -228,14 +274,45 @@ namespace gaseous_server.Classes
|
||||
return rows;
|
||||
}
|
||||
|
||||
private DataTable _ExecuteCMD(string Command, Dictionary<string, object> Parameters, int Timeout = 30, string ConnectionString = "")
|
||||
private DataTable _ExecuteCMD(string Command, Dictionary<string, object> Parameters, DatabaseMemoryCacheOptions? CacheOptions, int Timeout = 30, string ConnectionString = "")
|
||||
{
|
||||
string CacheKey = Command + string.Join(";", Parameters.Select(x => string.Join("=", x.Key, x.Value)));
|
||||
|
||||
if (CacheOptions is object && CacheOptions.CacheEnabled)
|
||||
{
|
||||
object? CachedData = DatabaseMemoryCache.GetCacheObject(CacheKey);
|
||||
if (CachedData is object)
|
||||
{
|
||||
return (DataTable)CachedData;
|
||||
}
|
||||
}
|
||||
|
||||
// purge cache if command contains "INSERT", "UPDATE", "DELETE", or "ALTER"
|
||||
if (
|
||||
Command.Contains("INSERT", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
Command.Contains("UPDATE", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
Command.Contains("DELETE", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
Command.Contains("ALTER", StringComparison.InvariantCultureIgnoreCase)
|
||||
)
|
||||
{
|
||||
// exclude logging events from purging the cache
|
||||
if (!Command.StartsWith("INSERT INTO SERVERLOGS", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
DatabaseMemoryCache.ClearCache();
|
||||
}
|
||||
}
|
||||
|
||||
if (ConnectionString == "") { ConnectionString = _ConnectionString; }
|
||||
switch (_ConnectorType)
|
||||
{
|
||||
case databaseType.MySql:
|
||||
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
||||
return (DataTable)conn.ExecCMD(Command, Parameters, Timeout);
|
||||
DataTable RetTable = conn.ExecCMD(Command, Parameters, Timeout);
|
||||
if (CacheOptions is object && CacheOptions.CacheEnabled)
|
||||
{
|
||||
DatabaseMemoryCache.SetCacheObject(CacheKey, RetTable, CacheOptions.ExpirationSeconds);
|
||||
}
|
||||
return RetTable;
|
||||
default:
|
||||
return new DataTable();
|
||||
}
|
||||
@@ -294,6 +371,148 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public static class DatabaseMemoryCache
|
||||
{
|
||||
private class MemoryCacheItem
|
||||
{
|
||||
public MemoryCacheItem(object CacheObject)
|
||||
{
|
||||
cacheObject = CacheObject;
|
||||
}
|
||||
|
||||
public MemoryCacheItem(object CacheObject, int ExpirationSeconds)
|
||||
{
|
||||
cacheObject = CacheObject;
|
||||
expirationSeconds = ExpirationSeconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The time the object was added to the cache in ticks
|
||||
/// </summary>
|
||||
public long addedTime { get; } = Environment.TickCount64;
|
||||
|
||||
/// <summary>
|
||||
/// The time the object will expire in ticks
|
||||
/// </summary>
|
||||
public long expirationTime
|
||||
{
|
||||
get
|
||||
{
|
||||
return addedTime + _expirationTicks;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of seconds the object will be cached
|
||||
/// </summary>
|
||||
public int expirationSeconds
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)TimeSpan.FromTicks(_expirationTicks).Seconds;
|
||||
}
|
||||
set
|
||||
{
|
||||
_expirationTicks = (long)TimeSpan.FromSeconds(value).Ticks;
|
||||
}
|
||||
}
|
||||
|
||||
private long _expirationTicks = (long)TimeSpan.FromSeconds(2).Ticks;
|
||||
|
||||
/// <summary>
|
||||
/// The object to be cached
|
||||
/// </summary>
|
||||
public object cacheObject { get; set; }
|
||||
}
|
||||
private static Dictionary<string, MemoryCacheItem> MemoryCache = new Dictionary<string, MemoryCacheItem>();
|
||||
private static Timer CacheTimer = new Timer(CacheTimerCallback, null, 0, 1000);
|
||||
|
||||
private static void CacheTimerCallback(object? state)
|
||||
{
|
||||
ClearExpiredCache();
|
||||
}
|
||||
|
||||
public static object? GetCacheObject(string CacheKey)
|
||||
{
|
||||
if (MemoryCache.ContainsKey(CacheKey))
|
||||
{
|
||||
if (MemoryCache[CacheKey].expirationTime < Environment.TickCount)
|
||||
{
|
||||
MemoryCache.Remove(CacheKey);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MemoryCache[CacheKey].cacheObject;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static void SetCacheObject(string CacheKey, object CacheObject, int ExpirationSeconds = 2)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (MemoryCache.ContainsKey(CacheKey))
|
||||
{
|
||||
MemoryCache.Remove(CacheKey);
|
||||
}
|
||||
MemoryCache.Add(CacheKey, new MemoryCacheItem(CacheObject, ExpirationSeconds));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Error while setting cache object", ex);
|
||||
ClearCache();
|
||||
}
|
||||
}
|
||||
public static void RemoveCacheObject(string CacheKey)
|
||||
{
|
||||
if (MemoryCache.ContainsKey(CacheKey))
|
||||
{
|
||||
MemoryCache.Remove(CacheKey);
|
||||
}
|
||||
}
|
||||
public static void ClearCache()
|
||||
{
|
||||
MemoryCache.Clear();
|
||||
}
|
||||
private static void ClearExpiredCache()
|
||||
{
|
||||
try
|
||||
{
|
||||
long currTime = Environment.TickCount64;
|
||||
|
||||
Dictionary<string, MemoryCacheItem> ExpiredItems = MemoryCache;
|
||||
foreach (string key in ExpiredItems.Keys)
|
||||
{
|
||||
if (MemoryCache[key].expirationTime < currTime)
|
||||
{
|
||||
Console.WriteLine("\x1b[95mPurging expired cache item " + key + ". Added: " + MemoryCache[key].addedTime + ". Expired: " + MemoryCache[key].expirationTime);
|
||||
MemoryCache.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Error while clearing expired cache", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DatabaseMemoryCacheOptions
|
||||
{
|
||||
public DatabaseMemoryCacheOptions(bool CacheEnabled = false, int ExpirationSeconds = 1)
|
||||
{
|
||||
this.CacheEnabled = CacheEnabled;
|
||||
this.ExpirationSeconds = ExpirationSeconds;
|
||||
}
|
||||
|
||||
public bool CacheEnabled { get; set; }
|
||||
public int ExpirationSeconds { get; set; }
|
||||
}
|
||||
|
||||
public int GetDatabaseSchemaVersion()
|
||||
{
|
||||
switch (_ConnectorType)
|
||||
@@ -384,7 +603,9 @@ namespace gaseous_server.Classes
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
||||
}
|
||||
RetTable.Load(cmd.ExecuteReader());
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
||||
Trace.WriteLine("Error executing " + SQL);
|
||||
Trace.WriteLine("Full exception: " + ex.ToString());
|
||||
@@ -397,7 +618,7 @@ namespace gaseous_server.Classes
|
||||
return RetTable;
|
||||
}
|
||||
|
||||
public int ExecNonQuery(string SQL, Dictionary< string, object> Parameters, int Timeout)
|
||||
public int ExecNonQuery(string SQL, Dictionary<string, object> Parameters, int Timeout)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
@@ -427,7 +648,9 @@ namespace gaseous_server.Classes
|
||||
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
||||
}
|
||||
result = cmd.ExecuteNonQuery();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
||||
Trace.WriteLine("Error executing " + SQL);
|
||||
Trace.WriteLine("Full exception: " + ex.ToString());
|
||||
|
@@ -1,6 +1,9 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using gaseous_server.Models;
|
||||
using IGDB.Models;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
@@ -64,6 +67,8 @@ namespace gaseous_server.Classes
|
||||
|
||||
public static void PostUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
@@ -103,6 +108,80 @@ namespace gaseous_server.Classes
|
||||
sql = "DELETE FROM Settings WHERE Setting LIKE 'LastRun_%';";
|
||||
db.ExecuteNonQuery(sql);
|
||||
break;
|
||||
|
||||
case 1023:
|
||||
// load country list
|
||||
Logging.Log(Logging.LogType.Information, "Database Upgrade", "Adding country look up table contents");
|
||||
|
||||
string countryResourceName = "gaseous_server.Support.Country.txt";
|
||||
using (Stream stream = assembly.GetManifestResourceStream(countryResourceName))
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
do
|
||||
{
|
||||
string[] line = reader.ReadLine().Split("|");
|
||||
|
||||
sql = "INSERT INTO Country (Code, Value) VALUES (@code, @value);";
|
||||
dbDict = new Dictionary<string, object>{
|
||||
{ "code", line[0] },
|
||||
{ "value", line[1] }
|
||||
};
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
} while (reader.EndOfStream == false);
|
||||
}
|
||||
|
||||
// load language list
|
||||
Logging.Log(Logging.LogType.Information, "Database Upgrade", "Adding language look up table contents");
|
||||
|
||||
string languageResourceName = "gaseous_server.Support.Language.txt";
|
||||
using (Stream stream = assembly.GetManifestResourceStream(languageResourceName))
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
do
|
||||
{
|
||||
string[] line = reader.ReadLine().Split("|");
|
||||
|
||||
sql = "INSERT INTO Language (Code, Value) VALUES (@code, @value);";
|
||||
dbDict = new Dictionary<string, object>{
|
||||
{ "code", line[0] },
|
||||
{ "value", line[1] }
|
||||
};
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
} while (reader.EndOfStream == false);
|
||||
}
|
||||
|
||||
// this is a safe background task
|
||||
BackgroundUpgradeTargetSchemaVersions.Add(1023);
|
||||
break;
|
||||
|
||||
case 1024:
|
||||
// create profiles for all existing users
|
||||
sql = "SELECT * FROM Users;";
|
||||
data = db.ExecuteCMD(sql);
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
// get legacy avatar from UserAvatars table
|
||||
sql = "SELECT Avatar FROM UserAvatars WHERE UserId = @userid;";
|
||||
dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "userid", row["Id"] }
|
||||
};
|
||||
DataTable avatarData = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
sql = "INSERT INTO UserProfiles (Id, UserId, DisplayName, Quip, Avatar, AvatarExtension, UnstructuredData) VALUES (@id, @userid, @displayname, @quip, @avatar, @avatarextension, @data);";
|
||||
dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "id", Guid.NewGuid() },
|
||||
{ "userid", row["Id"] },
|
||||
{ "displayname", row["Email"] },
|
||||
{ "quip", "" },
|
||||
{ "avatar", avatarData.Rows.Count > 0 ? avatarData.Rows[0]["Avatar"] : null },
|
||||
{ "avatarextension", avatarData.Rows.Count > 0 ? ".jpg" : null },
|
||||
{ "data", "{}" }
|
||||
};
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -117,6 +196,10 @@ namespace gaseous_server.Classes
|
||||
case 1002:
|
||||
MySql_1002_MigrateMetadataVersion();
|
||||
break;
|
||||
|
||||
case 1023:
|
||||
MySql_1023_MigrateMetadataVersion();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,5 +300,39 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void MySql_1023_MigrateMetadataVersion()
|
||||
{
|
||||
FileSignature fileSignature = new FileSignature();
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM Games_Roms WHERE RomDataVersion = 1;";
|
||||
DataTable data = db.ExecuteCMD(sql);
|
||||
long count = 1;
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Database Migration", "Updating ROM table for ROM (" + count + " / " + data.Rows.Count + "): " + (string)row["Name"]);
|
||||
|
||||
GameLibrary.LibraryItem library = GameLibrary.GetLibrary((int)row["LibraryId"]);
|
||||
Common.hashObject hash = new Common.hashObject()
|
||||
{
|
||||
md5hash = (string)row["MD5"],
|
||||
sha1hash = (string)row["SHA1"]
|
||||
};
|
||||
Signatures_Games signature = fileSignature.GetFileSignature(
|
||||
library,
|
||||
hash,
|
||||
new FileInfo((string)row["Path"]),
|
||||
(string)row["Path"]
|
||||
);
|
||||
|
||||
Platform platform = Platforms.GetPlatform((long)row["PlatformId"], false);
|
||||
Game game = Games.GetGame((long)row["GameId"], false, false, false);
|
||||
|
||||
ImportGame.StoreROM(library, hash, game, platform, signature, (string)row["Path"], (long)row["Id"]);
|
||||
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,9 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using HasheousClient.Models;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using NuGet.Common;
|
||||
using SevenZip;
|
||||
using SharpCompress.Archives;
|
||||
@@ -110,8 +113,10 @@ namespace gaseous_server.Classes
|
||||
// loop through contents until we find the first signature match
|
||||
List<ArchiveData> archiveFiles = new List<ArchiveData>();
|
||||
bool signatureFound = false;
|
||||
bool signatureSelectorAlreadyApplied = false;
|
||||
foreach (string file in Directory.GetFiles(ExtractPath, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
bool signatureSelector = false;
|
||||
if (File.Exists(file))
|
||||
{
|
||||
FileInfo zfi = new FileInfo(file);
|
||||
@@ -121,16 +126,6 @@ namespace gaseous_server.Classes
|
||||
|
||||
if (zfi != null)
|
||||
{
|
||||
ArchiveData archiveData = new ArchiveData
|
||||
{
|
||||
FileName = Path.GetFileName(file),
|
||||
FilePath = zfi.Directory.FullName.Replace(ExtractPath, ""),
|
||||
Size = zfi.Length,
|
||||
MD5 = hash.md5hash,
|
||||
SHA1 = hash.sha1hash
|
||||
};
|
||||
archiveFiles.Add(archiveData);
|
||||
|
||||
if (signatureFound == false)
|
||||
{
|
||||
gaseous_server.Models.Signatures_Games zDiscoveredSignature = _GetFileSignature(zhash, zfi.Name, zfi.Extension, zfi.Length, file, true);
|
||||
@@ -152,15 +147,37 @@ namespace gaseous_server.Classes
|
||||
discoveredSignature = zDiscoveredSignature;
|
||||
|
||||
signatureFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (signatureSelectorAlreadyApplied == false)
|
||||
{
|
||||
signatureSelector = true;
|
||||
signatureSelectorAlreadyApplied = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
discoveredSignature.Rom.Attributes.Add(new KeyValuePair<string, object>(
|
||||
ArchiveData archiveData = new ArchiveData
|
||||
{
|
||||
FileName = Path.GetFileName(file),
|
||||
FilePath = zfi.Directory.FullName.Replace(ExtractPath, ""),
|
||||
Size = zfi.Length,
|
||||
MD5 = zhash.md5hash,
|
||||
SHA1 = zhash.sha1hash,
|
||||
isSignatureSelector = signatureSelector
|
||||
};
|
||||
archiveFiles.Add(archiveData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (discoveredSignature.Rom.Attributes == null)
|
||||
{
|
||||
discoveredSignature.Rom.Attributes = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
discoveredSignature.Rom.Attributes.Add(
|
||||
"ZipContents", Newtonsoft.Json.JsonConvert.SerializeObject(archiveFiles)
|
||||
));
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -176,37 +193,45 @@ namespace gaseous_server.Classes
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Checking signature for file: " + GameFileImportPath + "\nMD5 hash: " + hash.md5hash + "\nSHA1 hash: " + hash.sha1hash);
|
||||
|
||||
|
||||
gaseous_server.Models.Signatures_Games discoveredSignature = new gaseous_server.Models.Signatures_Games();
|
||||
gaseous_server.Models.Signatures_Games? discoveredSignature = null;
|
||||
|
||||
// do database search first
|
||||
gaseous_server.Models.Signatures_Games? dbSignature = _GetFileSignatureFromDatabase(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||
|
||||
if (dbSignature != null)
|
||||
// begin signature search
|
||||
switch (Config.MetadataConfiguration.SignatureSource)
|
||||
{
|
||||
// local signature found
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature found in local database for game: " + dbSignature.Game.Name);
|
||||
discoveredSignature = dbSignature;
|
||||
case HasheousClient.Models.MetadataModel.SignatureSources.LocalOnly:
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Hasheous disabled - searching local database only");
|
||||
|
||||
discoveredSignature = _GetFileSignatureFromDatabase(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||
|
||||
break;
|
||||
|
||||
case HasheousClient.Models.MetadataModel.SignatureSources.Hasheous:
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Hasheous enabled - searching Hashesous and then local database if not found");
|
||||
|
||||
discoveredSignature = _GetFileSignatureFromHasheous(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||
|
||||
if (discoveredSignature == null)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature not found in Hasheous - checking local database");
|
||||
|
||||
discoveredSignature = _GetFileSignatureFromDatabase(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no local signature attempt to pull from Hasheous
|
||||
dbSignature = _GetFileSignatureFromHasheous(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||
|
||||
if (dbSignature != null)
|
||||
{
|
||||
// signature retrieved from Hasheous
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature retrieved from Hasheous for game: " + dbSignature.Game.Name);
|
||||
|
||||
discoveredSignature = dbSignature;
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature retrieved from Hasheous for game: " + discoveredSignature.Game.Name);
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (discoveredSignature == null)
|
||||
{
|
||||
// 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);
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature not found in local database or Hasheous (if enabled) - generating from file data");
|
||||
|
||||
discoveredSignature = dbSignature;
|
||||
}
|
||||
discoveredSignature = _GetFileSignatureFromFileData(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature generated from provided file for game: " + discoveredSignature.Game.Name);
|
||||
}
|
||||
|
||||
gaseous_server.Models.PlatformMapping.GetIGDBPlatformMapping(ref discoveredSignature, ImageExtension, false);
|
||||
@@ -265,11 +290,11 @@ namespace gaseous_server.Classes
|
||||
if (Config.MetadataConfiguration.SignatureSource == HasheousClient.Models.MetadataModel.SignatureSources.Hasheous)
|
||||
{
|
||||
HasheousClient.Hasheous hasheous = new HasheousClient.Hasheous();
|
||||
SignatureLookupItem? HasheousResult = null;
|
||||
|
||||
Console.WriteLine(HasheousClient.WebApp.HttpHelper.BaseUri);
|
||||
LookupItemModel? HasheousResult = null;
|
||||
try
|
||||
{
|
||||
HasheousResult = hasheous.RetrieveFromHasheousAsync(new HashLookupModel
|
||||
HasheousResult = hasheous.RetrieveFromHasheous(new HashLookupModel
|
||||
{
|
||||
MD5 = hash.md5hash,
|
||||
SHA1 = hash.sha1hash
|
||||
@@ -280,19 +305,46 @@ namespace gaseous_server.Classes
|
||||
if (HasheousResult.Signature != null)
|
||||
{
|
||||
gaseous_server.Models.Signatures_Games signature = new Models.Signatures_Games();
|
||||
signature.Game = HasheousResult.Signature.Game;
|
||||
signature.Rom = HasheousResult.Signature.Rom;
|
||||
string gameJson = Newtonsoft.Json.JsonConvert.SerializeObject(HasheousResult.Signature.Game);
|
||||
string romJson = Newtonsoft.Json.JsonConvert.SerializeObject(HasheousResult.Signature.Rom);
|
||||
signature.Game = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.Signatures_Games.GameItem>(gameJson);
|
||||
signature.Rom = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.Signatures_Games.RomItem>(romJson);
|
||||
|
||||
if (HasheousResult.MetadataResults != null)
|
||||
// get platform metadata
|
||||
if (HasheousResult.Platform != null)
|
||||
{
|
||||
if (HasheousResult.MetadataResults.Count > 0)
|
||||
if (HasheousResult.Platform.metadata.Count > 0)
|
||||
{
|
||||
foreach (SignatureLookupItem.MetadataResult metadataResult in HasheousResult.MetadataResults)
|
||||
foreach (HasheousClient.Models.MetadataItem metadataResult in HasheousResult.Platform.metadata)
|
||||
{
|
||||
if (metadataResult.Source == MetadataModel.MetadataSources.IGDB)
|
||||
if (metadataResult.Id.Length > 0)
|
||||
{
|
||||
signature.Flags.IGDBPlatformId = (long)metadataResult.PlatformId;
|
||||
signature.Flags.IGDBGameId = (long)metadataResult.GameId;
|
||||
switch (metadataResult.Source)
|
||||
{
|
||||
case HasheousClient.Models.MetadataSources.IGDB:
|
||||
signature.Flags.IGDBPlatformId = (long)Platforms.GetPlatform(metadataResult.Id, false).Id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get game metadata
|
||||
if (HasheousResult.Metadata != null)
|
||||
{
|
||||
if (HasheousResult.Metadata.Count > 0)
|
||||
{
|
||||
foreach (HasheousClient.Models.MetadataItem metadataResult in HasheousResult.Metadata)
|
||||
{
|
||||
if (metadataResult.Id.Length > 0)
|
||||
{
|
||||
switch (metadataResult.Source)
|
||||
{
|
||||
case HasheousClient.Models.MetadataSources.IGDB:
|
||||
signature.Flags.IGDBGameId = (long)Games.GetGame(metadataResult.Id, false, false, false).Id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,6 +354,29 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (AggregateException aggEx)
|
||||
{
|
||||
foreach (Exception ex in aggEx.InnerExceptions)
|
||||
{
|
||||
// get exception type
|
||||
if (ex is HttpRequestException)
|
||||
{
|
||||
if (ex.Message.Contains("404 (Not Found)"))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Get Signature", "No signature found in Hasheous");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous", ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous", ex);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous", ex);
|
||||
@@ -379,6 +454,7 @@ namespace gaseous_server.Classes
|
||||
public long Size { get; set; }
|
||||
public string MD5 { get; set; }
|
||||
public string SHA1 { get; set; }
|
||||
public bool isSignatureSelector { get; set; } = false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -26,7 +26,7 @@ namespace gaseous_server.Classes
|
||||
|
||||
string sql = "SELECT Platform.Id, Platform.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, Games_Roms.PlatformId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + ageRestriction_Platform + ") GROUP BY Game.Id , Games_Roms.PlatformId HAVING RomCount > 0) Game JOIN Platform ON Game.PlatformId = Platform.Id GROUP BY Platform.`Name`;";
|
||||
|
||||
DataTable dbResponse = db.ExecuteCMD(sql);
|
||||
DataTable dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));
|
||||
|
||||
foreach (DataRow dr in dbResponse.Rows)
|
||||
{
|
||||
@@ -83,7 +83,7 @@ namespace gaseous_server.Classes
|
||||
// age groups
|
||||
List<FilterItem> agegroupings = new List<FilterItem>();
|
||||
sql = "SELECT Game.AgeGroupId, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, AgeGroup.AgeGroupId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + ageRestriction_Platform + ") GROUP BY Game.Id HAVING RomCount > 0) Game GROUP BY Game.AgeGroupId ORDER BY Game.AgeGroupId DESC";
|
||||
dbResponse = db.ExecuteCMD(sql);
|
||||
dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));
|
||||
|
||||
foreach (DataRow dr in dbResponse.Rows)
|
||||
{
|
||||
@@ -114,7 +114,7 @@ namespace gaseous_server.Classes
|
||||
|
||||
string sql = "SELECT <ITEMNAME>.Id, <ITEMNAME>.`Name`, COUNT(Game.Id) AS GameCount FROM (SELECT DISTINCT Game.Id, AgeGroup.AgeGroupId, COUNT(Games_Roms.Id) AS RomCount FROM Game LEFT JOIN AgeGroup ON Game.Id = AgeGroup.GameId LEFT JOIN Games_Roms ON Game.Id = Games_Roms.GameId WHERE (" + AgeRestriction + ") GROUP BY Game.Id HAVING RomCount > 0) Game JOIN Relation_Game_<ITEMNAME>s ON Game.Id = Relation_Game_<ITEMNAME>s.GameId JOIN <ITEMNAME> ON Relation_Game_<ITEMNAME>s.<ITEMNAME>sId = <ITEMNAME>.Id GROUP BY <ITEMNAME>.`Name` ORDER BY <ITEMNAME>.`Name`;";
|
||||
sql = sql.Replace("<ITEMNAME>", Name);
|
||||
DataTable dbResponse = db.ExecuteCMD(sql);
|
||||
DataTable dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));
|
||||
|
||||
return dbResponse;
|
||||
}
|
||||
|
@@ -13,31 +13,31 @@ namespace gaseous_server
|
||||
public class PathExists : Exception
|
||||
{
|
||||
public PathExists(string path) : base("The library path " + path + " already exists.")
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
public class PathNotFound : Exception
|
||||
{
|
||||
public PathNotFound(string path) : base("The path " + path + " does not exist.")
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
public class LibraryNotFound : Exception
|
||||
{
|
||||
public LibraryNotFound(int LibraryId) : base("Library id " + LibraryId + " does not exist.")
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
public class CannotDeleteDefaultLibrary : Exception
|
||||
{
|
||||
public CannotDeleteDefaultLibrary() : base("Unable to delete the default library.")
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
public class CannotDeleteLibraryWhileScanIsActive : Exception
|
||||
{
|
||||
public CannotDeleteLibraryWhileScanIsActive() : base("Unable to delete library while a library scan is active. Wait for all scans to complete and try again")
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
// code
|
||||
@@ -66,7 +66,7 @@ namespace gaseous_server
|
||||
{
|
||||
List<LibraryItem> libraryItems = new List<LibraryItem>();
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM GameLibraries";
|
||||
string sql = "SELECT * FROM GameLibraries ORDER BY `Name`;";
|
||||
DataTable data = db.ExecuteCMD(sql);
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
@@ -129,7 +129,7 @@ namespace gaseous_server
|
||||
if (library.IsDefaultLibrary == false)
|
||||
{
|
||||
// check for active library scans
|
||||
foreach(ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||
{
|
||||
if (
|
||||
(item.ItemType == ProcessQueue.QueueItemType.LibraryScan && item.ItemState == ProcessQueue.QueueItemState.Running) ||
|
||||
@@ -175,6 +175,24 @@ namespace gaseous_server
|
||||
}
|
||||
}
|
||||
|
||||
public static LibraryItem ScanLibrary(int LibraryId)
|
||||
{
|
||||
// add the library to scan to the queue
|
||||
LibraryItem library = GetLibrary(LibraryId);
|
||||
ImportGame.LibrariesToScan.Add(library);
|
||||
|
||||
// start the library scan if it's not already running
|
||||
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||
{
|
||||
if (item.ItemType == ProcessQueue.QueueItemType.LibraryScan && item.ItemState != ProcessQueue.QueueItemState.Running)
|
||||
{
|
||||
item.ForceExecute();
|
||||
}
|
||||
}
|
||||
|
||||
return library;
|
||||
}
|
||||
|
||||
public class LibraryItem
|
||||
{
|
||||
public LibraryItem(int Id, string Name, string Path, long DefaultPlatformId, bool IsDefaultLibrary)
|
||||
|
@@ -47,8 +47,11 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public void ImportGameFile(string GameFileImportPath, IGDB.Models.Platform? OverridePlatform)
|
||||
public Dictionary<string, object> ImportGameFile(string GameFileImportPath, IGDB.Models.Platform? OverridePlatform)
|
||||
{
|
||||
Dictionary<string, object> RetVal = new Dictionary<string, object>();
|
||||
RetVal.Add("path", Path.GetFileName(GameFileImportPath));
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
@@ -67,6 +70,8 @@ namespace gaseous_server.Classes
|
||||
if (IsBios == null)
|
||||
{
|
||||
// file is a rom
|
||||
RetVal.Add("type", "rom");
|
||||
|
||||
// check to make sure we don't already have this file imported
|
||||
sql = "SELECT COUNT(Id) AS count FROM Games_Roms WHERE MD5=@md5 AND SHA1=@sha1";
|
||||
dbDict.Add("md5", hash.md5hash);
|
||||
@@ -94,6 +99,8 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Import Game", " " + GameFileImportPath + " already in database - skipping import");
|
||||
}
|
||||
|
||||
RetVal.Add("status", "duplicate");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -122,17 +129,27 @@ namespace gaseous_server.Classes
|
||||
IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature, discoveredSignature.Flags.IGDBPlatformId, true);
|
||||
|
||||
// add to database
|
||||
StoreROM(GameLibrary.GetDefaultLibrary, hash, determinedGame, determinedPlatform, discoveredSignature, GameFileImportPath);
|
||||
long RomId = StoreROM(GameLibrary.GetDefaultLibrary, hash, determinedGame, determinedPlatform, discoveredSignature, GameFileImportPath);
|
||||
|
||||
// build return value
|
||||
RetVal.Add("romid", RomId);
|
||||
RetVal.Add("platform", determinedPlatform);
|
||||
RetVal.Add("game", determinedGame);
|
||||
RetVal.Add("signature", discoveredSignature);
|
||||
RetVal.Add("status", "imported");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// file is a bios
|
||||
if (IsBios.WebEmulator != null)
|
||||
{
|
||||
RetVal.Add("type", "bios");
|
||||
RetVal.Add("status", "notimported");
|
||||
|
||||
foreach (Classes.Bios.BiosItem biosItem in Classes.Bios.GetBios())
|
||||
{
|
||||
if (biosItem.Available == false && biosItem.hash == hash.md5hash)
|
||||
if (biosItem.Available == false)
|
||||
{
|
||||
if (biosItem.hash == hash.md5hash)
|
||||
{
|
||||
string biosPath = biosItem.biosPath.Replace(biosItem.filename, "");
|
||||
if (!Directory.Exists(biosPath))
|
||||
@@ -142,12 +159,26 @@ namespace gaseous_server.Classes
|
||||
|
||||
File.Move(GameFileImportPath, biosItem.biosPath, true);
|
||||
|
||||
break;
|
||||
RetVal.Add("name", biosItem.filename);
|
||||
RetVal.Add("platform", Platforms.GetPlatform(biosItem.platformid, false, false));
|
||||
RetVal["status"] = "imported";
|
||||
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (biosItem.hash == hash.md5hash)
|
||||
{
|
||||
RetVal["status"] = "duplicate";
|
||||
return RetVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
public static IGDB.Models.Game SearchForGame(gaseous_server.Models.Signatures_Games Signature, long PlatformId, bool FullDownload)
|
||||
@@ -308,11 +339,11 @@ 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);";
|
||||
sql = "INSERT INTO Games_Roms (PlatformId, GameId, Name, Size, CRC, MD5, SHA1, DevelopmentStatus, Attributes, RomType, RomTypeMedia, MediaLabel, Path, MetadataSource, MetadataGameName, MetadataVersion, LibraryId, RomDataVersion) VALUES (@platformid, @gameid, @name, @size, @crc, @md5, @sha1, @developmentstatus, @Attributes, @romtype, @romtypemedia, @medialabel, @path, @metadatasource, @metadatagamename, @metadataversion, @libraryid, @romdataversion); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
}
|
||||
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;";
|
||||
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, RomDataVersion=@romdataversion WHERE Id=@id;";
|
||||
dbDict.Add("id", UpdateId);
|
||||
}
|
||||
dbDict.Add("platformid", Common.ReturnValueIfNull(determinedPlatform.Id, 0));
|
||||
@@ -327,6 +358,7 @@ namespace gaseous_server.Classes
|
||||
dbDict.Add("metadatagamename", discoveredSignature.Game.Name);
|
||||
dbDict.Add("metadataversion", 2);
|
||||
dbDict.Add("libraryid", library.Id);
|
||||
dbDict.Add("romdataversion", 2);
|
||||
|
||||
if (discoveredSignature.Rom.Attributes != null)
|
||||
{
|
||||
@@ -491,22 +523,40 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public void LibraryScan(GameLibrary.LibraryItem? singleLibrary = null)
|
||||
public static List<GameLibrary.LibraryItem> LibrariesToScan = new List<GameLibrary.LibraryItem>();
|
||||
public void LibraryScan()
|
||||
{
|
||||
int maxWorkers = Config.MetadataConfiguration.MaxLibraryScanWorkers;
|
||||
|
||||
List<GameLibrary.LibraryItem> libraries = new List<GameLibrary.LibraryItem>();
|
||||
if (singleLibrary == null)
|
||||
if (LibrariesToScan.Count == 0)
|
||||
{
|
||||
libraries.AddRange(GameLibrary.GetLibraries);
|
||||
}
|
||||
else
|
||||
{
|
||||
libraries.Add(singleLibrary);
|
||||
LibrariesToScan.AddRange(GameLibrary.GetLibraries);
|
||||
}
|
||||
|
||||
// setup background tasks for each library
|
||||
foreach (GameLibrary.LibraryItem library in libraries)
|
||||
do
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Library scan queue size: " + LibrariesToScan.Count);
|
||||
|
||||
GameLibrary.LibraryItem library = LibrariesToScan[0];
|
||||
LibrariesToScan.RemoveAt(0);
|
||||
|
||||
// check if library is already being scanned
|
||||
bool libraryAlreadyScanning = false;
|
||||
List<ProcessQueue.QueueItem> ProcessQueueItems = new List<ProcessQueue.QueueItem>();
|
||||
ProcessQueueItems.AddRange(ProcessQueue.QueueItems);
|
||||
foreach (ProcessQueue.QueueItem item in ProcessQueueItems)
|
||||
{
|
||||
if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker)
|
||||
{
|
||||
if (((GameLibrary.LibraryItem)item.Options).Id == library.Id)
|
||||
{
|
||||
libraryAlreadyScanning = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (libraryAlreadyScanning == false)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Starting worker process for library " + library.Name);
|
||||
ProcessQueue.QueueItem queue = new ProcessQueue.QueueItem(
|
||||
@@ -518,8 +568,10 @@ namespace gaseous_server.Classes
|
||||
ProcessQueue.QueueItemType.Rematcher
|
||||
},
|
||||
false,
|
||||
true);
|
||||
queue.Options = library;
|
||||
true)
|
||||
{
|
||||
Options = library
|
||||
};
|
||||
queue.ForceExecute();
|
||||
|
||||
ProcessQueue.QueueItems.Add(queue);
|
||||
@@ -530,9 +582,9 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
allowContinue = true;
|
||||
int currentWorkerCount = 0;
|
||||
List<ProcessQueue.QueueItem> queueItems = new List<ProcessQueue.QueueItem>();
|
||||
queueItems.AddRange(ProcessQueue.QueueItems);
|
||||
foreach (ProcessQueue.QueueItem item in queueItems)
|
||||
List<ProcessQueue.QueueItem> LibraryScan_QueueItems = new List<ProcessQueue.QueueItem>();
|
||||
LibraryScan_QueueItems.AddRange(ProcessQueue.QueueItems);
|
||||
foreach (ProcessQueue.QueueItem item in LibraryScan_QueueItems)
|
||||
{
|
||||
if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker)
|
||||
{
|
||||
@@ -546,6 +598,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
} while (allowContinue == false);
|
||||
}
|
||||
} while (LibrariesToScan.Count > 0);
|
||||
|
||||
bool WorkersStillWorking;
|
||||
do
|
||||
@@ -565,6 +618,12 @@ namespace gaseous_server.Classes
|
||||
} while (WorkersStillWorking == true);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Library scan complete. All workers stopped");
|
||||
|
||||
if (LibrariesToScan.Count > 0)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Library Scan", "There are still libraries to scan. Restarting scan process");
|
||||
LibraryScan();
|
||||
}
|
||||
}
|
||||
|
||||
public void LibrarySpecificScan(GameLibrary.LibraryItem library)
|
||||
|
@@ -3,6 +3,7 @@ using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages;
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public class Logging
|
||||
@@ -21,8 +22,13 @@ namespace gaseous_server.Classes
|
||||
ExceptionValue = Common.ReturnValueIfNull(ExceptionValue, "").ToString()
|
||||
};
|
||||
|
||||
_ = Task.Run(() => WriteLogAsync(logItem, LogToDiskOnly));
|
||||
}
|
||||
|
||||
static async Task WriteLogAsync(LogItem logItem, bool LogToDiskOnly)
|
||||
{
|
||||
bool AllowWrite = false;
|
||||
if (EventType == LogType.Debug)
|
||||
if (logItem.EventType == LogType.Debug)
|
||||
{
|
||||
if (Config.LoggingConfiguration.DebugLogging == true)
|
||||
{
|
||||
@@ -42,26 +48,32 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
TraceOutput += Environment.NewLine + logItem.ExceptionValue.ToString();
|
||||
}
|
||||
switch(logItem.EventType) {
|
||||
string consoleColour = "";
|
||||
switch (logItem.EventType)
|
||||
{
|
||||
case LogType.Information:
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
// Console.ForegroundColor = ConsoleColor.Blue;
|
||||
consoleColour = "\u001b[1;34m]";
|
||||
break;
|
||||
|
||||
case LogType.Warning:
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
// Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
consoleColour = "\u001b[1;33m]";
|
||||
break;
|
||||
|
||||
case LogType.Critical:
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
// Console.ForegroundColor = ConsoleColor.Red;
|
||||
consoleColour = "\u001b[1;31m]";
|
||||
break;
|
||||
|
||||
case LogType.Debug:
|
||||
Console.ForegroundColor = ConsoleColor.Magenta;
|
||||
// Console.ForegroundColor = ConsoleColor.Magenta;
|
||||
consoleColour = "\u001b[1;36m]";
|
||||
break;
|
||||
|
||||
}
|
||||
Console.WriteLine(TraceOutput);
|
||||
Console.ResetColor();
|
||||
Console.WriteLine(consoleColour + TraceOutput);
|
||||
// Console.ResetColor();
|
||||
|
||||
if (WriteToDiskOnly == true)
|
||||
{
|
||||
|
@@ -37,7 +37,7 @@ namespace gaseous_server.Classes
|
||||
Logging.Log(Logging.LogType.Information, "Maintenance", "Removing logs older than " + Config.LoggingConfiguration.LogRetention + " days");
|
||||
long deletedCount = 1;
|
||||
long deletedEventCount = 0;
|
||||
long maxLoops = 1000;
|
||||
long maxLoops = 10000;
|
||||
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)
|
||||
@@ -46,6 +46,8 @@ namespace gaseous_server.Classes
|
||||
deletedCount = (long)deletedCountTable.Rows[0][0];
|
||||
deletedEventCount += deletedCount;
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Maintenance", "Deleted " + deletedCount + " log entries");
|
||||
|
||||
// check if we've hit the limit
|
||||
maxLoops -= 1;
|
||||
if (maxLoops <= 0)
|
||||
|
@@ -216,44 +216,48 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
readonly static AgeGroupItem Adult_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_Z },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Eighteen },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.RP, AgeRatingTitle.AO },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Eighteen },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Eighteen},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_18}
|
||||
readonly static AgeGroupItem Adult_Item = new AgeGroupItem
|
||||
{
|
||||
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC },
|
||||
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_Z },
|
||||
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Eighteen },
|
||||
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.RP, AgeRatingTitle.AO },
|
||||
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Eighteen },
|
||||
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Eighteen },
|
||||
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_18 }
|
||||
};
|
||||
|
||||
readonly static AgeGroupItem Mature_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_M, AgeRatingTitle.ACB_MA15 },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_C, AgeRatingTitle.CERO_D },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Sixteen },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.M },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Fifteen },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Sixteen},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_16}
|
||||
readonly static AgeGroupItem Mature_Item = new AgeGroupItem
|
||||
{
|
||||
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_M, AgeRatingTitle.ACB_MA15 },
|
||||
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_C, AgeRatingTitle.CERO_D },
|
||||
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Sixteen },
|
||||
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.M },
|
||||
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Fifteen },
|
||||
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Sixteen },
|
||||
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_16 }
|
||||
};
|
||||
|
||||
readonly static AgeGroupItem Teen_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_PG },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_B },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Twelve, AgeRatingTitle.CLASS_IND_Fourteen },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.T },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Twelve },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Twelve},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_12}
|
||||
readonly static AgeGroupItem Teen_Item = new AgeGroupItem
|
||||
{
|
||||
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_PG },
|
||||
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_B },
|
||||
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Twelve, AgeRatingTitle.CLASS_IND_Fourteen },
|
||||
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.T },
|
||||
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Twelve },
|
||||
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Twelve },
|
||||
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_12 }
|
||||
};
|
||||
|
||||
readonly static AgeGroupItem Child_Item = new AgeGroupItem{
|
||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_G },
|
||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_A },
|
||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_L, AgeRatingTitle.CLASS_IND_Ten },
|
||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.E, AgeRatingTitle.E10 },
|
||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_All },
|
||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Three, AgeRatingTitle.Seven},
|
||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_0, AgeRatingTitle.USK_6}
|
||||
readonly static AgeGroupItem Child_Item = new AgeGroupItem
|
||||
{
|
||||
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_G },
|
||||
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_A },
|
||||
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_L, AgeRatingTitle.CLASS_IND_Ten },
|
||||
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.EC, AgeRatingTitle.E, AgeRatingTitle.E10 },
|
||||
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_All },
|
||||
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Three, AgeRatingTitle.Seven },
|
||||
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_0, AgeRatingTitle.USK_6 }
|
||||
};
|
||||
|
||||
public class AgeGroupItem
|
||||
|
@@ -74,8 +74,14 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
|
||||
// check if old value is different from the new value - only download if it's different
|
||||
Artwork oldImage = Storage.GetCacheValue<Artwork>(returnValue, "id", (long)searchValue);
|
||||
if (oldImage.ImageId != returnValue.ImageId)
|
||||
{
|
||||
forceImageDownload = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
|
@@ -195,6 +195,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
if (InRateLimitAvoidanceMode == true)
|
||||
{
|
||||
// sleep for a moment to help avoid hitting the rate limiter
|
||||
Logging.Log(Logging.LogType.Information, "API Connection: Endpoint:" + Endpoint, "IGDB rate limit hit. Pausing API communications for " + RateLimitAvoidanceWait + " milliseconds to avoid rate limiter.");
|
||||
Thread.Sleep(RateLimitAvoidanceWait);
|
||||
}
|
||||
|
||||
@@ -245,7 +246,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "API Connection", "Exception when accessing endpoint " + Endpoint, ex);
|
||||
throw;
|
||||
@@ -393,6 +394,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
if (InRateLimitAvoidanceMode == true)
|
||||
{
|
||||
// sleep for a moment to help avoid hitting the rate limiter
|
||||
Logging.Log(Logging.LogType.Information, "API Connection: Fetch Image", "IGDB rate limit hit. Pausing API communications for " + RateLimitAvoidanceWait + " milliseconds to avoid rate limiter.");
|
||||
Thread.Sleep(RateLimitAvoidanceWait);
|
||||
}
|
||||
|
||||
|
@@ -76,8 +76,14 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
|
||||
// check if old value is different from the new value - only download if it's different
|
||||
CompanyLogo oldImage = Storage.GetCacheValue<CompanyLogo>(returnValue, "id", (long)searchValue);
|
||||
if (oldImage.ImageId != returnValue.ImageId)
|
||||
{
|
||||
forceImageDownload = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
|
@@ -76,8 +76,14 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
|
||||
// check if old value is different from the new value - only download if it's different
|
||||
Cover oldCover = Storage.GetCacheValue<Cover>(returnValue, "id", (long)searchValue);
|
||||
if (oldCover.ImageId != returnValue.ImageId)
|
||||
{
|
||||
forceImageDownload = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using gaseous_server.Models;
|
||||
using IGDB;
|
||||
using IGDB.Models;
|
||||
|
||||
@@ -7,7 +8,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
public class Games
|
||||
{
|
||||
const string fieldList = "fields age_ratings,aggregated_rating,aggregated_rating_count,alternative_names,artworks,bundles,category,checksum,collection,collections,cover,created_at,dlcs,expanded_games,expansions,external_games,first_release_date,follows,forks,franchise,franchises,game_engines,game_localizations,game_modes,genres,hypes,involved_companies,keywords,language_supports,multiplayer_modes,name,parent_game,platforms,player_perspectives,ports,rating,rating_count,release_dates,remakes,remasters,screenshots,similar_games,slug,standalone_expansions,status,storyline,summary,tags,themes,total_rating,total_rating_count,updated_at,url,version_parent,version_title,videos,websites;";
|
||||
const string fieldList = "fields age_ratings,aggregated_rating,aggregated_rating_count,alternative_names,artworks,bundles,category,checksum,collections,cover,created_at,dlcs,expanded_games,expansions,external_games,first_release_date,follows,forks,franchise,franchises,game_engines,game_localizations,game_modes,genres,hypes,involved_companies,keywords,language_supports,multiplayer_modes,name,parent_game,platforms,player_perspectives,ports,rating,rating_count,release_dates,remakes,remasters,screenshots,similar_games,slug,standalone_expansions,status,storyline,summary,tags,themes,total_rating,total_rating_count,updated_at,url,version_parent,version_title,videos,websites;";
|
||||
|
||||
public Games()
|
||||
{
|
||||
@@ -504,24 +505,155 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
public static List<KeyValuePair<long, string>> GetAvailablePlatforms(long GameId)
|
||||
public static List<AvailablePlatformItem> GetAvailablePlatforms(string UserId, long GameId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT DISTINCT Games_Roms.PlatformId, Platform.`Name` FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.GameId = @gameid ORDER BY Platform.`Name`;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("gameid", GameId);
|
||||
string sql = @"
|
||||
SELECT DISTINCT
|
||||
Games_Roms.GameId,
|
||||
Games_Roms.PlatformId,
|
||||
Platform.`Name`,
|
||||
User_RecentPlayedRoms.UserId AS MostRecentUserId,
|
||||
User_RecentPlayedRoms.RomId AS MostRecentRomId,
|
||||
CASE User_RecentPlayedRoms.IsMediaGroup
|
||||
WHEN 0 THEN GMR.`Name`
|
||||
WHEN 1 THEN 'Media Group'
|
||||
ELSE NULL
|
||||
END AS `MostRecentRomName`,
|
||||
User_RecentPlayedRoms.IsMediaGroup AS MostRecentRomIsMediaGroup,
|
||||
User_GameFavouriteRoms.UserId AS FavouriteUserId,
|
||||
User_GameFavouriteRoms.RomId AS FavouriteRomId,
|
||||
CASE User_GameFavouriteRoms.IsMediaGroup
|
||||
WHEN 0 THEN GFV.`Name`
|
||||
WHEN 1 THEN 'Media Group'
|
||||
ELSE NULL
|
||||
END AS `FavouriteRomName`,
|
||||
User_GameFavouriteRoms.IsMediaGroup AS FavouriteRomIsMediaGroup
|
||||
FROM
|
||||
Games_Roms
|
||||
LEFT JOIN
|
||||
Platform ON Games_Roms.PlatformId = Platform.Id
|
||||
LEFT JOIN
|
||||
User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid
|
||||
AND User_RecentPlayedRoms.GameId = Games_Roms.GameId
|
||||
AND User_RecentPlayedRoms.PlatformId = Games_Roms.PlatformId
|
||||
LEFT JOIN
|
||||
User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid
|
||||
AND User_GameFavouriteRoms.GameId = Games_Roms.GameId
|
||||
AND User_GameFavouriteRoms.PlatformId = Games_Roms.PlatformId
|
||||
LEFT JOIN
|
||||
Games_Roms AS GMR ON GMR.Id = User_RecentPlayedRoms.RomId
|
||||
LEFT JOIN
|
||||
Games_Roms AS GFV ON GFV.Id = User_GameFavouriteRoms.RomId
|
||||
WHERE
|
||||
Games_Roms.GameId = @gameid
|
||||
ORDER BY Platform.`Name`;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "gameid", GameId },
|
||||
{ "userid", UserId }
|
||||
};
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
List<KeyValuePair<long, string>> platforms = new List<KeyValuePair<long, string>>();
|
||||
PlatformMapping platformMapping = new PlatformMapping();
|
||||
List<AvailablePlatformItem> platforms = new List<AvailablePlatformItem>();
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
KeyValuePair<long, string> valuePair = new KeyValuePair<long, string>((long)row["PlatformId"], (string)row["Name"]);
|
||||
IGDB.Models.Platform platform = Platforms.GetPlatform((long)row["PlatformId"]);
|
||||
PlatformMapping.UserEmulatorConfiguration? emulatorConfiguration = platformMapping.GetUserEmulator(UserId, GameId, (long)platform.Id);
|
||||
|
||||
if (emulatorConfiguration == null)
|
||||
{
|
||||
if (platform.Id != 0)
|
||||
{
|
||||
Models.PlatformMapping.PlatformMapItem platformMap = PlatformMapping.GetPlatformMap((long)platform.Id);
|
||||
emulatorConfiguration = new PlatformMapping.UserEmulatorConfiguration
|
||||
{
|
||||
EmulatorType = platformMap.WebEmulator.Type,
|
||||
Core = platformMap.WebEmulator.Core,
|
||||
EnableBIOSFiles = platformMap.EnabledBIOSHashes
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
long? LastPlayedRomId = null;
|
||||
bool? LastPlayedIsMediagroup = false;
|
||||
string? LastPlayedRomName = null;
|
||||
if (row["MostRecentRomId"] != DBNull.Value)
|
||||
{
|
||||
LastPlayedRomId = (long?)row["MostRecentRomId"];
|
||||
LastPlayedIsMediagroup = (bool)row["MostRecentRomIsMediaGroup"];
|
||||
LastPlayedRomName = (string)row["MostRecentRomName"];
|
||||
}
|
||||
|
||||
long? FavouriteRomId = null;
|
||||
bool? FavouriteRomIsMediagroup = false;
|
||||
string? FavouriteRomName = null;
|
||||
if (row["FavouriteRomId"] != DBNull.Value)
|
||||
{
|
||||
FavouriteRomId = (long?)row["FavouriteRomId"];
|
||||
FavouriteRomIsMediagroup = (bool)row["FavouriteRomIsMediaGroup"];
|
||||
FavouriteRomName = (string)row["FavouriteRomName"];
|
||||
}
|
||||
|
||||
AvailablePlatformItem valuePair = new AvailablePlatformItem
|
||||
{
|
||||
Id = platform.Id,
|
||||
Name = platform.Name,
|
||||
Category = platform.Category,
|
||||
emulatorConfiguration = emulatorConfiguration,
|
||||
LastPlayedRomId = LastPlayedRomId,
|
||||
LastPlayedRomIsMediagroup = LastPlayedIsMediagroup,
|
||||
LastPlayedRomName = LastPlayedRomName,
|
||||
FavouriteRomId = FavouriteRomId,
|
||||
FavouriteRomIsMediagroup = FavouriteRomIsMediagroup,
|
||||
FavouriteRomName = FavouriteRomName
|
||||
};
|
||||
platforms.Add(valuePair);
|
||||
}
|
||||
|
||||
return platforms;
|
||||
}
|
||||
|
||||
public static void GameSetFavouriteRom(string UserId, long GameId, long PlatformId, long RomId, bool IsMediaGroup)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "DELETE FROM User_GameFavouriteRoms WHERE UserId = @userid AND GameId = @gameid AND PlatformId = @platformid; INSERT INTO User_GameFavouriteRoms (UserId, GameId, PlatformId, RomId, IsMediaGroup) VALUES (@userid, @gameid, @platformid, @romid, @ismediagroup);";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "userid", UserId },
|
||||
{ "gameid", GameId },
|
||||
{ "platformid", PlatformId },
|
||||
{ "romid", RomId },
|
||||
{ "ismediagroup", IsMediaGroup }
|
||||
};
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
|
||||
public static void GameClearFavouriteRom(string UserId, long GameId, long PlatformId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "DELETE FROM User_GameFavouriteRoms WHERE UserId = @userid AND GameId = @gameid AND PlatformId = @platformid;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "userid", UserId },
|
||||
{ "gameid", GameId },
|
||||
{ "platformid", PlatformId }
|
||||
};
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
|
||||
public class AvailablePlatformItem : IGDB.Models.Platform
|
||||
{
|
||||
public PlatformMapping.UserEmulatorConfiguration emulatorConfiguration { get; set; }
|
||||
public long? LastPlayedRomId { get; set; }
|
||||
public bool? LastPlayedRomIsMediagroup { get; set; }
|
||||
public string? LastPlayedRomName { get; set; }
|
||||
public long? FavouriteRomId { get; set; }
|
||||
public bool? FavouriteRomIsMediagroup { get; set; }
|
||||
public string? FavouriteRomName { get; set; }
|
||||
}
|
||||
|
||||
public enum SearchType
|
||||
{
|
||||
where = 0,
|
||||
@@ -542,6 +674,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
this.Id = gameObject.Id;
|
||||
this.Name = gameObject.Name;
|
||||
this.Slug = gameObject.Slug;
|
||||
this.Summary = gameObject.Summary;
|
||||
this.TotalRating = gameObject.TotalRating;
|
||||
this.TotalRatingCount = gameObject.TotalRatingCount;
|
||||
this.Cover = gameObject.Cover;
|
||||
@@ -567,6 +700,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
public long Index { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public string Summary { get; set; }
|
||||
public double? TotalRating { get; set; }
|
||||
public int? TotalRatingCount { get; set; }
|
||||
public bool HasSavedGame { get; set; } = false;
|
||||
|
@@ -76,8 +76,14 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
|
||||
// check if old value is different from the new value - only download if it's different
|
||||
PlatformLogo oldImage = Storage.GetCacheValue<PlatformLogo>(returnValue, "id", (long)searchValue);
|
||||
if (oldImage.ImageId != returnValue.ImageId)
|
||||
{
|
||||
forceImageDownload = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
|
@@ -26,7 +26,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
public static PlatformVersion GetPlatformVersion(string Slug, Platform ParentPlatform, bool GetImages)
|
||||
public static PlatformVersion GetPlatformVersion(string Slug, Platform ParentPlatform, bool GetImages = false)
|
||||
{
|
||||
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.slug, Slug, ParentPlatform, GetImages);
|
||||
return RetVal.Result;
|
||||
|
@@ -74,8 +74,14 @@ namespace gaseous_server.Classes.Metadata
|
||||
{
|
||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||
Storage.NewCacheValue(returnValue, true);
|
||||
|
||||
// check if old value is different from the new value - only download if it's different
|
||||
Screenshot oldImage = Storage.GetCacheValue<Screenshot>(returnValue, "id", (long)searchValue);
|
||||
if (oldImage.ImageId != returnValue.ImageId)
|
||||
{
|
||||
forceImageDownload = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||
|
@@ -175,7 +175,7 @@ namespace gaseous_server.Classes.Metadata
|
||||
dbDict.Add("Endpoint", Endpoint);
|
||||
dbDict.Add(SearchField, SearchValue);
|
||||
|
||||
DataTable dt = db.ExecuteCMD(sql, dbDict);
|
||||
DataTable dt = db.ExecuteCMD(sql, dbDict, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromHours(8).Ticks));
|
||||
if (dt.Rows.Count == 0)
|
||||
{
|
||||
// no data stored for this item
|
||||
|
@@ -16,7 +16,7 @@ namespace gaseous_server.Classes
|
||||
public class InvalidMediaGroupId : Exception
|
||||
{
|
||||
public InvalidMediaGroupId(long Id) : base("Unable to find media group by id " + Id)
|
||||
{}
|
||||
{ }
|
||||
}
|
||||
|
||||
public static GameRomMediaGroupItem CreateMediaGroup(long GameId, long PlatformId, List<long> RomIds)
|
||||
@@ -81,14 +81,42 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
public static List<GameRomMediaGroupItem> GetMediaGroupsFromGameId(long GameId, string userid = "")
|
||||
public static List<GameRomMediaGroupItem> GetMediaGroupsFromGameId(long GameId, string userid = "", long? PlatformId = null)
|
||||
{
|
||||
string PlatformWhereClause = "";
|
||||
if (PlatformId != null)
|
||||
{
|
||||
PlatformWhereClause = " AND RomMediaGroup.PlatformId=@platformid";
|
||||
}
|
||||
|
||||
string UserFields = "";
|
||||
string UserJoin = "";
|
||||
if (userid.Length > 0)
|
||||
{
|
||||
UserFields = ", User_RecentPlayedRoms.RomId AS MostRecentRomId, User_RecentPlayedRoms.IsMediaGroup AS MostRecentRomIsMediaGroup, User_GameFavouriteRoms.RomId AS FavouriteRomId, User_GameFavouriteRoms.IsMediaGroup AS FavouriteRomIsMediaGroup";
|
||||
UserJoin = @"
|
||||
LEFT JOIN
|
||||
User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid
|
||||
AND User_RecentPlayedRoms.GameId = RomMediaGroup.GameId
|
||||
AND User_RecentPlayedRoms.PlatformId = RomMediaGroup.PlatformId
|
||||
AND User_RecentPlayedRoms.RomId = RomMediaGroup.Id
|
||||
AND User_RecentPlayedRoms.IsMediaGroup = 1
|
||||
LEFT JOIN
|
||||
User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid
|
||||
AND User_GameFavouriteRoms.GameId = RomMediaGroup.GameId
|
||||
AND User_GameFavouriteRoms.PlatformId = RomMediaGroup.PlatformId
|
||||
AND User_GameFavouriteRoms.RomId = RomMediaGroup.Id
|
||||
AND User_GameFavouriteRoms.IsMediaGroup = 1
|
||||
";
|
||||
}
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT DISTINCT RomMediaGroup.*, GameState.RomId AS GameStateRomId FROM gaseous.RomMediaGroup LEFT JOIN GameState ON RomMediaGroup.Id = GameState.RomId AND GameState.IsMediaGroup = 1 AND GameState.UserId = @userid WHERE RomMediaGroup.GameId=@gameid;";
|
||||
string sql = "SELECT DISTINCT RomMediaGroup.*, GameState.RomId AS GameStateRomId" + UserFields + " FROM gaseous.RomMediaGroup LEFT JOIN GameState ON RomMediaGroup.Id = GameState.RomId AND GameState.IsMediaGroup = 1 AND GameState.UserId = @userid " + UserJoin + " WHERE RomMediaGroup.GameId=@gameid" + PlatformWhereClause + ";";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "gameid", GameId },
|
||||
{ "userid", userid }
|
||||
{ "userid", userid },
|
||||
{ "platformid", PlatformId }
|
||||
};
|
||||
|
||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
||||
@@ -165,7 +193,7 @@ namespace gaseous_server.Classes
|
||||
public static void DeleteMediaGroup(long Id)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "DELETE FROM RomMediaGroup WHERE Id=@id; DELETE FROM GameState WHERE RomId=@id AND IsMediaGroup=1;";
|
||||
string sql = "DELETE FROM RomMediaGroup WHERE Id=@id; DELETE FROM GameState WHERE RomId=@id AND IsMediaGroup=1; UPDATE UserTimeTracking SET PlatformId = NULL, IsMediaGroup = NULL, RomId = NULL WHERE RomId=@id AND IsMediaGroup = 1;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", Id);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
@@ -188,14 +216,34 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem();
|
||||
mediaGroupItem.Id = (long)row["Id"];
|
||||
mediaGroupItem.Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"];
|
||||
mediaGroupItem.PlatformId = (long)row["PlatformId"];
|
||||
mediaGroupItem.GameId = (long)row["GameId"];
|
||||
mediaGroupItem.RomIds = new List<long>();
|
||||
mediaGroupItem.Roms = new List<Roms.GameRomItem>();
|
||||
mediaGroupItem.HasSaveStates = hasSaveStates;
|
||||
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem
|
||||
{
|
||||
Id = (long)row["Id"],
|
||||
Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"],
|
||||
PlatformId = (long)row["PlatformId"],
|
||||
GameId = (long)row["GameId"],
|
||||
RomIds = new List<long>(),
|
||||
Roms = new List<Roms.GameRomItem>(),
|
||||
HasSaveStates = hasSaveStates
|
||||
};
|
||||
|
||||
mediaGroupItem.RomUserLastUsed = false;
|
||||
if (row.Table.Columns.Contains("MostRecentRomId"))
|
||||
{
|
||||
if (row["MostRecentRomId"] != DBNull.Value)
|
||||
{
|
||||
mediaGroupItem.RomUserLastUsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
mediaGroupItem.RomUserFavourite = false;
|
||||
if (row.Table.Columns.Contains("FavouriteRomId"))
|
||||
{
|
||||
if (row["FavouriteRomId"] != DBNull.Value)
|
||||
{
|
||||
mediaGroupItem.RomUserFavourite = true;
|
||||
}
|
||||
}
|
||||
|
||||
// get members
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
@@ -216,18 +264,6 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
// check for a web emulator and update the romItem
|
||||
foreach (Models.PlatformMapping.PlatformMapItem platformMapping in Models.PlatformMapping.PlatformMap)
|
||||
{
|
||||
if (platformMapping.IGDBId == mediaGroupItem.PlatformId)
|
||||
{
|
||||
if (platformMapping.WebEmulator != null)
|
||||
{
|
||||
mediaGroupItem.Emulator = platformMapping.WebEmulator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mediaGroupItem;
|
||||
}
|
||||
|
||||
@@ -301,7 +337,7 @@ namespace gaseous_server.Classes
|
||||
if (File.Exists(rom.Path))
|
||||
{
|
||||
string romExt = Path.GetExtension(rom.Path);
|
||||
if (new string[]{ ".zip", ".rar", ".7z" }.Contains(romExt))
|
||||
if (new string[] { ".zip", ".rar", ".7z" }.Contains(romExt))
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Media Group", "Decompressing ROM: " + rom.Name);
|
||||
|
||||
@@ -515,7 +551,8 @@ namespace gaseous_server.Classes
|
||||
public long Id { get; set; }
|
||||
public long GameId { get; set; }
|
||||
public long PlatformId { get; set; }
|
||||
public string Platform {
|
||||
public string Platform
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
@@ -528,12 +565,14 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
}
|
||||
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
||||
public List<long> RomIds { get; set; }
|
||||
public List<Roms.GameRomItem> Roms { get; set; }
|
||||
public bool HasSaveStates { get; set; } = false;
|
||||
public bool RomUserLastUsed { get; set; }
|
||||
public bool RomUserFavourite { get; set; }
|
||||
private GroupBuildStatus _Status { get; set; }
|
||||
public GroupBuildStatus Status {
|
||||
public GroupBuildStatus Status
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_Status == GroupBuildStatus.Completed)
|
||||
@@ -557,7 +596,8 @@ namespace gaseous_server.Classes
|
||||
_Status = value;
|
||||
}
|
||||
}
|
||||
public long? Size {
|
||||
public long? Size
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Status == GroupBuildStatus.Completed)
|
||||
|
@@ -4,6 +4,9 @@ using gaseous_signature_parser.models.RomSignatureObject;
|
||||
using static gaseous_server.Classes.RomMediaGroup;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using IGDB.Models;
|
||||
using static HasheousClient.Models.FixMatchModel;
|
||||
using NuGet.Protocol.Core.Types;
|
||||
using static gaseous_server.Classes.FileSignature;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
@@ -40,13 +43,34 @@ namespace gaseous_server.Classes
|
||||
dbDict.Add("namesearch", '%' + NameSearch + '%');
|
||||
}
|
||||
|
||||
string UserFields = "";
|
||||
string UserJoin = "";
|
||||
if (userid.Length > 0)
|
||||
{
|
||||
UserFields = ", User_RecentPlayedRoms.RomId AS MostRecentRomId, User_RecentPlayedRoms.IsMediaGroup AS MostRecentRomIsMediaGroup, User_GameFavouriteRoms.RomId AS FavouriteRomId, User_GameFavouriteRoms.IsMediaGroup AS FavouriteRomIsMediaGroup";
|
||||
UserJoin = @"
|
||||
LEFT JOIN
|
||||
User_RecentPlayedRoms ON User_RecentPlayedRoms.UserId = @userid
|
||||
AND User_RecentPlayedRoms.GameId = Games_Roms.GameId
|
||||
AND User_RecentPlayedRoms.PlatformId = Games_Roms.PlatformId
|
||||
AND User_RecentPlayedRoms.RomId = Games_Roms.Id
|
||||
AND User_RecentPlayedRoms.IsMediaGroup = 0
|
||||
LEFT JOIN
|
||||
User_GameFavouriteRoms ON User_GameFavouriteRoms.UserId = @userid
|
||||
AND User_GameFavouriteRoms.GameId = Games_Roms.GameId
|
||||
AND User_GameFavouriteRoms.PlatformId = Games_Roms.PlatformId
|
||||
AND User_GameFavouriteRoms.RomId = Games_Roms.Id
|
||||
AND User_GameFavouriteRoms.IsMediaGroup = 0
|
||||
";
|
||||
}
|
||||
|
||||
// platform query
|
||||
sqlPlatform = "SELECT DISTINCT Games_Roms.PlatformId, Platform.`Name` FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE GameId = @id ORDER BY Platform.`Name`;";
|
||||
|
||||
if (PlatformId == -1)
|
||||
{
|
||||
// data query
|
||||
sql = "SELECT DISTINCT Games_Roms.*, Platform.`Name` AS platformname, GameState.RomId AS SavedStateRomId FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) WHERE Games_Roms.GameId = @id" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
||||
sql = "SELECT DISTINCT Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename, GameState.RomId AS SavedStateRomId" + UserFields + " FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.Id LEFT JOIN GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) " + UserJoin + " WHERE Games_Roms.GameId = @id" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
||||
|
||||
// count query
|
||||
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id" + NameSearchWhere + ";";
|
||||
@@ -54,16 +78,15 @@ namespace gaseous_server.Classes
|
||||
else
|
||||
{
|
||||
// data query
|
||||
sql = "SELECT DISTINCT Games_Roms.*, Platform.`Name` AS platformname, GameState.RomId AS SavedStateRomId FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
||||
sql = "SELECT DISTINCT Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename, GameState.RomId AS SavedStateRomId" + UserFields + " FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.Id LEFT JOIN GameState ON (Games_Roms.Id = GameState.RomId AND GameState.UserId = @userid AND GameState.IsMediaGroup = 0) " + UserJoin + " WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
||||
|
||||
// count query
|
||||
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + ";";
|
||||
|
||||
dbDict.Add("platformid", PlatformId);
|
||||
}
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
Dictionary<string, object> rowCount = db.ExecuteCMDDict(sqlCount, dbDict)[0];
|
||||
DataTable platformDT = db.ExecuteCMD(sqlPlatform, dbDict);
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromMinutes(1).Ticks));
|
||||
Dictionary<string, object> rowCount = db.ExecuteCMDDict(sqlCount, dbDict, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromMinutes(1).Ticks))[0];
|
||||
|
||||
if (romDT.Rows.Count > 0)
|
||||
{
|
||||
@@ -73,10 +96,9 @@ namespace gaseous_server.Classes
|
||||
int pageOffset = pageSize * (pageNumber - 1);
|
||||
for (int i = 0; i < romDT.Rows.Count; i++)
|
||||
{
|
||||
GameRomItem gameRomItem = BuildRom(romDT.Rows[i]);
|
||||
|
||||
if ((i >= pageOffset && i < pageOffset + pageSize) || pageSize == 0)
|
||||
{
|
||||
GameRomItem gameRomItem = BuildRom(romDT.Rows[i]);
|
||||
GameRoms.GameRomItems.Add(gameRomItem);
|
||||
}
|
||||
}
|
||||
@@ -92,7 +114,7 @@ namespace gaseous_server.Classes
|
||||
public static GameRomItem GetRom(long RomId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.Id = @id";
|
||||
string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.Id WHERE Games_Roms.Id = @id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", RomId);
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
@@ -112,7 +134,7 @@ namespace gaseous_server.Classes
|
||||
public static GameRomItem GetRom(string MD5)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.MD5 = @id";
|
||||
string sql = "SELECT Games_Roms.*, Platform.`Name` AS platformname, Game.`Name` AS gamename FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id LEFT JOIN Game ON Games_Roms.GameId = Game.Id WHERE Games_Roms.MD5 = @id";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", MD5);
|
||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||
@@ -147,6 +169,53 @@ namespace gaseous_server.Classes
|
||||
|
||||
GameRomItem rom = GetRom(RomId);
|
||||
|
||||
// send update to Hasheous if enabled
|
||||
if (PlatformId != 0 && GameId != 0)
|
||||
{
|
||||
if (Config.MetadataConfiguration.HasheousSubmitFixes == true)
|
||||
{
|
||||
if (
|
||||
Config.MetadataConfiguration.SignatureSource == HasheousClient.Models.MetadataModel.SignatureSources.Hasheous &&
|
||||
(
|
||||
Config.MetadataConfiguration.HasheousAPIKey != null &&
|
||||
Config.MetadataConfiguration.HasheousAPIKey != "")
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
// find signature used for identifing the rom
|
||||
string md5String = rom.Md5;
|
||||
string sha1String = rom.Sha1;
|
||||
if (rom.Attributes.ContainsKey("ZipContents"))
|
||||
{
|
||||
bool selectorFound = false;
|
||||
List<ArchiveData> archiveDataValues = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ArchiveData>>(rom.Attributes["ZipContents"].ToString());
|
||||
foreach (ArchiveData archiveData in archiveDataValues)
|
||||
{
|
||||
if (archiveData.isSignatureSelector == true)
|
||||
{
|
||||
md5String = archiveData.MD5;
|
||||
sha1String = archiveData.SHA1;
|
||||
selectorFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HasheousClient.WebApp.HttpHelper.AddHeader("X-API-Key", Config.MetadataConfiguration.HasheousAPIKey);
|
||||
HasheousClient.Hasheous hasheousClient = new HasheousClient.Hasheous();
|
||||
List<MetadataMatch> metadataMatchList = new List<MetadataMatch>();
|
||||
metadataMatchList.Add(new MetadataMatch(HasheousClient.Models.MetadataSources.IGDB, platform.Slug, game.Slug));
|
||||
hasheousClient.FixMatch(new HasheousClient.Models.FixMatchModel(md5String, sha1String, metadataMatchList));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Fix Match", "An error occurred while sending a fixed match to Hasheous.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rom;
|
||||
}
|
||||
|
||||
@@ -161,7 +230,7 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "DELETE FROM Games_Roms WHERE Id = @id; DELETE FROM GameState WHERE RomId = @id;";
|
||||
string sql = "DELETE FROM Games_Roms WHERE Id = @id; DELETE FROM GameState WHERE RomId = @id; UPDATE UserTimeTracking SET PlatformId = NULL, IsMediaGroup = NULL, RomId = NULL WHERE RomId = @id AND IsMediaGroup = 0;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("id", RomId);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
@@ -179,20 +248,37 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, object> romAttributes = new Dictionary<string, object>();
|
||||
if (romDR["attributes"] != DBNull.Value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ((string)romDR["attributes"] != "[ ]")
|
||||
{
|
||||
romAttributes = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>((string)romDR["attributes"]);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Roms", "Error parsing rom attributes: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
GameRomItem romItem = new GameRomItem
|
||||
{
|
||||
Id = (long)romDR["id"],
|
||||
PlatformId = (long)romDR["platformid"],
|
||||
Platform = (string)romDR["platformname"],
|
||||
GameId = (long)romDR["gameid"],
|
||||
Game = (string)romDR["gamename"],
|
||||
Name = (string)romDR["name"],
|
||||
Size = (long)romDR["size"],
|
||||
Crc = ((string)romDR["crc"]).ToLower(),
|
||||
Md5 = ((string)romDR["md5"]).ToLower(),
|
||||
Sha1 = ((string)romDR["sha1"]).ToLower(),
|
||||
DevelopmentStatus = (string)romDR["developmentstatus"],
|
||||
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<KeyValuePair<string, object>>>((string)Common.ReturnValueIfNull(romDR["attributes"], "[ ]")),
|
||||
RomType = (HasheousClient.Models.LookupResponseModel.RomItem.RomTypes)(int)romDR["romtype"],
|
||||
Attributes = romAttributes,
|
||||
RomType = (HasheousClient.Models.SignatureModel.RomItem.RomTypes)(int)romDR["romtype"],
|
||||
RomTypeMedia = (string)romDR["romtypemedia"],
|
||||
MediaLabel = (string)romDR["medialabel"],
|
||||
Path = (string)romDR["path"],
|
||||
@@ -202,16 +288,22 @@ namespace gaseous_server.Classes
|
||||
Library = GameLibrary.GetLibrary((int)romDR["LibraryId"])
|
||||
};
|
||||
|
||||
// check for a web emulator and update the romItem
|
||||
foreach (Models.PlatformMapping.PlatformMapItem platformMapping in Models.PlatformMapping.PlatformMap)
|
||||
romItem.RomUserLastUsed = false;
|
||||
if (romDR.Table.Columns.Contains("MostRecentRomId"))
|
||||
{
|
||||
if (platformMapping.IGDBId == romItem.PlatformId)
|
||||
if (romDR["MostRecentRomId"] != DBNull.Value)
|
||||
{
|
||||
if (platformMapping.WebEmulator != null)
|
||||
{
|
||||
romItem.Emulator = platformMapping.WebEmulator;
|
||||
romItem.RomUserLastUsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
romItem.RomUserFavourite = false;
|
||||
if (romDR.Table.Columns.Contains("FavouriteRomId"))
|
||||
{
|
||||
if (romDR["FavouriteRomId"] != DBNull.Value)
|
||||
{
|
||||
romItem.RomUserFavourite = true;
|
||||
}
|
||||
}
|
||||
|
||||
return romItem;
|
||||
@@ -223,16 +315,19 @@ namespace gaseous_server.Classes
|
||||
public int Count { get; set; }
|
||||
}
|
||||
|
||||
public class GameRomItem : HasheousClient.Models.LookupResponseModel.RomItem
|
||||
public class GameRomItem : HasheousClient.Models.SignatureModel.RomItem
|
||||
{
|
||||
public long PlatformId { get; set; }
|
||||
public string Platform { get; set; }
|
||||
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
||||
public long GameId { get; set; }
|
||||
public string Game { get; set; }
|
||||
public string? Path { get; set; }
|
||||
public string? SignatureSourceGameTitle { get; set; }
|
||||
public bool HasSaveStates { get; set; } = false;
|
||||
public GameLibrary.LibraryItem Library { get; set; }
|
||||
public bool RomUserLastUsed { get; set; }
|
||||
public bool RomUserFavourite { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,21 +8,49 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
{
|
||||
public class XMLIngestor : QueueItemStatus
|
||||
{
|
||||
public void Import(string SearchPath, gaseous_signature_parser.parser.SignatureParser XMLType)
|
||||
public void Import(string SearchPath, string ProcessedDirectory, gaseous_signature_parser.parser.SignatureParser XMLType)
|
||||
{
|
||||
// connect to database
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
|
||||
string? XMLDBSearchPath = null;
|
||||
string? XMLDBProcessedDirectory = null;
|
||||
if (XMLType == gaseous_signature_parser.parser.SignatureParser.NoIntro)
|
||||
{
|
||||
XMLDBSearchPath = Path.Combine(SearchPath, "DB");
|
||||
XMLDBProcessedDirectory = Path.Combine(ProcessedDirectory, "DB");
|
||||
SearchPath = Path.Combine(SearchPath, "DAT");
|
||||
ProcessedDirectory = Path.Combine(ProcessedDirectory, "DAT");
|
||||
}
|
||||
|
||||
// process provided files
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingestor - XML", "Importing from " + SearchPath);
|
||||
if (!Directory.Exists(SearchPath))
|
||||
{
|
||||
Directory.CreateDirectory(SearchPath);
|
||||
}
|
||||
if (!Directory.Exists(ProcessedDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(ProcessedDirectory);
|
||||
}
|
||||
|
||||
string[] PathContents = Directory.GetFiles(SearchPath);
|
||||
Array.Sort(PathContents);
|
||||
|
||||
string[]? DBPathContents = null;
|
||||
if (XMLDBSearchPath != null)
|
||||
{
|
||||
if (!Directory.Exists(XMLDBSearchPath))
|
||||
{
|
||||
Directory.CreateDirectory(XMLDBSearchPath);
|
||||
}
|
||||
if (!Directory.Exists(XMLDBProcessedDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(XMLDBProcessedDirectory);
|
||||
}
|
||||
|
||||
DBPathContents = Directory.GetFiles(XMLDBSearchPath);
|
||||
}
|
||||
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
System.Data.DataTable sigDB;
|
||||
@@ -33,12 +61,28 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
|
||||
SetStatus(i + 1, PathContents.Length, "Processing signature file: " + XMLFile);
|
||||
|
||||
if (Common.SkippableFiles.Contains(Path.GetFileName(XMLFile), StringComparer.OrdinalIgnoreCase))
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingest", "(" + (i + 1) + " / " + PathContents.Length + ") Processing " + XMLType.ToString() + " DAT file: " + XMLFile);
|
||||
|
||||
string? DBFile = null;
|
||||
if (XMLDBSearchPath != null)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingestor - XML", "Skipping file: " + XMLFile);
|
||||
switch (XMLType)
|
||||
{
|
||||
case gaseous_signature_parser.parser.SignatureParser.NoIntro:
|
||||
for (UInt16 x = 0; x < DBPathContents.Length; x++)
|
||||
{
|
||||
string tempDBFileName = Path.GetFileNameWithoutExtension(DBPathContents[x].Replace(" (DB Export)", ""));
|
||||
if (tempDBFileName == Path.GetFileNameWithoutExtension(XMLFile))
|
||||
{
|
||||
DBFile = DBPathContents[x];
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingest", "Using DB file: " + DBFile);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check xml file md5
|
||||
Common.hashObject hashObject = new Common.hashObject(XMLFile);
|
||||
sql = "SELECT * FROM Signatures_Sources WHERE SourceMD5=@sourcemd5";
|
||||
@@ -50,11 +94,9 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
{
|
||||
try
|
||||
{
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingestor - XML", "Importing file: " + XMLFile);
|
||||
|
||||
// start parsing file
|
||||
gaseous_signature_parser.parser Parser = new gaseous_signature_parser.parser();
|
||||
RomSignatureObject Object = Parser.ParseSignatureDAT(XMLFile, XMLType);
|
||||
RomSignatureObject Object = Parser.ParseSignatureDAT(XMLFile, DBFile, XMLType);
|
||||
|
||||
// store in database
|
||||
string[] flipNameAndDescription = {
|
||||
@@ -66,21 +108,27 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
bool processGames = false;
|
||||
if (Object.SourceMd5 != null)
|
||||
{
|
||||
sql = "SELECT * FROM Signatures_Sources WHERE SourceMD5=@sourcemd5";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
string sourceUriStr = "";
|
||||
if (Object.Url != null)
|
||||
int sourceId = 0;
|
||||
|
||||
sql = "SELECT * FROM Signatures_Sources WHERE `SourceMD5`=@sourcemd5";
|
||||
dbDict = new Dictionary<string, object>
|
||||
{
|
||||
sourceUriStr = Object.Url.ToString();
|
||||
{ "name", Common.ReturnValueIfNull(Object.Name, "") },
|
||||
{ "description", Common.ReturnValueIfNull(Object.Description, "") },
|
||||
{ "category", Common.ReturnValueIfNull(Object.Category, "") },
|
||||
{ "version", Common.ReturnValueIfNull(Object.Version, "") },
|
||||
{ "author", Common.ReturnValueIfNull(Object.Author, "") },
|
||||
{ "email", Common.ReturnValueIfNull(Object.Email, "") },
|
||||
{ "homepage", Common.ReturnValueIfNull(Object.Homepage, "") }
|
||||
};
|
||||
if (Object.Url == null)
|
||||
{
|
||||
dbDict.Add("uri", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("uri", Common.ReturnValueIfNull(Object.Url.ToString(), ""));
|
||||
}
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(Object.Name, ""));
|
||||
dbDict.Add("description", Common.ReturnValueIfNull(Object.Description, ""));
|
||||
dbDict.Add("category", Common.ReturnValueIfNull(Object.Category, ""));
|
||||
dbDict.Add("version", Common.ReturnValueIfNull(Object.Version, ""));
|
||||
dbDict.Add("author", Common.ReturnValueIfNull(Object.Author, ""));
|
||||
dbDict.Add("email", Common.ReturnValueIfNull(Object.Email, ""));
|
||||
dbDict.Add("homepage", Common.ReturnValueIfNull(Object.Homepage, ""));
|
||||
dbDict.Add("uri", sourceUriStr);
|
||||
dbDict.Add("sourcetype", Common.ReturnValueIfNull(Object.SourceType, ""));
|
||||
dbDict.Add("sourcemd5", Object.SourceMd5);
|
||||
dbDict.Add("sourcesha1", Object.SourceSHA1);
|
||||
@@ -89,9 +137,11 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Sources (Name, Description, Category, Version, Author, Email, Homepage, Url, SourceType, SourceMD5, SourceSHA1) VALUES (@name, @description, @category, @version, @author, @email, @homepage, @uri, @sourcetype, @sourcemd5, @sourcesha1)";
|
||||
sql = "INSERT INTO Signatures_Sources (`Name`, `Description`, `Category`, `Version`, `Author`, `Email`, `Homepage`, `Url`, `SourceType`, `SourceMD5`, `SourceSHA1`) VALUES (@name, @description, @category, @version, @author, @email, @homepage, @uri, @sourcetype, @sourcemd5, @sourcesha1); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
sourceId = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
|
||||
processGames = true;
|
||||
}
|
||||
@@ -121,21 +171,88 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
dbDict.Add("platform", Common.ReturnValueIfNull(gameObject.System, ""));
|
||||
dbDict.Add("systemvariant", Common.ReturnValueIfNull(gameObject.SystemVariant, ""));
|
||||
dbDict.Add("video", Common.ReturnValueIfNull(gameObject.Video, ""));
|
||||
dbDict.Add("country", Common.ReturnValueIfNull(gameObject.Country, ""));
|
||||
dbDict.Add("language", Common.ReturnValueIfNull(gameObject.Language, ""));
|
||||
|
||||
List<int> gameCountries = new List<int>();
|
||||
if (
|
||||
gameObject.Country != null &&
|
||||
gameObject.Country != "Unknown"
|
||||
)
|
||||
{
|
||||
string[] countries = gameObject.Country.Split(",");
|
||||
foreach (string country in countries)
|
||||
{
|
||||
int countryId = -1;
|
||||
countryId = Common.GetLookupByCode(Common.LookupTypes.Country, (string)Common.ReturnValueIfNull(country.Trim(), ""));
|
||||
if (countryId == -1)
|
||||
{
|
||||
countryId = Common.GetLookupByValue(Common.LookupTypes.Country, (string)Common.ReturnValueIfNull(country.Trim(), ""));
|
||||
|
||||
if (countryId == -1)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Signature Ingest", "Unable to locate country id for " + country.Trim());
|
||||
sql = "INSERT INTO Country (`Code`, `Value`) VALUES (@code, @name); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
Dictionary<string, object> countryDict = new Dictionary<string, object>{
|
||||
{ "code", country.Trim() },
|
||||
{ "name", country.Trim() }
|
||||
};
|
||||
countryId = int.Parse(db.ExecuteCMD(sql, countryDict).Rows[0][0].ToString());
|
||||
}
|
||||
}
|
||||
|
||||
if (countryId > 0)
|
||||
{
|
||||
gameCountries.Add(countryId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<int> gameLanguages = new List<int>();
|
||||
if (
|
||||
gameObject.Language != null &&
|
||||
gameObject.Language != "nolang"
|
||||
)
|
||||
{
|
||||
string[] languages = gameObject.Language.Split(",");
|
||||
foreach (string language in languages)
|
||||
{
|
||||
int languageId = -1;
|
||||
languageId = Common.GetLookupByCode(Common.LookupTypes.Language, (string)Common.ReturnValueIfNull(language.Trim(), ""));
|
||||
if (languageId == -1)
|
||||
{
|
||||
languageId = Common.GetLookupByValue(Common.LookupTypes.Language, (string)Common.ReturnValueIfNull(language.Trim(), ""));
|
||||
|
||||
if (languageId == -1)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Signature Ingest", "Unable to locate language id for " + language.Trim());
|
||||
sql = "INSERT INTO Language (`Code`, `Value`) VALUES (@code, @name); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
Dictionary<string, object> langDict = new Dictionary<string, object>{
|
||||
{ "code", language.Trim() },
|
||||
{ "name", language.Trim() }
|
||||
};
|
||||
languageId = int.Parse(db.ExecuteCMD(sql, langDict).Rows[0][0].ToString());
|
||||
}
|
||||
}
|
||||
|
||||
if (languageId > 0)
|
||||
{
|
||||
gameLanguages.Add(languageId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbDict.Add("copyright", Common.ReturnValueIfNull(gameObject.Copyright, ""));
|
||||
|
||||
// store platform
|
||||
int gameSystem = 0;
|
||||
if (gameObject.System != null)
|
||||
{
|
||||
sql = "SELECT Id FROM Signatures_Platforms WHERE Platform=@platform";
|
||||
sql = "SELECT `Id` FROM Signatures_Platforms WHERE `Platform`=@platform";
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Platforms (Platform) VALUES (@platform); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sql = "INSERT INTO Signatures_Platforms (`Platform`) VALUES (@platform); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
gameSystem = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
@@ -151,13 +268,13 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
int gamePublisher = 0;
|
||||
if (gameObject.Publisher != null)
|
||||
{
|
||||
sql = "SELECT * FROM Signatures_Publishers WHERE Publisher=@publisher";
|
||||
sql = "SELECT * FROM Signatures_Publishers WHERE `Publisher`=@publisher";
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Publishers (Publisher) VALUES (@publisher); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sql = "INSERT INTO Signatures_Publishers (`Publisher`) VALUES (@publisher); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
gamePublisher = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
}
|
||||
@@ -169,16 +286,16 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
dbDict.Add("publisherid", gamePublisher);
|
||||
|
||||
// store game
|
||||
int gameId = 0;
|
||||
sql = "SELECT * FROM Signatures_Games WHERE Name=@name AND Year=@year AND Publisherid=@publisher AND Systemid=@systemid AND Country=@country AND Language=@language";
|
||||
long gameId = 0;
|
||||
sql = "SELECT * FROM Signatures_Games WHERE `Name`=@name AND `Year`=@year AND `PublisherId`=@publisherid AND `SystemId`=@systemid";
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Games " +
|
||||
"(Name, Description, Year, PublisherId, Demo, SystemId, SystemVariant, Video, Country, Language, Copyright) VALUES " +
|
||||
"(@name, @description, @year, @publisherid, @demo, @systemid, @systemvariant, @video, @country, @language, @copyright); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
"(`Name`, `Description`, `Year`, `PublisherId`, `Demo`, `SystemId`, `SystemVariant`, `Video`, `Copyright`) VALUES " +
|
||||
"(@name, @description, @year, @publisherid, @demo, @systemid, @systemvariant, @video, @copyright); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
gameId = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
@@ -188,13 +305,57 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
gameId = (int)sigDB.Rows[0][0];
|
||||
}
|
||||
|
||||
// insert countries
|
||||
foreach (int gameCountry in gameCountries)
|
||||
{
|
||||
try
|
||||
{
|
||||
sql = "SELECT * FROM Signatures_Games_Countries WHERE GameId = @gameid AND CountryId = @Countryid";
|
||||
Dictionary<string, object> countryDict = new Dictionary<string, object>{
|
||||
{ "gameid", gameId },
|
||||
{ "Countryid", gameCountry }
|
||||
};
|
||||
if (db.ExecuteCMD(sql, countryDict).Rows.Count == 0)
|
||||
{
|
||||
sql = "INSERT INTO Signatures_Games_Countries (GameId, CountryId) VALUES (@gameid, @Countryid)";
|
||||
db.ExecuteCMD(sql, countryDict);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Game id: " + gameId + " with Country " + gameCountry);
|
||||
}
|
||||
}
|
||||
|
||||
// insert languages
|
||||
foreach (int gameLanguage in gameLanguages)
|
||||
{
|
||||
try
|
||||
{
|
||||
sql = "SELECT * FROM Signatures_Games_Languages WHERE GameId = @gameid AND LanguageId = @languageid";
|
||||
Dictionary<string, object> langDict = new Dictionary<string, object>{
|
||||
{ "gameid", gameId },
|
||||
{ "languageid", gameLanguage }
|
||||
};
|
||||
if (db.ExecuteCMD(sql, langDict).Rows.Count == 0)
|
||||
{
|
||||
sql = "INSERT INTO Signatures_Games_Languages (GameId, LanguageId) VALUES (@gameid, @languageid)";
|
||||
db.ExecuteCMD(sql, langDict);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Game id: " + gameId + " with language " + gameLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
// store rom
|
||||
foreach (RomSignatureObject.Game.Rom romObject in gameObject.Roms)
|
||||
{
|
||||
if (romObject.Md5 != null || romObject.Sha1 != null)
|
||||
{
|
||||
int romId = 0;
|
||||
sql = "SELECT * FROM Signatures_Roms WHERE GameId=@gameid AND MD5=@md5";
|
||||
long romId = 0;
|
||||
sql = "SELECT * FROM Signatures_Roms WHERE `GameId`=@gameid AND (`MD5`=@md5 OR `SHA1`=@sha1)";
|
||||
dbDict = new Dictionary<string, object>();
|
||||
dbDict.Add("gameid", gameId);
|
||||
dbDict.Add("name", Common.ReturnValueIfNull(romObject.Name, ""));
|
||||
@@ -212,12 +373,12 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("attributes", "[ ]");
|
||||
dbDict.Add("attributes", "");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDict.Add("attributes", "[ ]");
|
||||
dbDict.Add("attributes", "");
|
||||
}
|
||||
dbDict.Add("romtype", (int)romObject.RomType);
|
||||
dbDict.Add("romtypemedia", Common.ReturnValueIfNull(romObject.RomTypeMedia, ""));
|
||||
@@ -229,30 +390,51 @@ namespace gaseous_server.SignatureIngestors.XML
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
// entry not present, insert it
|
||||
sql = "INSERT INTO Signatures_Roms (GameId, Name, Size, CRC, MD5, SHA1, DevelopmentStatus, Attributes, RomType, RomTypeMedia, MediaLabel, MetadataSource, IngestorVersion) VALUES (@gameid, @name, @size, @crc, @md5, @sha1, @developmentstatus, @attributes, @romtype, @romtypemedia, @medialabel, @metadatasource, @ingestorversion); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sql = "INSERT INTO Signatures_Roms (`GameId`, `Name`, `Size`, `CRC`, `MD5`, `SHA1`, `DevelopmentStatus`, `Attributes`, `RomType`, `RomTypeMedia`, `MediaLabel`, `MetadataSource`, `IngestorVersion`) VALUES (@gameid, @name, @size, @crc, @md5, @sha1, @developmentstatus, @attributes, @romtype, @romtypemedia, @medialabel, @metadatasource, @ingestorversion); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
|
||||
romId = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
romId = (int)sigDB.Rows[0][0];
|
||||
}
|
||||
|
||||
// map the rom to the source
|
||||
sql = "SELECT * FROM Signatures_RomToSource WHERE SourceId=@sourceid AND RomId=@romid;";
|
||||
dbDict.Add("romid", romId);
|
||||
dbDict.Add("sourceId", sourceId);
|
||||
|
||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||
if (sigDB.Rows.Count == 0)
|
||||
{
|
||||
sql = "INSERT INTO Signatures_RomToSource (`SourceId`, `RomId`) VALUES (@sourceid, @romid);";
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File.Move(XMLFile, Path.Combine(ProcessedDirectory, Path.GetFileName(XMLFile)));
|
||||
if (DBFile != null)
|
||||
{
|
||||
File.Move(DBFile, Path.Combine(XMLDBProcessedDirectory, Path.GetFileName(DBFile)));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Warning, "Signature Ingestor - XML", "Invalid import file: " + XMLFile, ex);
|
||||
Logging.Log(Logging.LogType.Warning, "Signature Ingest", "Error ingesting " + XMLType.ToString() + " file: " + XMLFile, ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Debug, "Signature Ingestor - XML", "Rejecting already imported file: " + XMLFile);
|
||||
Logging.Log(Logging.LogType.Information, "Signature Ingest", "Rejecting already imported " + XMLType.ToString() + " file: " + XMLFile);
|
||||
File.Move(XMLFile, Path.Combine(ProcessedDirectory, Path.GetFileName(XMLFile)));
|
||||
if (DBFile != null)
|
||||
{
|
||||
File.Move(DBFile, Path.Combine(XMLDBProcessedDirectory, Path.GetFileName(DBFile)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
using System.Data;
|
||||
using gaseous_server.Models;
|
||||
using gaseous_signature_parser.models.RomSignatureObject;
|
||||
using static gaseous_server.Classes.Common;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
@@ -46,7 +48,7 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
Game = new gaseous_server.Models.Signatures_Games.GameItem
|
||||
{
|
||||
Id = (Int32)sigDbRow["Id"],
|
||||
Id = (long)(int)sigDbRow["Id"],
|
||||
Name = (string)sigDbRow["Name"],
|
||||
Description = (string)sigDbRow["Description"],
|
||||
Year = (string)sigDbRow["Year"],
|
||||
@@ -55,20 +57,20 @@ namespace gaseous_server.Classes
|
||||
System = (string)sigDbRow["Platform"],
|
||||
SystemVariant = (string)sigDbRow["SystemVariant"],
|
||||
Video = (string)sigDbRow["Video"],
|
||||
Country = (string)sigDbRow["Country"],
|
||||
Language = (string)sigDbRow["Language"],
|
||||
Countries = new Dictionary<string, string>(GetLookup(LookupTypes.Country, (long)(int)sigDbRow["Id"])),
|
||||
Languages = new Dictionary<string, string>(GetLookup(LookupTypes.Language, (long)(int)sigDbRow["Id"])),
|
||||
Copyright = (string)sigDbRow["Copyright"]
|
||||
},
|
||||
Rom = new gaseous_server.Models.Signatures_Games.RomItem
|
||||
{
|
||||
Id = (Int32)sigDbRow["romid"],
|
||||
Id = (long)(int)sigDbRow["romid"],
|
||||
Name = (string)sigDbRow["romname"],
|
||||
Size = (Int64)sigDbRow["Size"],
|
||||
Crc = (string)sigDbRow["CRC"],
|
||||
Md5 = ((string)sigDbRow["MD5"]).ToLower(),
|
||||
Sha1 = ((string)sigDbRow["SHA1"]).ToLower(),
|
||||
DevelopmentStatus = (string)sigDbRow["DevelopmentStatus"],
|
||||
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<KeyValuePair<string, object>>>((string)Common.ReturnValueIfNull(sigDbRow["Attributes"], "[]")),
|
||||
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>((string)Common.ReturnValueIfNull(sigDbRow["Attributes"], "[]")),
|
||||
RomType = (gaseous_server.Models.Signatures_Games.RomItem.RomTypes)(int)sigDbRow["RomType"],
|
||||
RomTypeMedia = (string)sigDbRow["RomTypeMedia"],
|
||||
MediaLabel = (string)sigDbRow["MediaLabel"],
|
||||
@@ -79,5 +81,77 @@ namespace gaseous_server.Classes
|
||||
}
|
||||
return GamesList;
|
||||
}
|
||||
|
||||
public List<Signatures_Sources> GetSources()
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM Signatures_Sources ORDER BY `SourceType`, `Name`;";
|
||||
DataTable sigDb = db.ExecuteCMD(sql);
|
||||
|
||||
List<Signatures_Sources> SourcesList = new List<Signatures_Sources>();
|
||||
|
||||
foreach (DataRow sigDbRow in sigDb.Rows)
|
||||
{
|
||||
Signatures_Sources sourceItem = new Signatures_Sources
|
||||
{
|
||||
Id = (int)sigDbRow["Id"],
|
||||
Name = (string)sigDbRow["Name"],
|
||||
Description = (string)sigDbRow["Description"],
|
||||
URL = (string)sigDbRow["URL"],
|
||||
Category = (string)sigDbRow["Category"],
|
||||
Version = (string)sigDbRow["Version"],
|
||||
Author = (string)sigDbRow["Author"],
|
||||
Email = (string)sigDbRow["Email"],
|
||||
Homepage = (string)sigDbRow["Homepage"],
|
||||
SourceType = (gaseous_signature_parser.parser.SignatureParser)Enum.Parse(typeof(gaseous_signature_parser.parser.SignatureParser), sigDbRow["SourceType"].ToString()),
|
||||
MD5 = (string)sigDbRow["SourceMD5"],
|
||||
SHA1 = (string)sigDbRow["SourceSHA1"]
|
||||
};
|
||||
SourcesList.Add(sourceItem);
|
||||
}
|
||||
return SourcesList;
|
||||
}
|
||||
|
||||
public void DeleteSource(int sourceId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "DELETE FROM Signatures_Sources WHERE Id = @sourceId;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "sourceId", sourceId }
|
||||
};
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
|
||||
public Dictionary<string, string> GetLookup(LookupTypes LookupType, long GameId)
|
||||
{
|
||||
string tableName = "";
|
||||
switch (LookupType)
|
||||
{
|
||||
case LookupTypes.Country:
|
||||
tableName = "Countries";
|
||||
break;
|
||||
|
||||
case LookupTypes.Language:
|
||||
tableName = "Languages";
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT " + LookupType.ToString() + ".Code, " + LookupType.ToString() + ".Value FROM Signatures_Games_" + tableName + " JOIN " + LookupType.ToString() + " ON Signatures_Games_" + tableName + "." + LookupType.ToString() + "Id = " + LookupType.ToString() + ".Id WHERE Signatures_Games_" + tableName + ".GameId = @id;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "id", GameId }
|
||||
};
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
Dictionary<string, string> returnDict = new Dictionary<string, string>();
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
returnDict.Add((string)row["Code"], (string)row["Value"]);
|
||||
}
|
||||
|
||||
return returnDict;
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,29 +5,45 @@ namespace gaseous_server.Classes
|
||||
{
|
||||
public class Statistics
|
||||
{
|
||||
public StatisticsModel RecordSession(Guid SessionId, long GameId, string UserId)
|
||||
public StatisticsModel RecordSession(Guid SessionId, long GameId, long PlatformId, long RomId, bool IsMediaGroup, string UserId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql;
|
||||
Dictionary<string, object> dbDict;
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "userid", UserId },
|
||||
{ "gameid", GameId },
|
||||
{ "platformid", PlatformId },
|
||||
{ "romid", RomId },
|
||||
{ "ismediagroup", IsMediaGroup }
|
||||
};
|
||||
|
||||
// update last played rom id
|
||||
sql = "INSERT INTO User_RecentPlayedRoms (UserId, GameId, PlatformId, RomId, IsMediaGroup) VALUES (@userid, @gameid, @platformid, @romid, @ismediagroup) ON DUPLICATE KEY UPDATE RomId = @romid, IsMediaGroup = @ismediagroup;";
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
|
||||
// update sessions
|
||||
|
||||
if (SessionId == Guid.Empty)
|
||||
{
|
||||
// new session required
|
||||
SessionId = Guid.NewGuid();
|
||||
|
||||
sql = "INSERT INTO UserTimeTracking (GameId, UserId, SessionId, SessionTime, SessionLength) VALUES (@gameid, @userid, @sessionid, @sessiontime, @sessionlength);";
|
||||
sql = "INSERT INTO UserTimeTracking (GameId, UserId, SessionId, SessionTime, SessionLength, PlatformId, IsMediaGroup, RomId) VALUES (@gameid, @userid, @sessionid, @sessiontime, @sessionlength, @platformid, @ismediagroup, @romid);";
|
||||
dbDict = new Dictionary<string, object>{
|
||||
{ "gameid", GameId },
|
||||
{ "userid", UserId },
|
||||
{ "sessionid", SessionId },
|
||||
{ "sessiontime", DateTime.UtcNow },
|
||||
{ "sessionlength", 1 }
|
||||
{ "sessionlength", 1 },
|
||||
{ "platformid", PlatformId },
|
||||
{ "ismediagroup", IsMediaGroup },
|
||||
{ "romid", RomId }
|
||||
};
|
||||
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
|
||||
return new StatisticsModel{
|
||||
return new StatisticsModel
|
||||
{
|
||||
GameId = GameId,
|
||||
SessionId = SessionId,
|
||||
SessionStart = (DateTime)dbDict["sessiontime"],
|
||||
@@ -50,7 +66,8 @@ namespace gaseous_server.Classes
|
||||
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid AND SessionId = @sessionid;";
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
return new StatisticsModel{
|
||||
return new StatisticsModel
|
||||
{
|
||||
GameId = (long)data.Rows[0]["GameId"],
|
||||
SessionId = Guid.Parse(data.Rows[0]["SessionId"].ToString()),
|
||||
SessionStart = (DateTime)data.Rows[0]["SessionTime"],
|
||||
@@ -87,7 +104,8 @@ namespace gaseous_server.Classes
|
||||
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid ORDER BY SessionTime DESC LIMIT 1;";
|
||||
data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
return new StatisticsModel{
|
||||
return new StatisticsModel
|
||||
{
|
||||
GameId = GameId,
|
||||
SessionLength = TotalTime,
|
||||
SessionStart = (DateTime)data.Rows[0]["SessionTime"]
|
||||
|
187
gaseous-server/Classes/UserProfile.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using System.Data;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public class UserProfile
|
||||
{
|
||||
static readonly Dictionary<string, string> supportedImages = new Dictionary<string, string>{
|
||||
{ ".png", "image/png" },
|
||||
{ ".jpg", "image/jpeg" },
|
||||
{ ".jpeg", "image/jpeg" },
|
||||
{ ".gif", "image/gif" },
|
||||
{ ".bmp", "image/bmp" },
|
||||
{ ".svg", "image/svg+xml" }
|
||||
};
|
||||
|
||||
public Models.UserProfile? GetUserProfile(string UserId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Id, DisplayName, Quip, AvatarExtension, ProfileBackgroundExtension, UnstructuredData FROM UserProfiles WHERE Id = @userid;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "userid", UserId }
|
||||
};
|
||||
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (data.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Models.UserProfile.ProfileImageItem? Avatar = null;
|
||||
if (data.Rows[0]["AvatarExtension"] != DBNull.Value)
|
||||
{
|
||||
Avatar = new Models.UserProfile.ProfileImageItem
|
||||
{
|
||||
MimeType = supportedImages[data.Rows[0]["AvatarExtension"].ToString()],
|
||||
Extension = data.Rows[0]["AvatarExtension"].ToString()
|
||||
};
|
||||
}
|
||||
|
||||
Models.UserProfile.ProfileImageItem? ProfileBackground = null;
|
||||
if (data.Rows[0]["ProfileBackgroundExtension"] != DBNull.Value)
|
||||
{
|
||||
ProfileBackground = new Models.UserProfile.ProfileImageItem
|
||||
{
|
||||
MimeType = supportedImages[data.Rows[0]["ProfileBackgroundExtension"].ToString()],
|
||||
Extension = data.Rows[0]["ProfileBackgroundExtension"].ToString()
|
||||
};
|
||||
}
|
||||
|
||||
return new Models.UserProfile
|
||||
{
|
||||
UserId = Guid.Parse(data.Rows[0]["Id"].ToString()),
|
||||
DisplayName = data.Rows[0]["DisplayName"].ToString(),
|
||||
Quip = data.Rows[0]["Quip"].ToString(),
|
||||
Avatar = Avatar,
|
||||
ProfileBackground = ProfileBackground,
|
||||
Data = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(data.Rows[0]["UnstructuredData"].ToString())
|
||||
};
|
||||
}
|
||||
|
||||
public void UpdateUserProfile(string InternalUserId, Models.UserProfile profile)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "UPDATE UserProfiles SET DisplayName = @displayname, Quip = @quip, UnstructuredData = @data WHERE UserId = @internalId AND Id = @userid;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "displayname", profile.DisplayName },
|
||||
{ "quip", profile.Quip },
|
||||
{ "data", Newtonsoft.Json.JsonConvert.SerializeObject(profile.Data) },
|
||||
{ "userid", profile.UserId },
|
||||
{ "internalId", InternalUserId }
|
||||
};
|
||||
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
|
||||
public enum ImageType
|
||||
{
|
||||
Avatar,
|
||||
Background
|
||||
}
|
||||
|
||||
public void UpdateImage(ImageType imageType, string UserId, string InternalUserId, string Filename, byte[] bytes)
|
||||
{
|
||||
// check if it's a supported file type
|
||||
if (!supportedImages.ContainsKey(Path.GetExtension(Filename).ToLower()))
|
||||
{
|
||||
throw new Exception("File type not supported");
|
||||
}
|
||||
|
||||
string ByteFieldName;
|
||||
string ExtensionFieldName;
|
||||
switch (imageType)
|
||||
{
|
||||
case ImageType.Avatar:
|
||||
ByteFieldName = "Avatar";
|
||||
ExtensionFieldName = "AvatarExtension";
|
||||
break;
|
||||
case ImageType.Background:
|
||||
ByteFieldName = "ProfileBackground";
|
||||
ExtensionFieldName = "ProfileBackgroundExtension";
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid image type");
|
||||
}
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = String.Format("UPDATE UserProfiles SET {0} = @content, {1} = @extension WHERE Id = @userid AND UserId = @internaluserid;", ByteFieldName, ExtensionFieldName);
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "content", bytes },
|
||||
{ "extension", Path.GetExtension(Filename) },
|
||||
{ "userid", UserId },
|
||||
{ "internaluserid", InternalUserId }
|
||||
};
|
||||
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
|
||||
public Models.ImageItem? GetImage(ImageType imageType, string UserId)
|
||||
{
|
||||
string ByteFieldName;
|
||||
string ExtensionFieldName;
|
||||
switch (imageType)
|
||||
{
|
||||
case ImageType.Avatar:
|
||||
ByteFieldName = "Avatar";
|
||||
ExtensionFieldName = "AvatarExtension";
|
||||
break;
|
||||
case ImageType.Background:
|
||||
ByteFieldName = "ProfileBackground";
|
||||
ExtensionFieldName = "ProfileBackgroundExtension";
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid image type");
|
||||
}
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = String.Format("SELECT {0}, {1} FROM UserProfiles WHERE Id = @userid;", ByteFieldName, ExtensionFieldName);
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "userid", UserId }
|
||||
};
|
||||
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (data.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Models.ImageItem? image = new Models.ImageItem
|
||||
{
|
||||
content = data.Rows[0][ByteFieldName] as byte[],
|
||||
mimeType = supportedImages[data.Rows[0][ExtensionFieldName] as string],
|
||||
extension = data.Rows[0][ExtensionFieldName] as string
|
||||
};
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
public void DeleteImage(ImageType imageType, string UserId)
|
||||
{
|
||||
string ByteFieldName;
|
||||
string ExtensionFieldName;
|
||||
switch (imageType)
|
||||
{
|
||||
case ImageType.Avatar:
|
||||
ByteFieldName = "Avatar";
|
||||
ExtensionFieldName = "AvatarExtension";
|
||||
break;
|
||||
case ImageType.Background:
|
||||
ByteFieldName = "ProfileBackground";
|
||||
ExtensionFieldName = "ProfileBackgroundExtension";
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid image type");
|
||||
}
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = String.Format("UPDATE UserProfiles SET {0} = NULL, {1} = NULL WHERE UserId = @userid;", ByteFieldName, ExtensionFieldName);
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "userid", UserId }
|
||||
};
|
||||
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
}
|
||||
}
|
@@ -99,7 +99,7 @@ namespace gaseous_server.Controllers
|
||||
profile.Roles = new List<string>(await _userManager.GetRolesAsync(user));
|
||||
profile.SecurityProfile = user.SecurityProfile;
|
||||
profile.UserPreferences = user.UserPreferences;
|
||||
profile.Avatar = user.Avatar;
|
||||
profile.ProfileId = user.ProfileId;
|
||||
profile.Roles.Sort();
|
||||
|
||||
return Ok(profile);
|
||||
@@ -188,7 +188,7 @@ namespace gaseous_server.Controllers
|
||||
user.LockoutEnabled = rawUser.LockoutEnabled;
|
||||
user.LockoutEnd = rawUser.LockoutEnd;
|
||||
user.SecurityProfile = rawUser.SecurityProfile;
|
||||
user.Avatar = rawUser.Avatar;
|
||||
user.ProfileId = rawUser.ProfileId;
|
||||
|
||||
// get roles
|
||||
ApplicationUser? aUser = await _userManager.FindByIdAsync(rawUser.Id);
|
||||
@@ -220,6 +220,10 @@ namespace gaseous_server.Controllers
|
||||
Email = model.Email,
|
||||
NormalizedEmail = model.Email.ToUpper()
|
||||
};
|
||||
if (await _userManager.FindByEmailAsync(model.Email) != null)
|
||||
{
|
||||
return NotFound("User already exists");
|
||||
}
|
||||
var result = await _userManager.CreateAsync(user, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
@@ -241,6 +245,23 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Users/Test")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public async Task<IActionResult> TestUserExists(string Email)
|
||||
{
|
||||
ApplicationUser? rawUser = await _userManager.FindByEmailAsync(Email);
|
||||
|
||||
if (rawUser != null)
|
||||
{
|
||||
return Ok(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Users/{UserId}")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
@@ -256,6 +277,7 @@ namespace gaseous_server.Controllers
|
||||
user.LockoutEnabled = rawUser.LockoutEnabled;
|
||||
user.LockoutEnd = rawUser.LockoutEnd;
|
||||
user.SecurityProfile = rawUser.SecurityProfile;
|
||||
user.ProfileId = rawUser.ProfileId;
|
||||
|
||||
// get roles
|
||||
IList<string> aUserRoles = await _userManager.GetRolesAsync(rawUser);
|
||||
@@ -306,7 +328,7 @@ namespace gaseous_server.Controllers
|
||||
// delete all roles
|
||||
foreach (string role in userRoles)
|
||||
{
|
||||
if ((new string[] { "Admin", "Gamer", "Player" }).Contains(role) )
|
||||
if ((new string[] { "Admin", "Gamer", "Player" }).Contains(role))
|
||||
{
|
||||
await _userManager.RemoveFromRoleAsync(user, role);
|
||||
}
|
||||
|
@@ -7,6 +7,9 @@ using gaseous_server.Classes;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Asp.Versioning;
|
||||
using Authentication;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using gaseous_server.Models;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
{
|
||||
@@ -17,6 +20,15 @@ namespace gaseous_server.Controllers
|
||||
[Authorize]
|
||||
public class BiosController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
|
||||
public BiosController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
@@ -43,11 +55,14 @@ namespace gaseous_server.Controllers
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpHead]
|
||||
[Route("zip/{PlatformId}")]
|
||||
[Route("zip/{PlatformId}/{GameId}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GetBiosCompressed(long PlatformId)
|
||||
public async Task<ActionResult> GetBiosCompressedAsync(long PlatformId, long GameId = -1, bool filtered = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (GameId == -1 || filtered == false)
|
||||
{
|
||||
IGDB.Models.Platform platform = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
|
||||
@@ -67,6 +82,33 @@ namespace gaseous_server.Controllers
|
||||
var stream = new FileStream(tempFile, FileMode.Open);
|
||||
return File(stream, "application/zip", platform.Slug + ".zip");
|
||||
}
|
||||
else
|
||||
{
|
||||
// get user platform map
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
PlatformMapping platformMapping = new PlatformMapping();
|
||||
PlatformMapping.PlatformMapItem userPlatformMap = platformMapping.GetUserPlatformMap(user.Id, PlatformId, GameId);
|
||||
|
||||
// build zip file
|
||||
string tempFile = Path.GetTempFileName();
|
||||
|
||||
using (FileStream zipFile = System.IO.File.Create(tempFile))
|
||||
using (var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Create))
|
||||
{
|
||||
foreach (Bios.BiosItem bios in GetBios(PlatformId, true))
|
||||
{
|
||||
if (userPlatformMap.EnabledBIOSHashes.Contains(bios.hash))
|
||||
{
|
||||
zipArchive.CreateEntryFromFile(bios.biosPath, bios.filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var stream = new FileStream(tempFile, FileMode.Open);
|
||||
return File(stream, "application/zip", userPlatformMap.IGDBSlug + ".zip");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
|
@@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
using static gaseous_server.Classes.Metadata.AgeRatings;
|
||||
using Asp.Versioning;
|
||||
using static gaseous_server.Models.PlatformMapping;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
{
|
||||
@@ -457,73 +458,6 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/artwork/{ArtworkId}/image/{size}")]
|
||||
[Route("{GameId}/artwork/{ArtworkId}/image/{size}/{ImageName}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> GameCoverImage(long GameId, long ArtworkId, Communications.IGDBAPI_ImageSize size, string ImageName)
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
try
|
||||
{
|
||||
IGDB.Models.Artwork artworkObject = Artworks.GetArtwork(ArtworkId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
||||
|
||||
if (artworkObject != null) {
|
||||
//string coverFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Artwork", size.ToString(), artworkObject.ImageId + ".jpg");
|
||||
|
||||
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Artwork");
|
||||
|
||||
Communications comms = new Communications();
|
||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, artworkObject.ImageId, size, new List<Communications.IGDBAPI_ImageSize>{ Communications.IGDBAPI_ImageSize.original });
|
||||
|
||||
string coverFilePath = ImgFetch.Result;
|
||||
|
||||
|
||||
if (System.IO.File.Exists(coverFilePath))
|
||||
{
|
||||
string filename = artworkObject.ImageId + ".jpg";
|
||||
string filepath = coverFilePath;
|
||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
||||
string contentType = "image/jpg";
|
||||
|
||||
var cd = new System.Net.Mime.ContentDisposition
|
||||
{
|
||||
FileName = filename,
|
||||
Inline = true,
|
||||
};
|
||||
|
||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||
|
||||
return File(filedata, contentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
@@ -562,32 +496,103 @@ namespace gaseous_server.Controllers
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/cover/image/{size}")]
|
||||
[Route("{GameId}/cover/image/{size}/{imagename}")]
|
||||
[Route("{GameId}/{ImageType}/{ImageId}/image/{size}")]
|
||||
[Route("{GameId}/{ImageType}/{ImageId}/image/{size}/{imagename}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> GameCoverImage(long GameId, Communications.IGDBAPI_ImageSize size, string imagename = "")
|
||||
public async Task<ActionResult> GameImage(long GameId, MetadataImageType imageType, long ImageId, Communications.IGDBAPI_ImageSize size, string imagename = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
string? imageId = null;
|
||||
string? imageTypePath = null;
|
||||
|
||||
switch (imageType)
|
||||
{
|
||||
case MetadataImageType.cover:
|
||||
if (gameObject.Cover != null)
|
||||
{
|
||||
if (gameObject.Cover.Id != null)
|
||||
{
|
||||
IGDB.Models.Cover cover = Classes.Metadata.Covers.GetCover(gameObject.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
||||
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Covers");
|
||||
imageId = cover.ImageId;
|
||||
imageTypePath = "Covers";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
break;
|
||||
|
||||
case MetadataImageType.screenshots:
|
||||
if (gameObject.Screenshots != null)
|
||||
{
|
||||
if (gameObject.Screenshots.Ids.Contains(ImageId))
|
||||
{
|
||||
IGDB.Models.Screenshot imageObject = Screenshots.GetScreenshot(ImageId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
||||
|
||||
imageId = imageObject.ImageId;
|
||||
imageTypePath = "Screenshots";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
break;
|
||||
|
||||
case MetadataImageType.artwork:
|
||||
if (gameObject.Artworks != null)
|
||||
{
|
||||
if (gameObject.Artworks.Ids.Contains(ImageId))
|
||||
{
|
||||
IGDB.Models.Artwork imageObject = Artworks.GetArtwork(ImageId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
||||
|
||||
imageId = imageObject.ImageId;
|
||||
imageTypePath = "Artwork";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (imageId == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), imageTypePath);
|
||||
string imagePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), imageTypePath, size.ToString(), imageId + ".jpg");
|
||||
|
||||
if (!System.IO.File.Exists(imagePath))
|
||||
{
|
||||
Communications comms = new Communications();
|
||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, cover.ImageId, size, new List<Communications.IGDBAPI_ImageSize>{ Communications.IGDBAPI_ImageSize.cover_big, Communications.IGDBAPI_ImageSize.original });
|
||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), imageTypePath), imageId, size, new List<Communications.IGDBAPI_ImageSize> { Communications.IGDBAPI_ImageSize.cover_big, Communications.IGDBAPI_ImageSize.original });
|
||||
|
||||
string coverFilePath = ImgFetch.Result;
|
||||
imagePath = ImgFetch.Result;
|
||||
}
|
||||
|
||||
if (System.IO.File.Exists(coverFilePath)) {
|
||||
string filename = cover.ImageId + ".jpg";
|
||||
string filepath = coverFilePath;
|
||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
||||
if (!System.IO.File.Exists(imagePath))
|
||||
{
|
||||
Communications comms = new Communications();
|
||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, imageId, size, new List<Communications.IGDBAPI_ImageSize> { Communications.IGDBAPI_ImageSize.cover_big, Communications.IGDBAPI_ImageSize.original });
|
||||
|
||||
imagePath = ImgFetch.Result;
|
||||
}
|
||||
|
||||
if (System.IO.File.Exists(imagePath))
|
||||
{
|
||||
string filename = imageId + ".jpg";
|
||||
string filepath = imagePath;
|
||||
string contentType = "image/jpg";
|
||||
|
||||
var cd = new System.Net.Mime.ContentDisposition
|
||||
@@ -599,10 +604,18 @@ namespace gaseous_server.Controllers
|
||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||
|
||||
byte[] filedata = null;
|
||||
using (FileStream fs = System.IO.File.OpenRead(filepath))
|
||||
{
|
||||
using (BinaryReader binaryReader = new BinaryReader(fs))
|
||||
{
|
||||
filedata = binaryReader.ReadBytes((int)fs.Length);
|
||||
}
|
||||
}
|
||||
|
||||
return File(filedata, contentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
catch
|
||||
@@ -611,6 +624,13 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
public enum MetadataImageType
|
||||
{
|
||||
cover,
|
||||
screenshots,
|
||||
artwork
|
||||
}
|
||||
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
@@ -796,7 +816,8 @@ namespace gaseous_server.Controllers
|
||||
companyData.Add("company", company);
|
||||
|
||||
return Ok(companyData);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
@@ -857,17 +878,146 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/emulatorconfiguration/{PlatformId}")]
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(UserEmulatorConfiguration), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> GetGameEmulator(long GameId, long PlatformId)
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
if (gameObject != null)
|
||||
{
|
||||
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
|
||||
if (platformObject != null)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
PlatformMapping platformMapping = new PlatformMapping();
|
||||
UserEmulatorConfiguration platformMappingObject = platformMapping.GetUserEmulator(user.Id, GameId, PlatformId);
|
||||
|
||||
if (platformMappingObject != null)
|
||||
{
|
||||
return Ok(platformMappingObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[Route("{GameId}/emulatorconfiguration/{PlatformId}")]
|
||||
[Authorize]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> SetGameEmulator(long GameId, long PlatformId, UserEmulatorConfiguration configuration)
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
if (gameObject != null)
|
||||
{
|
||||
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
|
||||
if (platformObject != null)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
PlatformMapping platformMapping = new PlatformMapping();
|
||||
platformMapping.SetUserEmulator(user.Id, GameId, PlatformId, configuration);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpDelete]
|
||||
[Route("{GameId}/emulatorconfiguration/{PlatformId}")]
|
||||
[Authorize]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> DeleteGameEmulator(long GameId, long PlatformId)
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
if (gameObject != null)
|
||||
{
|
||||
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
|
||||
if (platformObject != null)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
PlatformMapping platformMapping = new PlatformMapping();
|
||||
platformMapping.DeleteUserEmulator(user.Id, GameId, PlatformId);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/platforms")]
|
||||
[ProducesResponseType(typeof(List<KeyValuePair<long, string>>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(List<Games.AvailablePlatformItem>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> GamePlatforms(long GameId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Ok(Games.GetAvailablePlatforms(GameId));
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
return Ok(Games.GetAvailablePlatforms(user.Id, GameId));
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -1025,6 +1175,67 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[Route("{GameId}/roms/{RomId}/{PlatformId}/favourite")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> GameRomFavourite(long GameId, long RomId, long PlatformId, bool IsMediaGroup, bool favourite)
|
||||
{
|
||||
try
|
||||
{
|
||||
ApplicationUser? user = await _userManager.GetUserAsync(User);
|
||||
|
||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
if (IsMediaGroup == false)
|
||||
{
|
||||
Classes.Roms.GameRomItem rom = Classes.Roms.GetRom(RomId);
|
||||
if (rom.GameId == GameId)
|
||||
{
|
||||
if (favourite == true)
|
||||
{
|
||||
Classes.Metadata.Games.GameSetFavouriteRom(user.Id, GameId, PlatformId, RomId, IsMediaGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
Classes.Metadata.Games.GameClearFavouriteRom(user.Id, GameId, PlatformId);
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomId, user.Id);
|
||||
if (rom.GameId == GameId)
|
||||
{
|
||||
if (favourite == true)
|
||||
{
|
||||
Classes.Metadata.Games.GameSetFavouriteRom(user.Id, GameId, PlatformId, RomId, IsMediaGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
Classes.Metadata.Games.GameClearFavouriteRom(user.Id, GameId, PlatformId);
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
@@ -1137,11 +1348,10 @@ namespace gaseous_server.Controllers
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[Route("{GameId}/romgroup")]
|
||||
[ProducesResponseType(typeof(List<RomMediaGroup.GameRomMediaGroupItem>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> GetGameRomGroupAsync(long GameId)
|
||||
public async Task<ActionResult> GetGameRomGroupAsync(long GameId, long? PlatformId = null)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
@@ -1151,7 +1361,7 @@ namespace gaseous_server.Controllers
|
||||
|
||||
try
|
||||
{
|
||||
return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId, user.Id));
|
||||
return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId, user.Id, PlatformId));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -1388,7 +1598,8 @@ namespace gaseous_server.Controllers
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
if (gameObject != null) {
|
||||
if (gameObject != null)
|
||||
{
|
||||
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
||||
if (screenshotObject != null)
|
||||
{
|
||||
@@ -1410,56 +1621,56 @@ namespace gaseous_server.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{GameId}/screenshots/{ScreenshotId}/image/{size}")]
|
||||
[Route("{GameId}/screenshots/{ScreenshotId}/image/{size}/{ImageName}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> GameScreenshotImage(long GameId, long ScreenshotId, Communications.IGDBAPI_ImageSize Size, string ImageName)
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
// [MapToApiVersion("1.0")]
|
||||
// [MapToApiVersion("1.1")]
|
||||
// [HttpGet]
|
||||
// [Route("{GameId}/screenshots/{ScreenshotId}/image/{size}")]
|
||||
// [Route("{GameId}/screenshots/{ScreenshotId}/image/{size}/{ImageName}")]
|
||||
// [ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
// [ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
// public async Task<ActionResult> GameScreenshotImage(long GameId, long ScreenshotId, Communications.IGDBAPI_ImageSize Size, string ImageName)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||
|
||||
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
||||
// IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), true);
|
||||
|
||||
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Screenshots");
|
||||
// string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), "Screenshots");
|
||||
|
||||
Communications comms = new Communications();
|
||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, screenshotObject.ImageId, Size, new List<Communications.IGDBAPI_ImageSize>{ Communications.IGDBAPI_ImageSize.original });
|
||||
// Communications comms = new Communications();
|
||||
// Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, screenshotObject.ImageId, Size, new List<Communications.IGDBAPI_ImageSize> { Communications.IGDBAPI_ImageSize.original });
|
||||
|
||||
string coverFilePath = ImgFetch.Result;
|
||||
// string coverFilePath = ImgFetch.Result;
|
||||
|
||||
if (System.IO.File.Exists(coverFilePath))
|
||||
{
|
||||
string filename = screenshotObject.ImageId + ".jpg";
|
||||
string filepath = coverFilePath;
|
||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
||||
string contentType = "image/jpg";
|
||||
// if (System.IO.File.Exists(coverFilePath))
|
||||
// {
|
||||
// string filename = screenshotObject.ImageId + ".jpg";
|
||||
// string filepath = coverFilePath;
|
||||
// byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
||||
// string contentType = "image/jpg";
|
||||
|
||||
var cd = new System.Net.Mime.ContentDisposition
|
||||
{
|
||||
FileName = filename,
|
||||
Inline = true,
|
||||
};
|
||||
// var cd = new System.Net.Mime.ContentDisposition
|
||||
// {
|
||||
// FileName = filename,
|
||||
// Inline = true,
|
||||
// };
|
||||
|
||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||
// Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||
// Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||
|
||||
return File(filedata, contentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
// return File(filedata, contentType);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return NotFound();
|
||||
// }
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// return NotFound();
|
||||
// }
|
||||
// }
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
|
@@ -86,5 +86,24 @@ namespace gaseous_server.Controllers
|
||||
return NotFound(exLNF.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost("{LibraryId}/Scan")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult ScanLibrary(int LibraryId)
|
||||
{
|
||||
try
|
||||
{
|
||||
GameLibrary.ScanLibrary(LibraryId);
|
||||
return Ok();
|
||||
}
|
||||
catch (GameLibrary.LibraryNotFound exLNF)
|
||||
{
|
||||
return NotFound(exLNF.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -149,35 +149,6 @@ namespace gaseous_server.Controllers
|
||||
return Ok(new { count = files.Count, size });
|
||||
}
|
||||
|
||||
// [MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
// [Route("{PlatformId}")]
|
||||
// [ProducesResponseType(typeof(PlatformMapping.PlatformMapItem), StatusCodes.Status200OK)]
|
||||
// [ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
// [ProducesResponseType(StatusCodes.Status409Conflict)]
|
||||
// public ActionResult NewPlatformMap(long PlatformId, PlatformMapping.PlatformMapItem Map)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(PlatformId);
|
||||
|
||||
// if (platformMapItem != null)
|
||||
// {
|
||||
// return Conflict();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// PlatformMapping.WritePlatformMap(Map, false, false);
|
||||
// return Ok(PlatformMapping.GetPlatformMap(PlatformId));
|
||||
// }
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// return NotFound();
|
||||
// }
|
||||
// }
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPatch]
|
||||
|
@@ -114,22 +114,64 @@ namespace gaseous_server.Controllers
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{PlatformId}/platformlogo/image")]
|
||||
[Route("{PlatformId}/platformlogo/{size}/logo.png")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult PlatformLogoImage(long PlatformId)
|
||||
public async Task<ActionResult> GameImage(long PlatformId, Communications.IGDBAPI_ImageSize size)
|
||||
{
|
||||
try
|
||||
{
|
||||
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||
|
||||
string logoFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject), "Logo_Medium.png");
|
||||
if (System.IO.File.Exists(logoFilePath))
|
||||
IGDB.Models.PlatformLogo? logoObject = null;
|
||||
try
|
||||
{
|
||||
string filename = "Logo.png";
|
||||
string filepath = logoFilePath;
|
||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
||||
string contentType = "image/png";
|
||||
logoObject = PlatformLogos.GetPlatformLogo(platformObject.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// getting the logo failed, so we'll try a platform variant if available
|
||||
if (platformObject.Versions != null)
|
||||
{
|
||||
if (platformObject.Versions.Ids.Length > 0)
|
||||
{
|
||||
IGDB.Models.PlatformVersion platformVersion = Classes.Metadata.PlatformVersions.GetPlatformVersion(platformObject.Versions.Ids[0], platformObject);
|
||||
logoObject = PlatformLogos.GetPlatformLogo(platformVersion.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject));
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
string basePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject));
|
||||
string imagePath = Path.Combine(basePath, size.ToString(), logoObject.ImageId + ".jpg");
|
||||
|
||||
if (!System.IO.File.Exists(imagePath))
|
||||
{
|
||||
Communications comms = new Communications();
|
||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject)), logoObject.ImageId, size, new List<Communications.IGDBAPI_ImageSize> { Communications.IGDBAPI_ImageSize.cover_big, Communications.IGDBAPI_ImageSize.original });
|
||||
|
||||
imagePath = ImgFetch.Result;
|
||||
}
|
||||
|
||||
if (!System.IO.File.Exists(imagePath))
|
||||
{
|
||||
Communications comms = new Communications();
|
||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, logoObject.ImageId, size, new List<Communications.IGDBAPI_ImageSize> { Communications.IGDBAPI_ImageSize.cover_big, Communications.IGDBAPI_ImageSize.original });
|
||||
|
||||
imagePath = ImgFetch.Result;
|
||||
}
|
||||
|
||||
if (System.IO.File.Exists(imagePath))
|
||||
{
|
||||
string filename = logoObject.ImageId + ".jpg";
|
||||
string filepath = imagePath;
|
||||
string contentType = "image/jpg";
|
||||
|
||||
var cd = new System.Net.Mime.ContentDisposition
|
||||
{
|
||||
@@ -138,14 +180,22 @@ namespace gaseous_server.Controllers
|
||||
};
|
||||
|
||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||
|
||||
byte[] filedata = null;
|
||||
using (FileStream fs = System.IO.File.OpenRead(filepath))
|
||||
{
|
||||
using (BinaryReader binaryReader = new BinaryReader(fs))
|
||||
{
|
||||
filedata = binaryReader.ReadBytes((int)fs.Length);
|
||||
}
|
||||
}
|
||||
|
||||
return File(filedata, contentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return NotFound();
|
||||
|
@@ -31,41 +31,34 @@ namespace gaseous_server.Controllers
|
||||
[Authorize(Roles = "Admin,Gamer")]
|
||||
[ProducesResponseType(typeof(List<IFormFile>), StatusCodes.Status200OK)]
|
||||
[RequestSizeLimit(long.MaxValue)]
|
||||
[Consumes("multipart/form-data")]
|
||||
[DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, ValueLengthLimit = int.MaxValue)]
|
||||
public async Task<IActionResult> UploadRom(List<IFormFile> files, long? OverridePlatformId = null)
|
||||
public async Task<IActionResult> UploadRom(IFormFile file, long? OverridePlatformId = null)
|
||||
{
|
||||
Guid sessionid = Guid.NewGuid();
|
||||
|
||||
string workPath = Path.Combine(Config.LibraryConfiguration.LibraryUploadDirectory, sessionid.ToString());
|
||||
|
||||
long size = files.Sum(f => f.Length);
|
||||
|
||||
List<Dictionary<string, object>> UploadedFiles = new List<Dictionary<string, object>>();
|
||||
|
||||
foreach (IFormFile formFile in files)
|
||||
{
|
||||
if (formFile.Length > 0)
|
||||
if (file.Length > 0)
|
||||
{
|
||||
Guid FileId = Guid.NewGuid();
|
||||
|
||||
string filePath = Path.Combine(workPath, Path.GetFileName(formFile.FileName));
|
||||
string filePath = Path.Combine(workPath, Path.GetFileName(file.FileName));
|
||||
|
||||
if (!Directory.Exists(workPath))
|
||||
{
|
||||
Directory.CreateDirectory(workPath);
|
||||
}
|
||||
|
||||
Dictionary<string, object> UploadedFile = new Dictionary<string, object>();
|
||||
|
||||
using (var stream = System.IO.File.Create(filePath))
|
||||
{
|
||||
await formFile.CopyToAsync(stream);
|
||||
await file.CopyToAsync(stream);
|
||||
|
||||
Dictionary<string, object> UploadedFile = new Dictionary<string, object>();
|
||||
UploadedFile.Add("id", FileId.ToString());
|
||||
UploadedFile.Add("originalname", Path.GetFileName(formFile.FileName));
|
||||
UploadedFile.Add("originalname", Path.GetFileName(file.FileName));
|
||||
UploadedFile.Add("fullpath", filePath);
|
||||
UploadedFiles.Add(UploadedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get override platform if specified
|
||||
@@ -75,11 +68,22 @@ namespace gaseous_server.Controllers
|
||||
OverridePlatform = Platforms.GetPlatform((long)OverridePlatformId);
|
||||
}
|
||||
|
||||
// Process uploaded files
|
||||
foreach (Dictionary<string, object> UploadedFile in UploadedFiles)
|
||||
{
|
||||
// Process uploaded file
|
||||
Classes.ImportGame uploadImport = new ImportGame();
|
||||
uploadImport.ImportGameFile((string)UploadedFile["fullpath"], OverridePlatform);
|
||||
Dictionary<string, object> RetVal = uploadImport.ImportGameFile((string)UploadedFile["fullpath"], OverridePlatform);
|
||||
switch (RetVal["type"])
|
||||
{
|
||||
case "rom":
|
||||
if (RetVal["status"] == "imported")
|
||||
{
|
||||
IGDB.Models.Game? game = (IGDB.Models.Game)RetVal["game"];
|
||||
if (game.Id == null)
|
||||
{
|
||||
RetVal["game"] = Games.GetGame(0, false, false, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (Directory.Exists(workPath))
|
||||
@@ -87,7 +91,10 @@ namespace gaseous_server.Controllers
|
||||
Directory.Delete(workPath, true);
|
||||
}
|
||||
|
||||
return Ok(new { count = files.Count, size });
|
||||
return Ok(RetVal);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
@@ -73,7 +73,6 @@ namespace gaseous_server.Controllers
|
||||
private static async Task<List<GaseousGame>> _SearchForGame(long PlatformId, string SearchString)
|
||||
{
|
||||
string searchBody = "";
|
||||
// string searchFields = "fields cover,first_release_date,name,platforms,slug; ";
|
||||
string searchFields = "fields *; ";
|
||||
searchBody += "search \"" + SearchString + "\";";
|
||||
searchBody += "where platforms = (" + PlatformId + ");";
|
||||
|
@@ -9,6 +9,7 @@ using gaseous_signature_parser.models.RomSignatureObject;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Asp.Versioning;
|
||||
using gaseous_server.Models;
|
||||
|
||||
// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
||||
|
||||
@@ -54,11 +55,34 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
SignatureManagement signatureManagement = new SignatureManagement();
|
||||
return signatureManagement.GetByTosecName(TosecName);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public List<Signatures_Sources> GetSignatureSources()
|
||||
{
|
||||
SignatureManagement signatureManagement = new SignatureManagement();
|
||||
return signatureManagement.GetSources();
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpDelete]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IActionResult DeleteSignatureSource(int Id)
|
||||
{
|
||||
SignatureManagement signatureManagement = new SignatureManagement();
|
||||
signatureManagement.DeleteSource(Id);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -38,7 +38,10 @@ namespace gaseous_server.Controllers
|
||||
List<SystemInfo.PathItem> Disks = new List<SystemInfo.PathItem>();
|
||||
foreach (GameLibrary.LibraryItem libraryItem in GameLibrary.GetLibraries)
|
||||
{
|
||||
Disks.Add(GetDisk(libraryItem.Path));
|
||||
SystemInfo.PathItem pathItem = GetDisk(libraryItem.Path);
|
||||
pathItem.Name = libraryItem.Name;
|
||||
|
||||
Disks.Add(pathItem);
|
||||
}
|
||||
ReturnValue.Paths = Disks;
|
||||
|
||||
@@ -260,7 +263,14 @@ namespace gaseous_server.Controllers
|
||||
{
|
||||
AlwaysLogToDisk = Config.LoggingConfiguration.AlwaysLogToDisk,
|
||||
MinimumLogRetentionPeriod = Config.LoggingConfiguration.LogRetention,
|
||||
EmulatorDebugMode = Boolean.Parse(Config.ReadSetting<string>("emulatorDebugMode", false.ToString()))
|
||||
EmulatorDebugMode = Boolean.Parse(Config.ReadSetting<string>("emulatorDebugMode", false.ToString())),
|
||||
SignatureSource = new SystemSettingsModel.SignatureSourceItem()
|
||||
{
|
||||
Source = Config.MetadataConfiguration.SignatureSource,
|
||||
HasheousHost = Config.MetadataConfiguration.HasheousHost,
|
||||
HasheousSubmitFixes = (bool)Config.MetadataConfiguration.HasheousSubmitFixes,
|
||||
HasheousAPIKey = Config.MetadataConfiguration.HasheousAPIKey
|
||||
}
|
||||
};
|
||||
|
||||
return Ok(systemSettingsModel);
|
||||
@@ -279,6 +289,10 @@ namespace gaseous_server.Controllers
|
||||
Config.LoggingConfiguration.AlwaysLogToDisk = model.AlwaysLogToDisk;
|
||||
Config.LoggingConfiguration.LogRetention = model.MinimumLogRetentionPeriod;
|
||||
Config.SetSetting<string>("emulatorDebugMode", model.EmulatorDebugMode.ToString());
|
||||
Config.MetadataConfiguration.SignatureSource = model.SignatureSource.Source;
|
||||
Config.MetadataConfiguration.HasheousHost = model.SignatureSource.HasheousHost;
|
||||
Config.MetadataConfiguration.HasheousAPIKey = model.SignatureSource.HasheousAPIKey;
|
||||
Config.MetadataConfiguration.HasheousSubmitFixes = model.SignatureSource.HasheousSubmitFixes;
|
||||
Config.UpdateConfig();
|
||||
}
|
||||
|
||||
@@ -313,6 +327,7 @@ namespace gaseous_server.Controllers
|
||||
|
||||
public class PathItem
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string LibraryPath { get; set; }
|
||||
public long SpaceUsed { get; set; }
|
||||
public long SpaceAvailable { get; set; }
|
||||
@@ -719,5 +734,14 @@ namespace gaseous_server.Controllers
|
||||
public bool AlwaysLogToDisk { get; set; }
|
||||
public int MinimumLogRetentionPeriod { get; set; }
|
||||
public bool EmulatorDebugMode { get; set; }
|
||||
public SignatureSourceItem SignatureSource { get; set; }
|
||||
|
||||
public class SignatureSourceItem
|
||||
{
|
||||
public HasheousClient.Models.MetadataModel.SignatureSources Source { get; set; }
|
||||
public string HasheousHost { get; set; }
|
||||
public string HasheousAPIKey { get; set; }
|
||||
public bool HasheousSubmitFixes { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
80
gaseous-server/Controllers/V1.1/FileSystemController.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using gaseous_server.Classes;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
using IGDB.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
using static gaseous_server.Classes.Metadata.AgeRatings;
|
||||
using Asp.Versioning;
|
||||
|
||||
namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.1")]
|
||||
[ApiController]
|
||||
public class FileSystemController : ControllerBase
|
||||
{
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Authorize(Roles = "Admin")]
|
||||
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult GetFileSystem(string path, bool showFiles = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (path.Contains(".."))
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
Dictionary<string, List<Dictionary<string, string>>> allFiles = new Dictionary<string, List<Dictionary<string, string>>>();
|
||||
List<Dictionary<string, string>> directories = new List<Dictionary<string, string>>();
|
||||
string[] dirs = Directory.GetDirectories(path);
|
||||
Array.Sort(dirs);
|
||||
foreach (string dir in dirs)
|
||||
{
|
||||
DirectoryInfo directoryInfo = new DirectoryInfo(dir);
|
||||
directories.Add(new Dictionary<string, string> { { "name", directoryInfo.Name }, { "path", directoryInfo.FullName } });
|
||||
}
|
||||
allFiles.Add("directories", directories);
|
||||
|
||||
if (showFiles == true)
|
||||
{
|
||||
List<Dictionary<string, string>> files = new List<Dictionary<string, string>>();
|
||||
string[] filePaths = Directory.GetFiles(path);
|
||||
Array.Sort(filePaths);
|
||||
foreach (string file in filePaths)
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(file);
|
||||
files.Add(new Dictionary<string, string> { { "name", fileInfo.Name }, { "path", fileInfo.FullName } });
|
||||
}
|
||||
allFiles.Add("files", files);
|
||||
}
|
||||
|
||||
return Ok(allFiles);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NotFound();
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -26,7 +26,7 @@ namespace gaseous_server.Controllers.v1_1
|
||||
[ApiVersion("1.1")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class GamesController: ControllerBase
|
||||
public class GamesController : ControllerBase
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
@@ -106,7 +106,8 @@ namespace gaseous_server.Controllers.v1_1
|
||||
if (user != null)
|
||||
{
|
||||
string IncludeUnrated = "";
|
||||
if (user.SecurityProfile.AgeRestrictionPolicy.IncludeUnrated == true) {
|
||||
if (user.SecurityProfile.AgeRestrictionPolicy.IncludeUnrated == true)
|
||||
{
|
||||
IncludeUnrated = " OR view_Games.AgeGroupId IS NULL";
|
||||
}
|
||||
|
||||
@@ -446,7 +447,7 @@ namespace gaseous_server.Controllers.v1_1
|
||||
string orderByOrder = "ASC";
|
||||
if (model.Sorting != null)
|
||||
{
|
||||
switch(model.Sorting.SortBy)
|
||||
switch (model.Sorting.SortBy)
|
||||
{
|
||||
case GameSearchModel.GameSortingItem.SortField.NameThe:
|
||||
orderByField = "NameThe";
|
||||
@@ -485,6 +486,7 @@ SELECT DISTINCT
|
||||
Game.`Name`,
|
||||
Game.NameThe,
|
||||
Game.Slug,
|
||||
Game.Summary,
|
||||
Game.PlatformId,
|
||||
Game.TotalRating,
|
||||
Game.TotalRatingCount,
|
||||
@@ -551,7 +553,7 @@ FROM
|
||||
Favourites ON Game.Id = Favourites.GameId AND Favourites.UserId = @userid " + whereClause + " " + havingClause + " " + orderByClause;
|
||||
List<Games.MinimalGameItem> RetVal = new List<Games.MinimalGameItem>();
|
||||
|
||||
DataTable dbResponse = db.ExecuteCMD(sql, whereParams);
|
||||
DataTable dbResponse = db.ExecuteCMD(sql, whereParams, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 60));
|
||||
|
||||
// get count
|
||||
int RecordCount = dbResponse.Rows.Count;
|
||||
@@ -568,7 +570,7 @@ FROM
|
||||
}
|
||||
}
|
||||
|
||||
Game retGame = Storage.BuildCacheObject<Game>(new Game() , dbResponse.Rows[i]);
|
||||
Game retGame = Storage.BuildCacheObject<Game>(new Game(), dbResponse.Rows[i]);
|
||||
Games.MinimalGameItem retMinGame = new Games.MinimalGameItem(retGame);
|
||||
retMinGame.Index = i;
|
||||
if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value)
|
||||
@@ -593,28 +595,43 @@ FROM
|
||||
|
||||
// build alpha list
|
||||
Dictionary<string, int> AlphaList = new Dictionary<string, int>();
|
||||
if (orderByField == "NameThe" || orderByField == "Name")
|
||||
{
|
||||
int CurrentPage = 1;
|
||||
int NextPageIndex = pageSize;
|
||||
for (int i = 0; i < dbResponse.Rows.Count; i++)
|
||||
|
||||
string alphaSearchField;
|
||||
if (orderByField == "NameThe")
|
||||
{
|
||||
string firstChar = dbResponse.Rows[i]["NameThe"].ToString().Substring(0, 1).ToUpperInvariant();
|
||||
if (!"ABCDEFGHIJKLMNOPQRSTUVWXYZ".Contains(firstChar))
|
||||
{
|
||||
if (!AlphaList.ContainsKey("#"))
|
||||
{
|
||||
AlphaList.Add("#", 1);
|
||||
}
|
||||
alphaSearchField = "NameThe";
|
||||
}
|
||||
else
|
||||
{
|
||||
alphaSearchField = "Name";
|
||||
}
|
||||
|
||||
for (int i = 0; i < dbResponse.Rows.Count; i++)
|
||||
{
|
||||
if (NextPageIndex == i + 1)
|
||||
{
|
||||
NextPageIndex += pageSize;
|
||||
CurrentPage += 1;
|
||||
}
|
||||
|
||||
string firstChar = dbResponse.Rows[i][alphaSearchField].ToString().Substring(0, 1).ToUpperInvariant();
|
||||
if ("ABCDEFGHIJKLMNOPQRSTUVWXYZ".Contains(firstChar))
|
||||
{
|
||||
if (!AlphaList.ContainsKey(firstChar))
|
||||
{
|
||||
AlphaList.Add(firstChar, CurrentPage);
|
||||
}
|
||||
if (NextPageIndex == i + 1)
|
||||
}
|
||||
else
|
||||
{
|
||||
NextPageIndex += pageSize;
|
||||
CurrentPage += 1;
|
||||
if (!AlphaList.ContainsKey("#"))
|
||||
{
|
||||
AlphaList.Add("#", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Identity;
|
||||
using System.Data;
|
||||
using Asp.Versioning;
|
||||
using System.IO.Compression;
|
||||
using gaseous_server.Classes.Metadata;
|
||||
|
||||
namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
@@ -256,7 +257,25 @@ namespace gaseous_server.Controllers.v1_1
|
||||
else
|
||||
{
|
||||
// get rom data
|
||||
string romName = "";
|
||||
string romMd5 = "";
|
||||
string romSha1 = "";
|
||||
if (IsMediaGroup == false)
|
||||
{
|
||||
Roms.GameRomItem romItem = Roms.GetRom(RomId);
|
||||
romName = romItem.Name;
|
||||
romMd5 = romItem.Md5;
|
||||
romSha1 = romItem.Sha1;
|
||||
}
|
||||
else
|
||||
{
|
||||
RomMediaGroup.GameRomMediaGroupItem mediaGroupItem = RomMediaGroup.GetMediaGroup(RomId);
|
||||
IGDB.Models.Game game = Games.GetGame(mediaGroupItem.GameId, false, false, false);
|
||||
Classes.Common.hashObject hashObject = new Classes.Common.hashObject(Path.Combine(Config.LibraryConfiguration.LibraryMediaGroupDirectory, mediaGroupItem.Id.ToString() + ".zip"));
|
||||
romName = game.Name;
|
||||
romMd5 = hashObject.md5hash;
|
||||
romSha1 = hashObject.sha1hash;
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
if ((bool)data.Rows[0]["Zipped"] == false)
|
||||
@@ -267,9 +286,8 @@ namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
bytes = Common.Decompress((byte[])data.Rows[0]["State"]);
|
||||
}
|
||||
|
||||
string contentType = "";
|
||||
string filename = ((DateTime)data.Rows[0]["StateDateTime"]).ToString("yyyy-MM-ddTHH-mm-ss") + "-" + Path.GetFileNameWithoutExtension(romItem.Name);
|
||||
string filename = ((DateTime)data.Rows[0]["StateDateTime"]).ToString("yyyy-MM-ddTHH-mm-ss") + "-" + Path.GetFileNameWithoutExtension(romName);
|
||||
|
||||
|
||||
if (StateOnly == true)
|
||||
@@ -284,14 +302,14 @@ namespace gaseous_server.Controllers.v1_1
|
||||
|
||||
Dictionary<string, object> RomInfo = new Dictionary<string, object>
|
||||
{
|
||||
{ "Name", romItem.Name },
|
||||
{ "Name", romName },
|
||||
{ "StateDateTime", data.Rows[0]["StateDateTime"] },
|
||||
{ "StateName", data.Rows[0]["Name"] }
|
||||
};
|
||||
if ((int)data.Rows[0]["IsMediaGroup"] == 0)
|
||||
{
|
||||
RomInfo.Add("MD5", romItem.Md5);
|
||||
RomInfo.Add("SHA1", romItem.Sha1);
|
||||
RomInfo.Add("MD5", romMd5);
|
||||
RomInfo.Add("SHA1", romSha1);
|
||||
RomInfo.Add("Type", "ROM");
|
||||
}
|
||||
else
|
||||
|
@@ -12,7 +12,7 @@ namespace gaseous_server.Controllers.v1_1
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[ApiController]
|
||||
public class StatisticsController: ControllerBase
|
||||
public class StatisticsController : ControllerBase
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
@@ -32,15 +32,15 @@ namespace gaseous_server.Controllers.v1_1
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("Games/{GameId}/")]
|
||||
public async Task<ActionResult> NewRecordStatistics(long GameId)
|
||||
[Route("Games/{GameId}/{PlatformId}/{RomId}")]
|
||||
public async Task<ActionResult> NewRecordStatistics(long GameId, long PlatformId, long RomId, bool IsMediaGroup)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
Statistics statistics = new Statistics();
|
||||
return Ok(statistics.RecordSession(Guid.Empty, GameId, user.Id));
|
||||
return Ok(statistics.RecordSession(Guid.Empty, GameId, PlatformId, RomId, IsMediaGroup, user.Id));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -54,15 +54,15 @@ namespace gaseous_server.Controllers.v1_1
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("Games/{GameId}/{SessionId}")]
|
||||
public async Task<ActionResult> SubsequentRecordStatistics(long GameId, Guid SessionId)
|
||||
[Route("Games/{GameId}/{PlatformId}/{RomId}/{SessionId}")]
|
||||
public async Task<ActionResult> SubsequentRecordStatistics(long GameId, long PlatformId, long RomId, Guid SessionId, bool IsMediaGroup)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
Statistics statistics = new Statistics();
|
||||
return Ok(statistics.RecordSession(SessionId, GameId, user.Id));
|
||||
return Ok(statistics.RecordSession(SessionId, GameId, PlatformId, RomId, IsMediaGroup, user.Id));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
137
gaseous-server/Controllers/V1.1/UserProfileController.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using Asp.Versioning;
|
||||
using Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace gaseous_server.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Authorize]
|
||||
public class UserProfileController : ControllerBase
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
|
||||
public UserProfileController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager
|
||||
)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{UserId}")]
|
||||
[ProducesResponseType(typeof(Models.UserProfile), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
[ResponseCache(CacheProfileName = "5Minute")]
|
||||
public ActionResult GetUserProfile(string UserId)
|
||||
{
|
||||
Classes.UserProfile profile = new Classes.UserProfile();
|
||||
Models.UserProfile RetVal = profile.GetUserProfile(UserId);
|
||||
return Ok(RetVal);
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPut]
|
||||
[Route("{UserId}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult> UpdateUserProfileAsync(string UserId, Models.UserProfile profile)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user.ProfileId.ToString() != UserId)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
Classes.UserProfile userProfile = new Classes.UserProfile();
|
||||
userProfile.UpdateUserProfile(user.Id, profile);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPut]
|
||||
[ProducesResponseType(typeof(List<IFormFile>), StatusCodes.Status200OK)]
|
||||
[RequestSizeLimit(long.MaxValue)]
|
||||
[Consumes("multipart/form-data")]
|
||||
[DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, ValueLengthLimit = int.MaxValue)]
|
||||
[Route("{UserId}/{ProfileImageType}")]
|
||||
public async Task<ActionResult> UpdateAvatarAsync(string UserId, Classes.UserProfile.ImageType ProfileImageType, IFormFile file)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user.ProfileId.ToString() != UserId)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
if (file.Length > 0)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
file.CopyTo(ms);
|
||||
byte[] fileBytes = ms.ToArray();
|
||||
|
||||
Classes.UserProfile userProfile = new Classes.UserProfile();
|
||||
userProfile.UpdateImage(ProfileImageType, UserId, user.Id, file.FileName, fileBytes);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Route("{UserId}/{ProfileImageType}")]
|
||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ResponseCache(CacheProfileName = "5Minute")]
|
||||
public async Task<ActionResult> GetAvatarAsync(string UserId, Classes.UserProfile.ImageType ProfileImageType)
|
||||
{
|
||||
Classes.UserProfile userProfile = new Classes.UserProfile();
|
||||
|
||||
Models.ImageItem image = userProfile.GetImage(ProfileImageType, UserId);
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
return File(image.content, image.mimeType, UserId + image.extension);
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpDelete]
|
||||
[Route("{UserId}/{ProfileImageType}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
public async Task<ActionResult> DeleteAvatarAsync(string UserId, Classes.UserProfile.ImageType ProfileImageType)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user.ProfileId.ToString() != UserId)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
Classes.UserProfile userProfile = new Classes.UserProfile();
|
||||
userProfile.DeleteImage(ProfileImageType, user.Id);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
@@ -44,8 +44,6 @@ namespace gaseous_server.Models
|
||||
{
|
||||
Id = this.Cover.Id
|
||||
};
|
||||
|
||||
return cover;
|
||||
}
|
||||
}
|
||||
|
||||
|
9
gaseous-server/Models/ImageItem.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class ImageItem
|
||||
{
|
||||
public byte[] content { get; set; }
|
||||
public string mimeType { get; set; }
|
||||
public string extension { get; set; }
|
||||
}
|
||||
}
|
@@ -15,8 +15,6 @@ namespace gaseous_server.Models
|
||||
{
|
||||
public class PlatformMapping
|
||||
{
|
||||
private static Dictionary<string, PlatformMapItem> PlatformMapCache = new Dictionary<string, PlatformMapItem>();
|
||||
|
||||
/// <summary>
|
||||
/// Updates the platform map from the embedded platform map resource
|
||||
/// </summary>
|
||||
@@ -74,8 +72,8 @@ namespace gaseous_server.Models
|
||||
|
||||
foreach (PlatformMapItem mapItem in platforms)
|
||||
{
|
||||
// get the IGDB platform data
|
||||
Platform platform = Platforms.GetPlatform(mapItem.IGDBId, false);
|
||||
// insert dummy platform data - it'll be cleaned up on the first metadata refresh
|
||||
Platform platform = CreateDummyPlatform(mapItem);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -94,49 +92,57 @@ namespace gaseous_server.Models
|
||||
}
|
||||
}
|
||||
|
||||
private static IGDB.Models.Platform CreateDummyPlatform(PlatformMapItem mapItem)
|
||||
{
|
||||
IGDB.Models.Platform platform = new IGDB.Models.Platform
|
||||
{
|
||||
Id = mapItem.IGDBId,
|
||||
Name = mapItem.IGDBName,
|
||||
Slug = mapItem.IGDBSlug,
|
||||
AlternativeName = mapItem.AlternateNames.FirstOrDefault()
|
||||
};
|
||||
|
||||
if (Storage.GetCacheStatus("Platform", mapItem.IGDBId) == Storage.CacheStatus.NotPresent)
|
||||
{
|
||||
Storage.NewCacheValue(platform);
|
||||
}
|
||||
|
||||
return platform;
|
||||
}
|
||||
|
||||
public static List<PlatformMapItem> PlatformMap
|
||||
{
|
||||
get
|
||||
{
|
||||
// if (Database.DatabaseMemoryCache.GetCacheObject("PlatformMap") != null)
|
||||
// {
|
||||
// return (List<PlatformMapItem>)Database.DatabaseMemoryCache.GetCacheObject("PlatformMap");
|
||||
// }
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM PlatformMap";
|
||||
DataTable data = db.ExecuteCMD(sql);
|
||||
DataTable data = db.ExecuteCMD(sql); //, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromSeconds(5).Ticks));
|
||||
|
||||
List<PlatformMapItem> platformMaps = new List<PlatformMapItem>();
|
||||
foreach (DataRow row in data.Rows)
|
||||
{
|
||||
long mapId = (long)row["Id"];
|
||||
if (PlatformMapCache.ContainsKey(mapId.ToString()))
|
||||
{
|
||||
PlatformMapItem mapItem = PlatformMapCache[mapId.ToString()];
|
||||
if (mapItem != null)
|
||||
{
|
||||
platformMaps.Add(mapItem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
PlatformMapItem mapItem = BuildPlatformMapItem(row);
|
||||
if (mapItem != null)
|
||||
{
|
||||
platformMaps.Add(mapItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
platformMaps.Sort((x, y) => x.IGDBName.CompareTo(y.IGDBName));
|
||||
|
||||
//Database.DatabaseMemoryCache.SetCacheObject("PlatformMap", platformMaps, 600);
|
||||
|
||||
return platformMaps;
|
||||
}
|
||||
}
|
||||
|
||||
public static PlatformMapItem GetPlatformMap(long Id)
|
||||
{
|
||||
if (PlatformMapCache.ContainsKey(Id.ToString()))
|
||||
{
|
||||
return PlatformMapCache[Id.ToString()];
|
||||
}
|
||||
else
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT * FROM PlatformMap WHERE Id = @Id";
|
||||
@@ -157,10 +163,11 @@ namespace gaseous_server.Models
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void WritePlatformMap(PlatformMapItem item, bool Update, bool AllowAvailableEmulatorOverwrite)
|
||||
{
|
||||
CreateDummyPlatform(item);
|
||||
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||
@@ -239,20 +246,29 @@ namespace gaseous_server.Models
|
||||
{
|
||||
foreach (PlatformMapItem.EmulatorBiosItem biosItem in item.Bios)
|
||||
{
|
||||
sql = "INSERT INTO PlatformMap_Bios (Id, Filename, Description, Hash) VALUES (@Id, @Filename, @Description, @Hash);";
|
||||
bool isEnabled = false;
|
||||
if (item.EnabledBIOSHashes == null)
|
||||
{
|
||||
item.EnabledBIOSHashes = new List<string>();
|
||||
}
|
||||
if (item.EnabledBIOSHashes.Contains(biosItem.hash))
|
||||
{
|
||||
isEnabled = true;
|
||||
}
|
||||
|
||||
sql = "INSERT INTO PlatformMap_Bios (Id, Filename, Description, Hash, Enabled) VALUES (@Id, @Filename, @Description, @Hash, @Enabled);";
|
||||
dbDict.Clear();
|
||||
dbDict.Add("Id", item.IGDBId);
|
||||
dbDict.Add("Filename", biosItem.filename);
|
||||
dbDict.Add("Description", biosItem.description);
|
||||
dbDict.Add("Hash", biosItem.hash);
|
||||
dbDict.Add("Enabled", isEnabled);
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
}
|
||||
|
||||
if (PlatformMapCache.ContainsKey(item.IGDBId.ToString()))
|
||||
{
|
||||
PlatformMapCache.Remove(item.IGDBId.ToString());
|
||||
}
|
||||
// clear cache
|
||||
Database.DatabaseMemoryCache.RemoveCacheObject("PlatformMap");
|
||||
}
|
||||
|
||||
public static void WriteAvailableEmulators(PlatformMapItem item)
|
||||
@@ -287,7 +303,16 @@ namespace gaseous_server.Models
|
||||
string sql = "";
|
||||
|
||||
// get platform data
|
||||
IGDB.Models.Platform? platform = Platforms.GetPlatform(IGDBId, false);
|
||||
// IGDB.Models.Platform? platform = Platforms.GetPlatform(IGDBId, false);
|
||||
IGDB.Models.Platform? platform = null;
|
||||
if (Storage.GetCacheStatus("Platform", IGDBId) == Storage.CacheStatus.NotPresent)
|
||||
{
|
||||
//platform = Platforms.GetPlatform(IGDBId, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
platform = (IGDB.Models.Platform)Storage.GetCacheValue<IGDB.Models.Platform>(new Platform(), "id", IGDBId);
|
||||
}
|
||||
|
||||
if (platform != null)
|
||||
{
|
||||
@@ -353,6 +378,7 @@ namespace gaseous_server.Models
|
||||
DataTable biosTable = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
List<PlatformMapItem.EmulatorBiosItem> bioss = new List<PlatformMapItem.EmulatorBiosItem>();
|
||||
List<string> enabledBios = new List<string>();
|
||||
foreach (DataRow biosRow in biosTable.Rows)
|
||||
{
|
||||
PlatformMapItem.EmulatorBiosItem bios = new PlatformMapItem.EmulatorBiosItem
|
||||
@@ -362,6 +388,11 @@ namespace gaseous_server.Models
|
||||
hash = ((string)Common.ReturnValueIfNull(biosRow["Hash"], "")).ToLower()
|
||||
};
|
||||
bioss.Add(bios);
|
||||
|
||||
if ((bool)Common.ReturnValueIfNull(biosRow["Enabled"], true) == true)
|
||||
{
|
||||
enabledBios.Add(bios.hash);
|
||||
}
|
||||
}
|
||||
|
||||
// build item
|
||||
@@ -383,15 +414,7 @@ namespace gaseous_server.Models
|
||||
AvailableWebEmulators = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem.WebEmulatorItem.AvailableWebEmulatorItem>>((string)Common.ReturnValueIfNull(row["AvailableWebEmulators"], "[]"))
|
||||
};
|
||||
mapItem.Bios = bioss;
|
||||
|
||||
if (PlatformMapCache.ContainsKey(IGDBId.ToString()))
|
||||
{
|
||||
PlatformMapCache[IGDBId.ToString()] = mapItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
PlatformMapCache.Add(IGDBId.ToString(), mapItem);
|
||||
}
|
||||
mapItem.EnabledBIOSHashes = enabledBios;
|
||||
|
||||
return mapItem;
|
||||
}
|
||||
@@ -458,6 +481,74 @@ namespace gaseous_server.Models
|
||||
}
|
||||
}
|
||||
|
||||
public PlatformMapItem GetUserPlatformMap(string UserId, long PlatformId, long GameId)
|
||||
{
|
||||
// get the system enabled bios hashes
|
||||
Models.PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(PlatformId);
|
||||
|
||||
// get the user enabled bios hashes
|
||||
PlatformMapping.UserEmulatorConfiguration userEmulatorConfiguration = GetUserEmulator(UserId, GameId, PlatformId);
|
||||
if (userEmulatorConfiguration != null)
|
||||
{
|
||||
platformMapItem.WebEmulator.Type = userEmulatorConfiguration.EmulatorType;
|
||||
platformMapItem.WebEmulator.Core = userEmulatorConfiguration.Core;
|
||||
platformMapItem.EnabledBIOSHashes = userEmulatorConfiguration.EnableBIOSFiles;
|
||||
}
|
||||
|
||||
return platformMapItem;
|
||||
}
|
||||
|
||||
public UserEmulatorConfiguration GetUserEmulator(string UserId, long GameId, long PlatformId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT Mapping FROM User_PlatformMap WHERE id = @UserId AND GameId = @GameId AND PlatformId = @PlatformId;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "UserId", UserId },
|
||||
{ "GameId", GameId },
|
||||
{ "PlatformId", PlatformId }
|
||||
};
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (data.Rows.Count > 0)
|
||||
{
|
||||
UserEmulatorConfiguration emulator = Newtonsoft.Json.JsonConvert.DeserializeObject<UserEmulatorConfiguration>((string)data.Rows[0]["Mapping"]);
|
||||
|
||||
return emulator;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUserEmulator(string UserId, long GameId, long PlatformId, UserEmulatorConfiguration Mapping)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "INSERT INTO User_PlatformMap (id, GameId, PlatformId, Mapping) VALUES (@UserId, @GameId, @PlatformId, @Mapping) ON DUPLICATE KEY UPDATE Mapping = @Mapping;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "UserId", UserId },
|
||||
{ "GameId", GameId },
|
||||
{ "PlatformId", PlatformId },
|
||||
{ "Mapping", Newtonsoft.Json.JsonConvert.SerializeObject(Mapping) }
|
||||
};
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
|
||||
public void DeleteUserEmulator(string UserId, long GameId, long PlatformId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "DELETE FROM User_PlatformMap WHERE id = @UserId AND GameId = @GameId AND PlatformId = @PlatformId;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "UserId", UserId },
|
||||
{ "GameId", GameId },
|
||||
{ "PlatformId", PlatformId }
|
||||
};
|
||||
db.ExecuteCMD(sql, dbDict);
|
||||
}
|
||||
|
||||
public class PlatformMapItem
|
||||
{
|
||||
public long IGDBId { get; set; }
|
||||
@@ -505,6 +596,15 @@ namespace gaseous_server.Models
|
||||
public string description { get; set; }
|
||||
public string filename { get; set; }
|
||||
}
|
||||
|
||||
public List<string> EnabledBIOSHashes { get; set; }
|
||||
}
|
||||
|
||||
public class UserEmulatorConfiguration
|
||||
{
|
||||
public string EmulatorType { get; set; }
|
||||
public string Core { get; set; }
|
||||
public List<string> EnableBIOSFiles { get; set; } = new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,12 +4,36 @@ using gaseous_signature_parser.models.RomSignatureObject;
|
||||
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class Signatures_Games : HasheousClient.Models.LookupResponseModel
|
||||
public class Signatures_Games : HasheousClient.Models.SignatureModel
|
||||
{
|
||||
public Signatures_Games()
|
||||
{
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public int Score
|
||||
{
|
||||
get
|
||||
{
|
||||
int _score = 0;
|
||||
|
||||
if (Game != null)
|
||||
{
|
||||
_score = _score + Game.Score;
|
||||
}
|
||||
|
||||
if (Rom != null)
|
||||
{
|
||||
_score = _score + Rom.Score;
|
||||
}
|
||||
|
||||
return _score;
|
||||
}
|
||||
}
|
||||
|
||||
public GameItem Game = new GameItem();
|
||||
public RomItem Rom = new RomItem();
|
||||
|
||||
public SignatureFlags Flags = new SignatureFlags();
|
||||
|
||||
public class SignatureFlags
|
||||
@@ -18,5 +42,213 @@ namespace gaseous_server.Models
|
||||
public string IGDBPlatformName { get; set; }
|
||||
public long IGDBGameId { get; set; }
|
||||
}
|
||||
|
||||
public class GameItem : HasheousClient.Models.SignatureModel.GameItem
|
||||
{
|
||||
public GameItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public int Score
|
||||
{
|
||||
get
|
||||
{
|
||||
// calculate a score based on the availablility of data
|
||||
int _score = 0;
|
||||
var properties = this.GetType().GetProperties();
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
if (prop.GetGetMethod() != null)
|
||||
{
|
||||
switch (prop.Name.ToLower())
|
||||
{
|
||||
case "id":
|
||||
case "score":
|
||||
break;
|
||||
case "name":
|
||||
case "year":
|
||||
case "publisher":
|
||||
case "system":
|
||||
if (prop.PropertyType == typeof(string))
|
||||
{
|
||||
if (prop.GetValue(this) != null)
|
||||
{
|
||||
string propVal = prop.GetValue(this).ToString();
|
||||
if (propVal.Length > 0)
|
||||
{
|
||||
_score = _score + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (prop.PropertyType == typeof(string))
|
||||
{
|
||||
if (prop.GetValue(this) != null)
|
||||
{
|
||||
string propVal = prop.GetValue(this).ToString();
|
||||
if (propVal.Length > 0)
|
||||
{
|
||||
_score = _score + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class RomItem : HasheousClient.Models.SignatureModel.RomItem
|
||||
{
|
||||
[JsonIgnore]
|
||||
public int Score
|
||||
{
|
||||
get
|
||||
{
|
||||
// calculate a score based on the availablility of data
|
||||
int _score = 0;
|
||||
var properties = this.GetType().GetProperties();
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
if (prop.GetGetMethod() != null)
|
||||
{
|
||||
switch (prop.Name.ToLower())
|
||||
{
|
||||
case "name":
|
||||
case "size":
|
||||
case "crc":
|
||||
case "developmentstatus":
|
||||
case "flags":
|
||||
case "attributes":
|
||||
case "romtypemedia":
|
||||
case "medialabel":
|
||||
if (prop.PropertyType == typeof(string) || prop.PropertyType == typeof(Int64) || prop.PropertyType == typeof(List<string>))
|
||||
{
|
||||
if (prop.GetValue(this) != null)
|
||||
{
|
||||
string propVal = prop.GetValue(this).ToString();
|
||||
if (propVal.Length > 0)
|
||||
{
|
||||
_score = _score + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (prop.PropertyType == typeof(string))
|
||||
{
|
||||
if (prop.GetValue(this) != null)
|
||||
{
|
||||
string propVal = prop.GetValue(this).ToString();
|
||||
if (propVal.Length > 0)
|
||||
{
|
||||
_score = _score + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _score;
|
||||
}
|
||||
}
|
||||
|
||||
public class MediaType
|
||||
{
|
||||
public MediaType(SignatureSourceType Source, string MediaTypeString)
|
||||
{
|
||||
switch (Source)
|
||||
{
|
||||
case RomItem.SignatureSourceType.TOSEC:
|
||||
string[] typeString = MediaTypeString.Split(" ");
|
||||
|
||||
string inType = "";
|
||||
foreach (string typeStringVal in typeString)
|
||||
{
|
||||
if (inType == "")
|
||||
{
|
||||
switch (typeStringVal.ToLower())
|
||||
{
|
||||
case "disk":
|
||||
Media = RomItem.RomTypes.Disk;
|
||||
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "disc":
|
||||
Media = RomItem.RomTypes.Disc;
|
||||
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "file":
|
||||
Media = RomItem.RomTypes.File;
|
||||
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "part":
|
||||
Media = RomItem.RomTypes.Part;
|
||||
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "tape":
|
||||
Media = RomItem.RomTypes.Tape;
|
||||
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "of":
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
case "side":
|
||||
inType = typeStringVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (inType.ToLower())
|
||||
{
|
||||
case "disk":
|
||||
case "disc":
|
||||
case "file":
|
||||
case "part":
|
||||
case "tape":
|
||||
Number = int.Parse(typeStringVal);
|
||||
break;
|
||||
case "of":
|
||||
Count = int.Parse(typeStringVal);
|
||||
break;
|
||||
case "side":
|
||||
Side = typeStringVal;
|
||||
break;
|
||||
}
|
||||
inType = "";
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public RomItem.RomTypes? Media { get; set; }
|
||||
|
||||
public int? Number { get; set; }
|
||||
|
||||
public int? Count { get; set; }
|
||||
|
||||
public string? Side { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
20
gaseous-server/Models/Signatures_Sources.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using NuGet.Protocol.Core.Types;
|
||||
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class Signatures_Sources
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string URL { get; set; }
|
||||
public string Category { get; set; }
|
||||
public string Version { get; set; }
|
||||
public string Author { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Homepage { get; set; }
|
||||
public gaseous_signature_parser.parser.SignatureParser SourceType { get; set; }
|
||||
public string MD5 { get; set; }
|
||||
public string SHA1 { get; set; }
|
||||
}
|
||||
}
|
17
gaseous-server/Models/UserProfile.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class UserProfile
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string Quip { get; set; }
|
||||
public ProfileImageItem? Avatar { get; set; }
|
||||
public ProfileImageItem? ProfileBackground { get; set; }
|
||||
public Dictionary<string, object> Data { get; set; }
|
||||
public class ProfileImageItem
|
||||
{
|
||||
public string MimeType { get; set; }
|
||||
public string Extension { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -245,14 +245,32 @@ namespace gaseous_server
|
||||
CallingQueueItem = this
|
||||
};
|
||||
|
||||
Logging.Log(Logging.LogType.Debug, "Signature Import", "Processing TOSEC files");
|
||||
tIngest.Import(Path.Combine(Config.LibraryConfiguration.LibrarySignatureImportDirectory, "TOSEC"), gaseous_signature_parser.parser.SignatureParser.TOSEC);
|
||||
foreach (int i in Enum.GetValues(typeof(gaseous_signature_parser.parser.SignatureParser)))
|
||||
{
|
||||
gaseous_signature_parser.parser.SignatureParser parserType = (gaseous_signature_parser.parser.SignatureParser)i;
|
||||
if (
|
||||
parserType != gaseous_signature_parser.parser.SignatureParser.Auto &&
|
||||
parserType != gaseous_signature_parser.parser.SignatureParser.Unknown
|
||||
)
|
||||
{
|
||||
Logging.Log(Logging.LogType.Debug, "Signature Import", "Processing " + parserType + " files");
|
||||
|
||||
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);
|
||||
string SignaturePath = Path.Combine(Config.LibraryConfiguration.LibrarySignaturesDirectory, parserType.ToString());
|
||||
string SignatureProcessedPath = Path.Combine(Config.LibraryConfiguration.LibrarySignaturesProcessedDirectory, parserType.ToString());
|
||||
|
||||
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);
|
||||
if (!Directory.Exists(SignaturePath))
|
||||
{
|
||||
Directory.CreateDirectory(SignaturePath);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(SignatureProcessedPath))
|
||||
{
|
||||
Directory.CreateDirectory(SignatureProcessedPath);
|
||||
}
|
||||
|
||||
tIngest.Import(SignaturePath, SignatureProcessedPath, parserType);
|
||||
}
|
||||
}
|
||||
|
||||
_SaveLastRunTime = true;
|
||||
|
||||
@@ -350,8 +368,7 @@ 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();
|
||||
@@ -362,8 +379,7 @@ 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();
|
||||
|
@@ -45,10 +45,6 @@ AgeRatings.PopulateAgeMap();
|
||||
|
||||
// load app settings
|
||||
Config.InitSettings();
|
||||
|
||||
// disable hasheous
|
||||
Config.MetadataConfiguration.SignatureSource = HasheousClient.Models.MetadataModel.SignatureSources.LocalOnly;
|
||||
|
||||
// write updated settings back to the config file
|
||||
Config.UpdateConfig();
|
||||
|
||||
@@ -71,13 +67,14 @@ if (Directory.Exists(Config.LibraryConfiguration.LibraryUploadDirectory))
|
||||
// kick off any delayed upgrade tasks
|
||||
// run 1002 background updates in the background on every start
|
||||
DatabaseMigration.BackgroundUpgradeTargetSchemaVersions.Add(1002);
|
||||
DatabaseMigration.BackgroundUpgradeTargetSchemaVersions.Add(1023);
|
||||
// start the task
|
||||
ProcessQueue.QueueItem queueItem = new ProcessQueue.QueueItem(
|
||||
ProcessQueue.QueueItemType.BackgroundDatabaseUpgrade,
|
||||
1,
|
||||
new List<ProcessQueue.QueueItemType>
|
||||
{
|
||||
ProcessQueue.QueueItemType.All
|
||||
ProcessQueue.QueueItemType.SignatureIngestor
|
||||
},
|
||||
false,
|
||||
true
|
||||
@@ -326,72 +323,6 @@ app.Use(async (context, next) =>
|
||||
await next();
|
||||
});
|
||||
|
||||
// emergency password recovery if environment variable is set
|
||||
// process:
|
||||
// - set the environment variable "recoveraccount" to the email address of the account to be recovered
|
||||
// - when the server starts the password will be reset to a random string and saved in the library
|
||||
// directory with the name RecoverAccount.txt
|
||||
// - user should copy this password and remove the "recoveraccount" environment variable and the
|
||||
// RecoverAccount.txt file
|
||||
// - the server will not start while the RecoverAccount.txt file exists
|
||||
string PasswordRecoveryFile = Path.Combine(Config.LibraryConfiguration.LibraryRootDirectory, "RecoverAccount.txt");
|
||||
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("recoveraccount")))
|
||||
{
|
||||
if (File.Exists(PasswordRecoveryFile))
|
||||
{
|
||||
// password has already been set - do nothing and just exit
|
||||
Logging.Log(Logging.LogType.Critical, "Server Startup", "Unable to start while recoveraccount environment varibale is set and RecoverAccount.txt file exists.", null, true);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// generate and save the password to disk
|
||||
int length = 10;
|
||||
string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+";
|
||||
var random = new Random();
|
||||
string password = new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
|
||||
|
||||
File.WriteAllText(PasswordRecoveryFile, password);
|
||||
|
||||
// reset the password
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var userManager = scope.ServiceProvider.GetRequiredService<UserStore>();
|
||||
if (await userManager.FindByNameAsync(Environment.GetEnvironmentVariable("recoveraccount"), CancellationToken.None) != null)
|
||||
{
|
||||
ApplicationUser User = await userManager.FindByEmailAsync(Environment.GetEnvironmentVariable("recoveraccount"), CancellationToken.None);
|
||||
|
||||
//set user password
|
||||
PasswordHasher<ApplicationUser> ph = new PasswordHasher<ApplicationUser>();
|
||||
User.PasswordHash = ph.HashPassword(User, password);
|
||||
|
||||
await userManager.SetPasswordHashAsync(User, User.PasswordHash, CancellationToken.None);
|
||||
|
||||
Logging.Log(Logging.LogType.Information, "Server Startup", "Password reset complete, remove the recoveraccount environment variable and RecoverAccount.text file to allow server start.", null, true);
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Log(Logging.LogType.Critical, "Server Startup", "Account to recover not found.", null, true);
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if RecoverAccount.text file is present
|
||||
if (File.Exists(PasswordRecoveryFile))
|
||||
{
|
||||
// cannot start while password recovery file exists
|
||||
Logging.Log(Logging.LogType.Critical, "Server Startup", "Unable to start while RecoverAccount.txt file exists. Remove the file and try again.", null, true);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// setup library directories
|
||||
Config.LibraryConfiguration.InitLibrary();
|
||||
|
||||
@@ -404,9 +335,6 @@ gaseous_server.Classes.Metadata.Platforms.AssignAllPlatformsToGameIdZero();
|
||||
// extract platform map if not present
|
||||
PlatformMapping.ExtractPlatformMap();
|
||||
|
||||
// force load platform map into cache
|
||||
var platformMap = PlatformMapping.PlatformMap;
|
||||
|
||||
// add background tasks
|
||||
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
||||
ProcessQueue.QueueItemType.SignatureIngestor)
|
||||
|
73
gaseous-server/Support/Country.txt
Normal file
@@ -0,0 +1,73 @@
|
||||
AE|United Arab Emirates
|
||||
AL|Albania
|
||||
AS|Asia
|
||||
AT|Austria
|
||||
AU|Australia
|
||||
BA|Bosnia and Herzegovina
|
||||
BE|Belgium
|
||||
BG|Bulgaria
|
||||
BR|Brazil
|
||||
CA|Canada
|
||||
CH|Switzerland
|
||||
CL|Chile
|
||||
CN|China
|
||||
CS|Serbia and Montenegro
|
||||
CY|Cyprus
|
||||
CZ|Czech Republic
|
||||
DE|Germany
|
||||
DK|Denmark
|
||||
EE|Estonia
|
||||
EG|Egypt
|
||||
ES|Spain
|
||||
EU|Europe
|
||||
FI|Finland
|
||||
FR|France
|
||||
GB|United Kingdom
|
||||
GR|Greece
|
||||
HK|Hong Kong
|
||||
HR|Croatia
|
||||
HU|Hungary
|
||||
ID|Indonesia
|
||||
IE|Ireland
|
||||
IL|Israel
|
||||
IN|India
|
||||
IR|Iran
|
||||
IS|Iceland
|
||||
IT|Italy
|
||||
JO|Jordan
|
||||
JP|Japan
|
||||
KR|Korea
|
||||
KR|South Korea
|
||||
LT|Lithuania
|
||||
LU|Luxembourg
|
||||
LV|Latvia
|
||||
MN|Mongolia
|
||||
MX|Mexico
|
||||
MY|Malaysia
|
||||
NL|Netherlands
|
||||
NO|Norway
|
||||
NP|Nepal
|
||||
NZ|New Zealand
|
||||
OM|Oman
|
||||
PE|Peru
|
||||
PH|Philippines
|
||||
PL|Poland
|
||||
PT|Portugal
|
||||
QA|Qatar
|
||||
RO|Romania
|
||||
RU|Russia
|
||||
SE|Sweden
|
||||
SG|Singapore
|
||||
SI|Slovenia
|
||||
SK|Slovakia
|
||||
TH|Thailand
|
||||
TR|Turkey
|
||||
TW|Taiwan
|
||||
US|United States
|
||||
USA|United States
|
||||
VN|Vietnam
|
||||
YU|Yugoslavia
|
||||
ZA|South Africa
|
||||
World|World
|
||||
Europe|Europe
|
||||
Asia|Asia
|
17
gaseous-server/Support/Database/MySQL/gaseous-1023.sql
Normal file
@@ -0,0 +1,17 @@
|
||||
CREATE TABLE `Country` (
|
||||
`Id` INT NOT NULL AUTO_INCREMENT,
|
||||
`Code` VARCHAR(20) NULL,
|
||||
`Value` VARCHAR(255) NULL,
|
||||
PRIMARY KEY (`Id`),
|
||||
INDEX `id_Code` (`Code` ASC) VISIBLE,
|
||||
INDEX `id_Value` (`Value` ASC) VISIBLE
|
||||
);
|
||||
|
||||
CREATE TABLE `Language` (
|
||||
`Id` INT NOT NULL AUTO_INCREMENT,
|
||||
`Code` VARCHAR(20) NULL,
|
||||
`Value` VARCHAR(255) NULL,
|
||||
PRIMARY KEY (`Id`),
|
||||
INDEX `id_Code` (`Code` ASC) VISIBLE,
|
||||
INDEX `id_Value` (`Value` ASC) VISIBLE
|
||||
);
|
79
gaseous-server/Support/Database/MySQL/gaseous-1024.sql
Normal file
@@ -0,0 +1,79 @@
|
||||
CREATE TABLE `Signatures_RomToSource` (
|
||||
`SourceId` int NOT NULL,
|
||||
`RomId` int NOT NULL,
|
||||
PRIMARY KEY (`SourceId`, `RomId`)
|
||||
);
|
||||
|
||||
CREATE TABLE `Signatures_Games_Countries` (
|
||||
`GameId` INT NOT NULL,
|
||||
`CountryId` INT NOT NULL,
|
||||
PRIMARY KEY (`GameId`, `CountryId`),
|
||||
CONSTRAINT `GameCountry` FOREIGN KEY (`GameId`) REFERENCES `Signatures_Games` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
);
|
||||
|
||||
CREATE TABLE `Signatures_Games_Languages` (
|
||||
`GameId` INT NOT NULL,
|
||||
`LanguageId` INT NOT NULL,
|
||||
PRIMARY KEY (`GameId`, `LanguageId`),
|
||||
CONSTRAINT `GameLanguage` FOREIGN KEY (`GameId`) REFERENCES `Signatures_Games` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
);
|
||||
|
||||
ALTER TABLE `Games_Roms` ADD COLUMN `RomDataVersion` INT DEFAULT 1;
|
||||
|
||||
CREATE TABLE UserProfiles (
|
||||
`Id` VARCHAR(45) NOT NULL,
|
||||
`UserId` VARCHAR(45) NOT NULL,
|
||||
`DisplayName` VARCHAR(255) NOT NULL,
|
||||
`Quip` VARCHAR(255) NOT NULL,
|
||||
`Avatar` LONGBLOB,
|
||||
`AvatarExtension` CHAR(6),
|
||||
`ProfileBackground` LONGBLOB,
|
||||
`ProfileBackgroundExtension` CHAR(6),
|
||||
`UnstructuredData` LONGTEXT NOT NULL,
|
||||
PRIMARY KEY (`Id`, `UserId`)
|
||||
);
|
||||
|
||||
ALTER TABLE `PlatformMap_Bios`
|
||||
ADD COLUMN `Enabled` BOOLEAN DEFAULT TRUE;
|
||||
|
||||
CREATE TABLE `User_PlatformMap` (
|
||||
`id` VARCHAR(128) NOT NULL,
|
||||
`GameId` BIGINT NOT NULL,
|
||||
`PlatformId` BIGINT NOT NULL,
|
||||
`Mapping` LONGTEXT,
|
||||
PRIMARY KEY (`id`, `GameId`, `PlatformId`),
|
||||
CONSTRAINT `User_PlatformMap_UserId` FOREIGN KEY (`id`) REFERENCES `Users` (`Id`) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
ALTER TABLE `UserTimeTracking`
|
||||
ADD COLUMN `PlatformId` BIGINT,
|
||||
ADD COLUMN `IsMediaGroup` BOOLEAN DEFAULT FALSE,
|
||||
ADD COLUMN `RomId` BIGINT;
|
||||
|
||||
CREATE TABLE `User_RecentPlayedRoms` (
|
||||
`UserId` varchar(128) NOT NULL,
|
||||
`GameId` bigint(20) NOT NULL,
|
||||
`PlatformId` bigint(20) NOT NULL,
|
||||
`RomId` bigint(20) NOT NULL,
|
||||
`IsMediaGroup` tinyint(1) DEFAULT NULL,
|
||||
PRIMARY KEY (
|
||||
`UserId`,
|
||||
`GameId`,
|
||||
`PlatformId`
|
||||
),
|
||||
CONSTRAINT `RecentPlayedRoms_Users` FOREIGN KEY (`UserId`) REFERENCES `Users` (`Id`) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE `User_GameFavouriteRoms` (
|
||||
`UserId` varchar(128) NOT NULL,
|
||||
`GameId` bigint(20) NOT NULL,
|
||||
`PlatformId` bigint(20) NOT NULL,
|
||||
`RomId` bigint(20) NOT NULL,
|
||||
`IsMediaGroup` tinyint(1) DEFAULT NULL,
|
||||
PRIMARY KEY (
|
||||
`UserId`,
|
||||
`GameId`,
|
||||
`PlatformId`
|
||||
),
|
||||
CONSTRAINT `GameFavouriteRoms_Users` FOREIGN KEY (`UserId`) REFERENCES `Users` (`Id`) ON DELETE CASCADE
|
||||
);
|
47
gaseous-server/Support/Language.txt
Normal file
@@ -0,0 +1,47 @@
|
||||
ar|Arabic
|
||||
bg|Bulgarian
|
||||
bs|Bosnian
|
||||
cs|Czech
|
||||
cy|Welsh
|
||||
da|Danish
|
||||
de|German
|
||||
el|Greek
|
||||
en|English
|
||||
eo|Esperanto
|
||||
es|Spanish
|
||||
et|Estonian
|
||||
fa|Persian
|
||||
fi|Finnish
|
||||
fr|French
|
||||
fr-ca|French Canadian
|
||||
ga|Irish
|
||||
gd|Gaelic
|
||||
gu|Gujarati
|
||||
he|Hebrew
|
||||
hi|Hindi
|
||||
hr|Croatian
|
||||
hu|Hungarian
|
||||
is|Icelandic
|
||||
it|Italian
|
||||
ja|Japanese
|
||||
ko|Korean
|
||||
lt|Lithuanian
|
||||
lv|Latvian
|
||||
ms|Malay
|
||||
nl|Dutch
|
||||
no|Norwegian
|
||||
pl|Polish
|
||||
pt|Portuguese
|
||||
ro|Romanian
|
||||
ru|Russian
|
||||
sk|Slovakian
|
||||
sl|Slovenian
|
||||
sq|Albanian
|
||||
sr|Serbian
|
||||
sv|Swedish
|
||||
th|Thai
|
||||
tr|Turkish
|
||||
ur|Urdu
|
||||
vi|Vietnamese
|
||||
yi|Yiddish
|
||||
zh|Chinese
|
@@ -16,20 +16,20 @@
|
||||
<DocumentationFile>bin\Release\net8.0\gaseous-server.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Asp.Versioning.Mvc" Version="8.0.0" />
|
||||
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.0.0" />
|
||||
<PackageReference Include="gaseous-signature-parser" Version="2.1.0" />
|
||||
<PackageReference Include="Asp.Versioning.Mvc" Version="8.1.0" />
|
||||
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
|
||||
<PackageReference Include="gaseous-signature-parser" Version="2.2.1" />
|
||||
<PackageReference Include="gaseous.IGDB" Version="1.0.2" />
|
||||
<PackageReference Include="hasheous-client" Version="0.1.0" />
|
||||
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="13.5.0" />
|
||||
<PackageReference Include="sharpcompress" Version="0.36.0" />
|
||||
<PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.1.23" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.3.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.1" />
|
||||
<PackageReference Include="hasheous-client" Version="1.0.2" />
|
||||
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.0.0" />
|
||||
<PackageReference Include="sharpcompress" Version="0.37.2" />
|
||||
<PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.2.24" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.1" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.3.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -39,6 +39,8 @@
|
||||
<None Remove="Classes\" />
|
||||
<None Remove="Classes\SignatureIngestors\" />
|
||||
<None Remove="Support\" />
|
||||
<None Remove="Support\Country.txt" />
|
||||
<None Remove="Support\Language.txt" />
|
||||
<None Remove="Support\Database\" />
|
||||
<None Remove="Support\Database\MySQL\" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1000.sql" />
|
||||
@@ -65,6 +67,8 @@
|
||||
<None Remove="Support\Database\MySQL\gaseous-1020.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1021.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1022.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1023.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1024.sql" />
|
||||
<None Remove="Classes\Metadata\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -86,6 +90,8 @@
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Support\Country.txt" />
|
||||
<EmbeddedResource Include="Support\Language.txt" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1000.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1001.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1002.sql" />
|
||||
@@ -110,5 +116,7 @@
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1020.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1021.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1022.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1023.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1024.sql" />
|
||||
</ItemGroup>
|
||||
</Project>
|
BIN
gaseous-server/wwwroot/.DS_Store
vendored
@@ -22,9 +22,11 @@
|
||||
if (StateUrl) {
|
||||
console.log('Loading saved state from: ' + StateUrl);
|
||||
EJS_loadStateURL = StateUrl;
|
||||
EJS_startOnLoaded = true;
|
||||
}
|
||||
|
||||
// start the emulator automatically when loaded
|
||||
EJS_startOnLoaded = true;
|
||||
|
||||
// Path to the data directory
|
||||
EJS_pathtodata = '/emulators/EmulatorJS/data/';
|
||||
|
||||
@@ -42,10 +44,11 @@
|
||||
|
||||
EJS_Buttons = {
|
||||
saveSavFiles: false,
|
||||
loadSavFiles: false
|
||||
loadSavFiles: false,
|
||||
exitEmulation: false
|
||||
}
|
||||
|
||||
EJS_onSaveState = function(e) {
|
||||
EJS_onSaveState = function (e) {
|
||||
var returnValue = {
|
||||
"ScreenshotByteArrayBase64": btoa(Uint8ToString(e.screenshot)),
|
||||
"StateByteArrayBase64": btoa(Uint8ToString(e.state))
|
||||
@@ -72,8 +75,12 @@
|
||||
returnValue = undefined;
|
||||
}
|
||||
|
||||
EJS_onLoadState = function(e) {
|
||||
showDialog('emulatorloadstate', { "romId": romId, "IsMediaGroup": IsMediaGroup });
|
||||
EJS_onLoadState = function (e) {
|
||||
let rompath = decodeURIComponent(getQueryString('rompath', 'string'));
|
||||
rompath = rompath.substring(rompath.lastIndexOf('/') + 1);
|
||||
console.log(rompath);
|
||||
let stateManager = new EmulatorStateManager(romId, IsMediaGroup, getQueryString('engine', 'string'), getQueryString('core', 'string'), platformId, gameId, rompath);
|
||||
stateManager.open();
|
||||
}
|
||||
</script>
|
||||
<script src='/emulators/EmulatorJS/data/loader.js'></script>
|
16
gaseous-server/wwwroot/images/Critical.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>stop-warning</title>
|
||||
<g id="Layer_2" data-name="Layer 2">
|
||||
<g id="invisible_box" data-name="invisible box">
|
||||
<rect width="48" height="48" fill="none"/>
|
||||
</g>
|
||||
<g id="icons_Q2" data-name="icons Q2">
|
||||
<g>
|
||||
<path d="M43.4,15.1,32.9,4.6A2,2,0,0,0,31.5,4h-15a2,2,0,0,0-1.4.6L4.6,15.1A2,2,0,0,0,4,16.5v15a2,2,0,0,0,.6,1.4L15.1,43.4a2,2,0,0,0,1.4.6h15a2,2,0,0,0,1.4-.6L43.4,32.9a2,2,0,0,0,.6-1.4v-15A2,2,0,0,0,43.4,15.1ZM40,30.6,30.6,40H17.4L8,30.6V17.4L17.4,8H30.6L40,17.4Z"/>
|
||||
<path d="M26.8,24l5.6-5.6a2,2,0,0,0-2.8-2.8L24,21.2l-5.6-5.6a2,2,0,0,0-2.8,2.8L21.2,24l-5.6,5.6a1.9,1.9,0,0,0,0,2.8,1.9,1.9,0,0,0,2.8,0L24,26.8l5.6,5.6a1.9,1.9,0,0,0,2.8,0,1.9,1.9,0,0,0,0-2.8Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
After Width: | Height: | Size: 969 B |
8
gaseous-server/wwwroot/images/NoIntro-logo.svg
Normal file
After Width: | Height: | Size: 480 KiB |
1
gaseous-server/wwwroot/images/Ratings/ESRB/EC.svg
Normal file
After Width: | Height: | Size: 8.3 KiB |
17
gaseous-server/wwwroot/images/Warning.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>warning</title>
|
||||
<g id="Layer_2" data-name="Layer 2">
|
||||
<g id="invisible_box" data-name="invisible box">
|
||||
<rect width="48" height="48" fill="none"/>
|
||||
</g>
|
||||
<g id="icons_Q2" data-name="icons Q2">
|
||||
<g>
|
||||
<path d="M24,9,40.6,39H7.5L24,9M2.3,40A2,2,0,0,0,4,43H44a2,2,0,0,0,1.7-3L25.7,4a2,2,0,0,0-3.4,0Z"/>
|
||||
<path d="M22,19v9a2,2,0,0,0,4,0V19a2,2,0,0,0-4,0Z"/>
|
||||
<circle cx="24" cy="34" r="2"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
After Width: | Height: | Size: 695 B |
12
gaseous-server/wwwroot/images/arrow-down.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 512.011 512.011" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M505.755,123.592c-8.341-8.341-21.824-8.341-30.165,0L256.005,343.176L36.421,123.592c-8.341-8.341-21.824-8.341-30.165,0
|
||||
s-8.341,21.824,0,30.165l234.667,234.667c4.16,4.16,9.621,6.251,15.083,6.251c5.462,0,10.923-2.091,15.083-6.251l234.667-234.667
|
||||
C514.096,145.416,514.096,131.933,505.755,123.592z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 684 B |
12
gaseous-server/wwwroot/images/arrow-left.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 512.006 512.006" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M388.419,475.59L168.834,256.005L388.418,36.421c8.341-8.341,8.341-21.824,0-30.165s-21.824-8.341-30.165,0
|
||||
L123.586,240.923c-8.341,8.341-8.341,21.824,0,30.165l234.667,234.667c4.16,4.16,9.621,6.251,15.083,6.251
|
||||
c5.461,0,10.923-2.091,15.083-6.251C396.76,497.414,396.76,483.931,388.419,475.59z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 679 B |
12
gaseous-server/wwwroot/images/arrow-right.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 512.005 512.005" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M388.418,240.923L153.751,6.256c-8.341-8.341-21.824-8.341-30.165,0s-8.341,21.824,0,30.165L343.17,256.005
|
||||
L123.586,475.589c-8.341,8.341-8.341,21.824,0,30.165c4.16,4.16,9.621,6.251,15.083,6.251c5.461,0,10.923-2.091,15.083-6.251
|
||||
l234.667-234.667C396.759,262.747,396.759,249.264,388.418,240.923z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 682 B |
11
gaseous-server/wwwroot/images/arrow-up.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 512 512" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M505.752,358.248L271.085,123.582c-8.331-8.331-21.839-8.331-30.17,0L6.248,358.248c-8.331,8.331-8.331,21.839,0,30.17
|
||||
s21.839,8.331,30.17,0L256,168.837l219.582,219.582c8.331,8.331,21.839,8.331,30.17,0S514.083,366.58,505.752,358.248z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 609 B |
69
gaseous-server/wwwroot/images/bios.svg
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 512 512" xml:space="preserve">
|
||||
<g>
|
||||
<rect x="342.232" y="460.8" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||
<rect x="234.442" y="460.8" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||
<rect x="126.653" y="460.8" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||
<rect x="8.084" y="234.442" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||
<rect x="8.084" y="342.232" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||
<rect x="460.8" y="342.232" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||
<rect x="460.8" y="234.442" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||
<rect x="460.8" y="126.653" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||
<rect x="342.232" y="13.474" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||
<rect x="234.442" y="13.474" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||
<rect x="126.653" y="13.474" style="fill:#AFB6BB;" width="43.116" height="37.726"/>
|
||||
<rect x="8.084" y="126.653" style="fill:#AFB6BB;" width="43.116" height="43.116"/>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="51.2" y="126.653" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||
<rect x="51.2" y="234.442" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||
<rect x="51.2" y="342.232" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||
<rect x="126.653" y="428.463" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||
<rect x="234.442" y="428.463" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||
<rect x="342.232" y="428.463" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||
<rect x="428.463" y="342.232" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||
<rect x="428.463" y="234.442" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||
<rect x="428.463" y="126.653" style="fill:#E7ECED;" width="32.337" height="43.116"/>
|
||||
<rect x="342.232" y="51.2" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||
<rect x="234.442" y="51.2" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||
<rect x="126.653" y="51.2" style="fill:#E7ECED;" width="43.116" height="32.337"/>
|
||||
</g>
|
||||
<path style="fill:#595E62;" d="M428.463,385.347v32.337c0,5.928-4.851,10.779-10.779,10.779h-32.337h-43.116h-64.674h-43.116
|
||||
h-64.674h-43.116H94.316c-5.928,0-10.779-4.851-10.779-10.779v-32.337v-43.116v-64.674v-43.116v-64.674v-43.116V94.316
|
||||
c0-5.928,4.851-10.779,10.779-10.779h32.337h43.116h64.674h43.116h64.674h43.116h32.337c5.928,0,10.779,4.851,10.779,10.779v32.337
|
||||
v43.116v64.674v43.116v64.674V385.347z M385.347,385.347V126.653H126.653v258.695H385.347z"/>
|
||||
<rect x="126.653" y="126.653" style="fill:#36C63F;" width="258.695" height="258.695"/>
|
||||
<path style="fill:#00AB4E;" d="M173.785,126.653h-47.132v258.695h258.695v-47.132C284.709,306.659,205.341,227.291,173.785,126.653z
|
||||
"/>
|
||||
<path style="fill:#44494C;" d="M126.653,385.347V126.653H256V83.537h-21.558h-64.674h-43.116H94.316
|
||||
c-5.928,0-10.779,4.851-10.779,10.779v32.337v43.116v64.674v43.116v64.674v43.116v32.337c0,5.928,4.851,10.779,10.779,10.779h32.337
|
||||
h43.116h64.674H256v-43.116H126.653z"/>
|
||||
<g>
|
||||
<rect x="180.547" y="161.684" style="fill:#FFFFFF;" width="150.905" height="16.168"/>
|
||||
<rect x="180.547" y="237.137" style="fill:#FFFFFF;" width="150.905" height="16.168"/>
|
||||
<rect x="180.547" y="199.411" style="fill:#FFFFFF;" width="26.947" height="16.168"/>
|
||||
<rect x="180.547" y="334.147" style="fill:#FFFFFF;" width="26.947" height="16.168"/>
|
||||
<rect x="223.663" y="334.147" style="fill:#FFFFFF;" width="26.947" height="16.168"/>
|
||||
<rect x="299.116" y="334.147" style="fill:#FFFFFF;" width="26.947" height="16.168"/>
|
||||
<rect x="239.832" y="199.411" style="fill:#FFFFFF;" width="91.621" height="16.168"/>
|
||||
</g>
|
||||
<path d="M118.568,393.432h274.863V118.568H118.568V393.432z M134.737,134.737h242.526v242.526H134.737V134.737z"/>
|
||||
<path d="M512,177.853v-59.284h-75.453V94.316c0-10.401-8.463-18.863-18.863-18.863h-24.253V5.389h-59.284v70.063h-48.505V5.389
|
||||
h-59.284v70.063h-48.505V5.389h-59.284v70.063H94.316c-10.401,0-18.863,8.463-18.863,18.863v24.253H0v59.284h75.453v48.505H0v59.284
|
||||
h75.453v48.505H0v59.284h75.453v24.253c0,10.401,8.463,18.863,18.863,18.863h24.253v70.063h59.284v-70.063h48.505v70.063h59.284
|
||||
v-70.063h48.505v70.063h59.284v-70.063h24.253c10.401,0,18.863-8.463,18.863-18.863v-24.253H512v-59.284h-75.453v-48.505H512
|
||||
v-59.284h-75.453v-48.505H512z M436.547,134.737h16.168v26.947h-16.168V134.737z M495.832,161.684h-26.947v-26.947h26.947V161.684z
|
||||
M350.316,59.284h26.947v16.168h-26.947V59.284z M377.263,21.558v21.558h-26.947V21.558H377.263z M242.526,59.284h26.947v16.168
|
||||
h-26.947V59.284z M269.474,21.558v21.558h-26.947V21.558H269.474z M134.737,59.284h26.947v16.168h-26.947V59.284z M161.684,21.558
|
||||
v21.558h-26.947V21.558H161.684z M75.453,161.684H59.284v-26.947h16.168V161.684z M16.168,134.737h26.947v26.947H16.168V134.737z
|
||||
M75.453,269.474H59.284v-26.947h16.168V269.474z M16.168,242.526h26.947v26.947H16.168V242.526z M75.453,377.263H59.284v-26.947
|
||||
h16.168V377.263z M16.168,350.316h26.947v26.947H16.168V350.316z M161.684,452.716h-26.947v-16.168h26.947V452.716z
|
||||
M134.737,490.442v-21.558h26.947v21.558H134.737z M269.474,452.716h-26.947v-16.168h26.947V452.716z M242.526,490.442v-21.558
|
||||
h26.947v21.558H242.526z M377.263,452.716h-26.947v-16.168h26.947V452.716z M350.316,490.442v-21.558h26.947v21.558H350.316z
|
||||
M436.547,350.316h16.168v26.947h-16.168V350.316z M495.832,377.263h-26.947v-26.947h26.947V377.263z M436.547,242.526h16.168
|
||||
v26.947h-16.168V242.526z M495.832,269.474h-26.947v-26.947h26.947V269.474z M420.379,417.684c0,1.461-1.234,2.695-2.695,2.695
|
||||
H94.316c-1.461,0-2.695-1.234-2.695-2.695V94.316c0-1.461,1.234-2.695,2.695-2.695h323.368c1.461,0,2.695,1.234,2.695,2.695V417.684
|
||||
z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 5.8 KiB |
17
gaseous-server/wwwroot/images/cross.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
|
||||
<title>cross-circle</title>
|
||||
<desc>Created with Sketch Beta.</desc>
|
||||
<defs>
|
||||
|
||||
</defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="Icon-Set" sketch:type="MSLayerGroup" transform="translate(-568.000000, -1087.000000)" fill="red">
|
||||
<path d="M584,1117 C576.268,1117 570,1110.73 570,1103 C570,1095.27 576.268,1089 584,1089 C591.732,1089 598,1095.27 598,1103 C598,1110.73 591.732,1117 584,1117 L584,1117 Z M584,1087 C575.163,1087 568,1094.16 568,1103 C568,1111.84 575.163,1119 584,1119 C592.837,1119 600,1111.84 600,1103 C600,1094.16 592.837,1087 584,1087 L584,1087 Z M589.717,1097.28 C589.323,1096.89 588.686,1096.89 588.292,1097.28 L583.994,1101.58 L579.758,1097.34 C579.367,1096.95 578.733,1096.95 578.344,1097.34 C577.953,1097.73 577.953,1098.37 578.344,1098.76 L582.58,1102.99 L578.314,1107.26 C577.921,1107.65 577.921,1108.29 578.314,1108.69 C578.708,1109.08 579.346,1109.08 579.74,1108.69 L584.006,1104.42 L588.242,1108.66 C588.633,1109.05 589.267,1109.05 589.657,1108.66 C590.048,1108.27 590.048,1107.63 589.657,1107.24 L585.42,1103.01 L589.717,1098.71 C590.11,1098.31 590.11,1097.68 589.717,1097.28 L589.717,1097.28 Z" id="cross-circle" sketch:type="MSShapeGroup">
|
||||
|
||||
</path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
4
gaseous-server/wwwroot/images/discord.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18.59 5.88997C17.36 5.31997 16.05 4.89997 14.67 4.65997C14.5 4.95997 14.3 5.36997 14.17 5.69997C12.71 5.47997 11.26 5.47997 9.83001 5.69997C9.69001 5.36997 9.49001 4.95997 9.32001 4.65997C7.94001 4.89997 6.63001 5.31997 5.40001 5.88997C2.92001 9.62997 2.25001 13.28 2.58001 16.87C4.23001 18.1 5.82001 18.84 7.39001 19.33C7.78001 18.8 8.12001 18.23 8.42001 17.64C7.85001 17.43 7.31001 17.16 6.80001 16.85C6.94001 16.75 7.07001 16.64 7.20001 16.54C10.33 18 13.72 18 16.81 16.54C16.94 16.65 17.07 16.75 17.21 16.85C16.7 17.16 16.15 17.42 15.59 17.64C15.89 18.23 16.23 18.8 16.62 19.33C18.19 18.84 19.79 18.1 21.43 16.87C21.82 12.7 20.76 9.08997 18.61 5.88997H18.59ZM8.84001 14.67C7.90001 14.67 7.13001 13.8 7.13001 12.73C7.13001 11.66 7.88001 10.79 8.84001 10.79C9.80001 10.79 10.56 11.66 10.55 12.73C10.55 13.79 9.80001 14.67 8.84001 14.67ZM15.15 14.67C14.21 14.67 13.44 13.8 13.44 12.73C13.44 11.66 14.19 10.79 15.15 10.79C16.11 10.79 16.87 11.66 16.86 12.73C16.86 13.79 16.11 14.67 15.15 14.67Z" fill="#000000"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
gaseous-server/wwwroot/images/github-mark.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg>
|
After Width: | Height: | Size: 963 B |
5
gaseous-server/wwwroot/images/hasheous.svg
Normal file
After Width: | Height: | Size: 567 KiB |
4
gaseous-server/wwwroot/images/home.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3103 1.77586C11.6966 1.40805 12.3034 1.40805 12.6897 1.77586L20.6897 9.39491L23.1897 11.7759C23.5896 12.1567 23.605 12.7897 23.2241 13.1897C22.8433 13.5896 22.2103 13.605 21.8103 13.2241L21 12.4524V20C21 21.1046 20.1046 22 19 22H14H10H5C3.89543 22 3 21.1046 3 20V12.4524L2.18966 13.2241C1.78972 13.605 1.15675 13.5896 0.775862 13.1897C0.394976 12.7897 0.410414 12.1567 0.810345 11.7759L3.31034 9.39491L11.3103 1.77586ZM5 10.5476V20H9V15C9 13.3431 10.3431 12 12 12C13.6569 12 15 13.3431 15 15V20H19V10.5476L12 3.88095L5 10.5476ZM13 20V15C13 14.4477 12.5523 14 12 14C11.4477 14 11 14.4477 11 15V20H13Z" fill="#000000"/>
|
||||
</svg>
|
After Width: | Height: | Size: 901 B |