Compare commits
18 Commits
v1.7.4-pre
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
![]() |
bec461259c | ||
![]() |
bb86cb52f6 | ||
![]() |
c615b804fa | ||
![]() |
7dfb0b54eb | ||
![]() |
f0783fcae8 | ||
![]() |
68be24d514 | ||
![]() |
a5da1a9033 | ||
![]() |
fc09681cdd | ||
![]() |
6185912151 | ||
![]() |
deef919d5b | ||
![]() |
fd7b354571 | ||
![]() |
be1d53b3b1 | ||
![]() |
e0cff36819 | ||
![]() |
cea654692e | ||
![]() |
c82ffb6c97 | ||
![]() |
7400a8c040 | ||
![]() |
eda171efa1 | ||
![]() |
f881459c0b |
@@ -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 apt-get update && apt-get install -y p7zip-full
|
||||||
RUN mkdir -p /workspace/gaseous-server/wwwroot/emulators/EmulatorJS
|
RUN mkdir -p /workspace/gaseous-server/wwwroot/emulators/EmulatorJS
|
||||||
RUN wget https://cdn.emulatorjs.org/releases/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.11.7z
|
RUN 7z x -y -o/workspace/gaseous-server/wwwroot/emulators/EmulatorJS 4.0.12.7z
|
@@ -36,7 +36,9 @@
|
|||||||
"AndersEAndersen.html-class-suggestions",
|
"AndersEAndersen.html-class-suggestions",
|
||||||
"george-alisson.html-preview-vscode",
|
"george-alisson.html-preview-vscode",
|
||||||
"ms-dotnettools.vscodeintellicode-csharp",
|
"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}
|
- dbhost=${DATABASE_HOST}
|
||||||
- dbuser=${DATABASE_USER}
|
- dbuser=${DATABASE_USER}
|
||||||
- dbpass=${DATABASE_PASSWORD}
|
- dbpass=${DATABASE_PASSWORD}
|
||||||
- igdbclientid=<clientid>
|
- igdbclientid=${IGDB_CLIENT_ID}
|
||||||
- igdbclientsecret=<clientsecret>
|
- igdbclientsecret=${IGDB_CLIENT_SECRET}
|
||||||
mariadb:
|
mariadb:
|
||||||
hostname: mariadb
|
hostname: mariadb
|
||||||
image: mariadb:latest
|
image: mariadb:latest
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
environment:
|
environment:
|
||||||
- MARIADB_ROOT_PASSWORD=${DATABASE_PASSWORD}
|
- MARIADB_ROOT_PASSWORD=${DATABASE_PASSWORD}
|
||||||
- MARIADB_DATABASE=${DATABASE_DB}
|
- MARIADB_DATABASE=${DATABASE_DB}
|
||||||
|
@@ -9,9 +9,14 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
- name: Install dotnet tool
|
- name: Install dotnet tool
|
||||||
@@ -21,18 +26,37 @@ jobs:
|
|||||||
- name: Sign in to Nuget
|
- 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"
|
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"
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Build and push
|
- name: Login to GitHub Package Registry
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Build and push standard image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
|
file: ./build/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: gaseousgames/gaseousserver:${{ github.ref_name}}
|
tags: |
|
||||||
|
gaseousgames/gaseousserver:${{ github.ref_name}}
|
||||||
|
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}
|
||||||
|
- 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/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||||
|
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}-embeddeddb
|
40
.github/workflows/BuildDockerOnTag-Release.yml
vendored
@@ -8,9 +8,14 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
- name: Install dotnet tool
|
- name: Install dotnet tool
|
||||||
@@ -20,18 +25,39 @@ jobs:
|
|||||||
- name: Sign in to Nuget
|
- 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"
|
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"
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Build and push
|
- name: Login to GitHub Package Registry
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Build and push standard image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
|
file: ./build/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: gaseousgames/gaseousserver:latest,gaseousgames/gaseousserver:${{ github.ref_name}}
|
tags: |
|
||||||
|
gaseousgames/gaseousserver:latest
|
||||||
|
gaseousgames/gaseousserver:${{ github.ref_name}}
|
||||||
|
ghcr.io/gaseous-project/gaseousserver:latest
|
||||||
|
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}
|
||||||
|
- 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/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||||
|
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}-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
|
# Local History for Visual Studio
|
||||||
.localhistory/
|
.localhistory/
|
||||||
gaseous-server/.DS_Store
|
gaseous-server/.DS_Store
|
||||||
|
gaseous-server/wwwroot/.DS_Store
|
||||||
gaseous-server/wwwroot/emulators/EmulatorJS
|
gaseous-server/wwwroot/emulators/EmulatorJS
|
||||||
|
.devcontainer/.env
|
||||||
|
.mono/
|
||||||
|
3
.vscode/launch.json
vendored
@@ -24,7 +24,8 @@
|
|||||||
},
|
},
|
||||||
"sourceFileMap": {
|
"sourceFileMap": {
|
||||||
"/Views": "${workspaceFolder}/Views"
|
"/Views": "${workspaceFolder}/Views"
|
||||||
}
|
},
|
||||||
|
"enableStepFiltering": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": ".NET Core Attach",
|
"name": ".NET Core Attach",
|
||||||
|
28
Dockerfile
@@ -1,28 +0,0 @@
|
|||||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
|
|
||||||
ARG TARGETARCH
|
|
||||||
ARG BUILDPLATFORM
|
|
||||||
WORKDIR /App
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
RUN echo "Target: $TARGETARCH"
|
|
||||||
RUN echo "Build: $BUILDPLATFORM"
|
|
||||||
|
|
||||||
# Copy everything
|
|
||||||
COPY . ./
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# download and unzip EmulatorJS from CDN
|
|
||||||
RUN apt-get update && 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
|
|
||||||
|
|
||||||
# Build runtime image
|
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
|
||||||
ENV INDOCKER=1
|
|
||||||
WORKDIR /App
|
|
||||||
COPY --from=build-env /App/out .
|
|
||||||
ENTRYPOINT ["dotnet", "gaseous-server.dll"]
|
|
26
Gaseous.sln
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 16
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 25.0.1704.4
|
VisualStudioVersion = 25.0.1704.4
|
||||||
@@ -21,36 +21,30 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "screenshots", "screenshots"
|
|||||||
screenshots\Game.png = screenshots\Game.png
|
screenshots\Game.png = screenshots\Game.png
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gaseous-cli", "gaseous-cli\gaseous-cli.csproj", "{419CC4E4-8932-4E4A-B027-5521AA0CBA85}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{08699C93-15CD-4E39-9053-D3C8056CE938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{08699C93-15CD-4E39-9053-D3C8056CE938}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{08699C93-15CD-4E39-9053-D3C8056CE938}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{08699C93-15CD-4E39-9053-D3C8056CE938}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{FFCEC386-033F-4772-A45B-D33579F2E5EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{FFCEC386-033F-4772-A45B-D33579F2E5EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{FFCEC386-033F-4772-A45B-D33579F2E5EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{FFCEC386-033F-4772-A45B-D33579F2E5EE}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Release|Any CPU.Build.0 = Release|Any CPU
|
{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{B07A4655-A003-416B-A790-ADAA5B548E1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{B07A4655-A003-416B-A790-ADAA5B548E1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{B07A4655-A003-416B-A790-ADAA5B548E1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{B07A4655-A003-416B-A790-ADAA5B548E1A}.Release|Any CPU.Build.0 = Release|Any CPU
|
{419CC4E4-8932-4E4A-B027-5521AA0CBA85}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {979BF092-AFBC-4F19-B55F-32E73959BD1A}
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{F1A847C7-57BC-4DA9-8F83-CD060A7F5122} = {17FA6F12-8532-420C-9489-CB8FDE42137C}
|
{F1A847C7-57BC-4DA9-8F83-CD060A7F5122} = {17FA6F12-8532-420C-9489-CB8FDE42137C}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {979BF092-AFBC-4F19-B55F-32E73959BD1A}
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
147
LICENSE
@@ -1,5 +1,5 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
@@ -7,17 +7,15 @@
|
|||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
The GNU Affero General Public License is a free, copyleft license for
|
||||||
software and other kinds of works.
|
software and other kinds of works, specifically designed to ensure
|
||||||
|
cooperation with the community in the case of network server software.
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
The licenses for most software and other practical works are designed
|
||||||
to take away your freedom to share and change the works. By contrast,
|
to take away your freedom to share and change the works. By contrast,
|
||||||
the GNU General Public License is intended to guarantee your freedom to
|
our General Public Licenses are intended to guarantee your freedom to
|
||||||
share and change all versions of a program--to make sure it remains free
|
share and change all versions of a program--to make sure it remains free
|
||||||
software for all its users. We, the Free Software Foundation, use the
|
software for all its users.
|
||||||
GNU General Public License for most of our software; it applies also to
|
|
||||||
any other work released this way by its authors. You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
When we speak of free software, we are referring to freedom, not
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
@@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you
|
|||||||
want it, that you can change the software or use pieces of it in new
|
want it, that you can change the software or use pieces of it in new
|
||||||
free programs, and that you know you can do these things.
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you
|
Developers that use our General Public Licenses protect your rights
|
||||||
these rights or asking you to surrender the rights. Therefore, you have
|
with two steps: (1) assert copyright on the software, and (2) offer
|
||||||
certain responsibilities if you distribute copies of the software, or if
|
you this License which gives you legal permission to copy, distribute
|
||||||
you modify it: responsibilities to respect the freedom of others.
|
and/or modify the software.
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
A secondary benefit of defending all users' freedom is that
|
||||||
gratis or for a fee, you must pass on to the recipients the same
|
improvements made in alternate versions of the program, if they
|
||||||
freedoms that you received. You must make sure that they, too, receive
|
receive widespread use, become available for other developers to
|
||||||
or can get the source code. And you must show them these terms so they
|
incorporate. Many developers of free software are heartened and
|
||||||
know their rights.
|
encouraged by the resulting cooperation. However, in the case of
|
||||||
|
software used on network servers, this result may fail to come about.
|
||||||
|
The GNU General Public License permits making a modified version and
|
||||||
|
letting the public access it on a server without ever releasing its
|
||||||
|
source code to the public.
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps:
|
The GNU Affero General Public License is designed specifically to
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
ensure that, in such cases, the modified source code becomes available
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
to the community. It requires the operator of a network server to
|
||||||
|
provide the source code of the modified version running there to the
|
||||||
|
users of that server. Therefore, public use of a modified version, on
|
||||||
|
a publicly accessible server, gives the public access to the source
|
||||||
|
code of the modified version.
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains
|
An older license, called the Affero General Public License and
|
||||||
that there is no warranty for this free software. For both users' and
|
published by Affero, was designed to accomplish similar goals. This is
|
||||||
authors' sake, the GPL requires that modified versions be marked as
|
a different license, not a version of the Affero GPL, but Affero has
|
||||||
changed, so that their problems will not be attributed erroneously to
|
released a new version of the Affero GPL which permits relicensing under
|
||||||
authors of previous versions.
|
this license.
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run
|
|
||||||
modified versions of the software inside them, although the manufacturer
|
|
||||||
can do so. This is fundamentally incompatible with the aim of
|
|
||||||
protecting users' freedom to change the software. The systematic
|
|
||||||
pattern of such abuse occurs in the area of products for individuals to
|
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we
|
|
||||||
have designed this version of the GPL to prohibit the practice for those
|
|
||||||
products. If such problems arise substantially in other domains, we
|
|
||||||
stand ready to extend this provision to those domains in future versions
|
|
||||||
of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents.
|
|
||||||
States should not allow patents to restrict development and use of
|
|
||||||
software on general-purpose computers, but in those that do, we wish to
|
|
||||||
avoid the special danger that patents applied to a free program could
|
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that
|
|
||||||
patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
The precise terms and conditions for copying, distribution and
|
||||||
modification follow.
|
modification follow.
|
||||||
@@ -72,7 +60,7 @@ modification follow.
|
|||||||
|
|
||||||
0. Definitions.
|
0. Definitions.
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License.
|
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
works, such as semiconductor masks.
|
works, such as semiconductor masks.
|
||||||
@@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey
|
|||||||
the Program, the only way you could satisfy both those terms and this
|
the Program, the only way you could satisfy both those terms and this
|
||||||
License would be to refrain entirely from conveying the Program.
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License.
|
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, if you modify the
|
||||||
|
Program, your modified version must prominently offer all users
|
||||||
|
interacting with it remotely through a computer network (if your version
|
||||||
|
supports such interaction) an opportunity to receive the Corresponding
|
||||||
|
Source of your version by providing access to the Corresponding Source
|
||||||
|
from a network server at no charge, through some standard or customary
|
||||||
|
means of facilitating copying of software. This Corresponding Source
|
||||||
|
shall include the Corresponding Source for any work covered by version 3
|
||||||
|
of the GNU General Public License that is incorporated pursuant to the
|
||||||
|
following paragraph.
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
Notwithstanding any other provision of this License, you have
|
||||||
permission to link or combine any covered work with a work licensed
|
permission to link or combine any covered work with a work licensed
|
||||||
under version 3 of the GNU Affero General Public License into a single
|
under version 3 of the GNU General Public License into a single
|
||||||
combined work, and to convey the resulting work. The terms of this
|
combined work, and to convey the resulting work. The terms of this
|
||||||
License will continue to apply to the part which is the covered work,
|
License will continue to apply to the part which is the covered work,
|
||||||
but the special requirements of the GNU Affero General Public License,
|
but the work with which it is combined will remain governed by version
|
||||||
section 13, concerning interaction through a network will apply to the
|
3 of the GNU General Public License.
|
||||||
combination as such.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
the GNU General Public License from time to time. Such new versions will
|
the GNU Affero General Public License from time to time. Such new versions
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
will be similar in spirit to the present version, but may differ in detail to
|
||||||
address new problems or concerns.
|
address new problems or concerns.
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
Each version is given a distinguishing version number. If the
|
||||||
Program specifies that a certain numbered version of the GNU General
|
Program specifies that a certain numbered version of the GNU Affero General
|
||||||
Public License "or any later version" applies to it, you have the
|
Public License "or any later version" applies to it, you have the
|
||||||
option of following the terms and conditions either of that numbered
|
option of following the terms and conditions either of that numbered
|
||||||
version or of any later version published by the Free Software
|
version or of any later version published by the Free Software
|
||||||
Foundation. If the Program does not specify a version number of the
|
Foundation. If the Program does not specify a version number of the
|
||||||
GNU General Public License, you may choose any version ever published
|
GNU Affero General Public License, you may choose any version ever published
|
||||||
by the Free Software Foundation.
|
by the Free Software Foundation.
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
If the Program specifies that a proxy can decide which future
|
||||||
versions of the GNU General Public License can be used, that proxy's
|
versions of the GNU Affero General Public License can be used, that proxy's
|
||||||
public statement of acceptance of a version permanently authorizes you
|
public statement of acceptance of a version permanently authorizes you
|
||||||
to choose that version for the Program.
|
to choose that version for the Program.
|
||||||
|
|
||||||
@@ -631,44 +629,33 @@ to attach them to the start of each source file to most effectively
|
|||||||
state the exclusion of warranty; and each file should have at least
|
state the exclusion of warranty; and each file should have at least
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
Gaseous
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
Copyright (C) 2023 Gaseous
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU Affero General Public License as published
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
If your software can interact with users remotely through a computer
|
||||||
notice like this when it starts in an interactive mode:
|
network, you should also make sure that it provides a way for users to
|
||||||
|
get its source. For example, if your program is a web application, its
|
||||||
<program> Copyright (C) 2023 Gaseous
|
interface could display a "Source" link that leads users to an archive
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
of the code. There are many ways you could offer source, and different
|
||||||
This is free software, and you are welcome to redistribute it
|
solutions will be better for different programs; see section 13 for the
|
||||||
under certain conditions; type `show c' for details.
|
specific requirements.
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||||
<https://www.gnu.org/licenses/>.
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
|
||||||
|
@@ -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**.
|
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
|
## Screenshots
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
73
build/Dockerfile
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
|
||||||
|
ARG TARGETARCH
|
||||||
|
ARG BUILDPLATFORM
|
||||||
|
WORKDIR /App
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
RUN echo "Target: $TARGETARCH"
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# clean up apt-get
|
||||||
|
RUN apt-get clean && rm -rf /var/lib/apt/lists
|
||||||
|
|
||||||
|
# Build runtime image
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||||
|
ENV INDOCKER=1
|
||||||
|
WORKDIR /App
|
||||||
|
COPY --from=build-env /App/out .
|
||||||
|
|
||||||
|
# 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" ]
|
79
build/Dockerfile-EmbeddedDB
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
|
||||||
|
ARG TARGETARCH
|
||||||
|
ARG BUILDPLATFORM
|
||||||
|
WORKDIR /App
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
RUN echo "Target: $TARGETARCH"
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Build runtime image
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||||
|
ENV INDOCKER=1
|
||||||
|
WORKDIR /App
|
||||||
|
COPY --from=build-env /App/out .
|
||||||
|
|
||||||
|
# variables
|
||||||
|
ARG PUID=1000
|
||||||
|
ARG PGID=1000
|
||||||
|
ARG dbhost=localhost
|
||||||
|
ARG dbuser=root
|
||||||
|
ARG dbpass=gaseous
|
||||||
|
ARG MARIADB_ROOT_PASSWORD=$dbpass
|
||||||
|
|
||||||
|
ENV PUID=${PUID}
|
||||||
|
ENV PGID=${PGID}
|
||||||
|
ENV dbhost=${dbhost}
|
||||||
|
ENV dbuser=${dbuser}
|
||||||
|
ENV dbpass=${dbpass}
|
||||||
|
ENV MARIADB_ROOT_PASSWORD=${dbpass}
|
||||||
|
|
||||||
|
# install mariadb
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive && \
|
||||||
|
apt-get update && apt-get install -y mariadb-server
|
||||||
|
RUN mkdir -p /run/mysqld
|
||||||
|
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/embeddeddb/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/embeddeddb/entrypoint.sh /usr/sbin/entrypoint.sh
|
||||||
|
RUN chmod +x /usr/sbin/entrypoint.sh
|
||||||
|
|
||||||
|
# volumes
|
||||||
|
VOLUME /home/gaseous/.gaseous-server /var/lib/mysql
|
||||||
|
|
||||||
|
# start services
|
||||||
|
ENTRYPOINT [ "/usr/sbin/entrypoint.sh" ]
|
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
|
25
build/embeddeddb/mariadb.sh
Normal file
@@ -0,0 +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
|
||||||
|
echo "Starting MariaDB"
|
||||||
|
/usr/sbin/mariadbd --datadir=/var/lib/mysql --user=gaseous
|
37
build/embeddeddb/supervisord.conf
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
[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:mariadb]
|
||||||
|
user=gaseous
|
||||||
|
command=bash -c "/usr/sbin/start-mariadb.sh"
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
redirect_stderr=true
|
||||||
|
stdout_logfile=/dev/fd/1
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
|
||||||
|
[program:gaseous-server]
|
||||||
|
user=gaseous
|
||||||
|
command=dotnet /App/gaseous-server.dll
|
||||||
|
environment=HOME="/home/gaseous",USER="gaseous"
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
redirect_stderr=true
|
||||||
|
stdout_logfile=/dev/fd/1
|
||||||
|
stdout_logfile_maxbytes=0
|
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
|
container_name: gaseous-server
|
||||||
build:
|
build:
|
||||||
context: ./
|
context: ./
|
||||||
|
dockerfile: ./build/Dockerfile
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
- gaseous
|
- gaseous
|
||||||
@@ -12,7 +13,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 5198:80
|
- 5198:80
|
||||||
volumes:
|
volumes:
|
||||||
- gs:/root/.gaseous-server
|
- gs:/home/gaseous/.gaseous-server
|
||||||
environment:
|
environment:
|
||||||
- TZ=Australia/Sydney
|
- TZ=Australia/Sydney
|
||||||
- dbhost=gsdb
|
- dbhost=gsdb
|
||||||
|
@@ -11,7 +11,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 5198:80
|
- 5198:80
|
||||||
volumes:
|
volumes:
|
||||||
- gs:/root/.gaseous-server
|
- gs:/home/gaseous/.gaseous-server
|
||||||
environment:
|
environment:
|
||||||
- TZ=Australia/Sydney
|
- TZ=Australia/Sydney
|
||||||
- dbhost=gsdb
|
- 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 SecurityProfileViewModel SecurityProfile { get; set; }
|
||||||
public List<UserPreferenceViewModel> UserPreferences { 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);
|
var roleName = GetRoleName(roleId);
|
||||||
ApplicationRole? role = null;
|
ApplicationRole? role = null;
|
||||||
|
|
||||||
if(roleName != null)
|
if (roleName != null)
|
||||||
{
|
{
|
||||||
role = new ApplicationRole();
|
role = new ApplicationRole();
|
||||||
role.Id = roleId;
|
role.Id = roleId;
|
||||||
@@ -153,7 +153,7 @@ namespace Authentication
|
|||||||
string commandText = "Select Name from Roles";
|
string commandText = "Select Name from Roles";
|
||||||
|
|
||||||
var rows = _database.ExecuteCMDDict(commandText);
|
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));
|
ApplicationRole role = (ApplicationRole)Activator.CreateInstance(typeof(ApplicationRole));
|
||||||
role.Id = (string)row["Id"];
|
role.Id = (string)row["Id"];
|
||||||
|
@@ -35,7 +35,7 @@ namespace Authentication
|
|||||||
parameters.Add("@userId", userId);
|
parameters.Add("@userId", userId);
|
||||||
|
|
||||||
var rows = _database.ExecuteCMD(commandText, parameters).Rows;
|
var rows = _database.ExecuteCMD(commandText, parameters).Rows;
|
||||||
foreach(DataRow row in rows)
|
foreach (DataRow row in rows)
|
||||||
{
|
{
|
||||||
roles.Add((string)row["Name"]);
|
roles.Add((string)row["Name"]);
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ namespace Authentication
|
|||||||
/// Class that represents the Users table in the MySQL Database
|
/// Class that represents the Users table in the MySQL Database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UserTable<TUser>
|
public class UserTable<TUser>
|
||||||
where TUser :ApplicationUser
|
where TUser : ApplicationUser
|
||||||
{
|
{
|
||||||
private Database _database;
|
private Database _database;
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ namespace Authentication
|
|||||||
public TUser GetUserById(string userId)
|
public TUser GetUserById(string userId)
|
||||||
{
|
{
|
||||||
TUser user = null;
|
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 } };
|
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@id", userId } };
|
||||||
|
|
||||||
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
||||||
@@ -89,7 +89,7 @@ namespace Authentication
|
|||||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
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.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
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.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
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.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.SecurityProfile = GetSecurityProfile(user);
|
||||||
user.UserPreferences = GetPreferences(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;
|
return user;
|
||||||
@@ -114,11 +114,11 @@ namespace Authentication
|
|||||||
public List<TUser> GetUserByName(string normalizedUserName)
|
public List<TUser> GetUserByName(string normalizedUserName)
|
||||||
{
|
{
|
||||||
List<TUser> users = new List<TUser>();
|
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 } };
|
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@name", normalizedUserName } };
|
||||||
|
|
||||||
var rows = _database.ExecuteCMDDict(commandText, parameters);
|
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));
|
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
|
||||||
user.Id = (string)row["Id"];
|
user.Id = (string)row["Id"];
|
||||||
@@ -127,7 +127,7 @@ namespace Authentication
|
|||||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
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.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
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.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
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.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.SecurityProfile = GetSecurityProfile(user);
|
||||||
user.UserPreferences = GetPreferences(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);
|
users.Add(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,10 +148,10 @@ namespace Authentication
|
|||||||
public List<TUser> GetUsers()
|
public List<TUser> GetUsers()
|
||||||
{
|
{
|
||||||
List<TUser> users = new List<TUser>();
|
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);
|
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));
|
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
|
||||||
user.Id = (string)row["Id"];
|
user.Id = (string)row["Id"];
|
||||||
@@ -160,7 +160,7 @@ namespace Authentication
|
|||||||
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
user.SecurityStamp = (string?)(string.IsNullOrEmpty((string?)row["SecurityStamp"]) ? null : row["SecurityStamp"]);
|
||||||
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
user.ConcurrencyStamp = (string?)(string.IsNullOrEmpty((string?)row["ConcurrencyStamp"]) ? null : row["ConcurrencyStamp"]);
|
||||||
user.Email = (string?)(string.IsNullOrEmpty((string?)row["Email"]) ? null : row["Email"]);
|
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.PhoneNumber = (string?)(string.IsNullOrEmpty((string?)row["PhoneNumber"]) ? null : row["PhoneNumber"]);
|
||||||
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
|
||||||
user.NormalizedEmail = (string?)(string.IsNullOrEmpty((string?)row["NormalizedEmail"]) ? null : row["NormalizedEmail"]);
|
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.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
|
||||||
user.LockoutEnd = string.IsNullOrEmpty((string?)row["LockoutEnd"]) ? DateTime.Now : DateTime.Parse((string?)row["LockoutEnd"]);
|
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.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.SecurityProfile = GetSecurityProfile(user);
|
||||||
user.UserPreferences = GetPreferences(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);
|
users.Add(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,10 +258,11 @@ namespace Authentication
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public int Insert(TUser user)
|
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>();
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||||
parameters.Add("@name", user.UserName);
|
parameters.Add("@name", user.UserName);
|
||||||
parameters.Add("@id", user.Id);
|
parameters.Add("@id", user.Id);
|
||||||
|
parameters.Add("@profileId", Guid.NewGuid());
|
||||||
parameters.Add("@pwdHash", user.PasswordHash);
|
parameters.Add("@pwdHash", user.PasswordHash);
|
||||||
parameters.Add("@SecStamp", user.SecurityStamp);
|
parameters.Add("@SecStamp", user.SecurityStamp);
|
||||||
parameters.Add("@concurrencystamp", user.ConcurrencyStamp);
|
parameters.Add("@concurrencystamp", user.ConcurrencyStamp);
|
||||||
@@ -292,7 +293,7 @@ namespace Authentication
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private int Delete(string userId)
|
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>();
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||||
parameters.Add("@userId", userId);
|
parameters.Add("@userId", userId);
|
||||||
|
|
||||||
|
@@ -8,8 +8,9 @@ namespace Authentication
|
|||||||
public List<String> Roles { get; set; }
|
public List<String> Roles { get; set; }
|
||||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||||
public List<UserPreferenceViewModel> UserPreferences { get; set; }
|
public List<UserPreferenceViewModel> UserPreferences { get; set; }
|
||||||
public Guid Avatar { get; set; }
|
public Guid ProfileId { get; set; }
|
||||||
public string HighestRole {
|
public string HighestRole
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
string _highestRole = "";
|
string _highestRole = "";
|
||||||
|
@@ -8,11 +8,14 @@ namespace Authentication
|
|||||||
public DateTimeOffset? LockoutEnd { get; set; }
|
public DateTimeOffset? LockoutEnd { get; set; }
|
||||||
public List<string> Roles { get; set; }
|
public List<string> Roles { get; set; }
|
||||||
public SecurityProfileViewModel SecurityProfile { get; set; }
|
public SecurityProfileViewModel SecurityProfile { get; set; }
|
||||||
public Guid Avatar { get; set; }
|
public Guid ProfileId { get; set; }
|
||||||
public string HighestRole {
|
public string HighestRole
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
string _highestRole = "";
|
string _highestRole = "";
|
||||||
|
if (Roles != null)
|
||||||
|
{
|
||||||
foreach (string role in Roles)
|
foreach (string role in Roles)
|
||||||
{
|
{
|
||||||
switch (role)
|
switch (role)
|
||||||
@@ -40,6 +43,11 @@ namespace Authentication
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_highestRole = "Player";
|
||||||
|
}
|
||||||
|
|
||||||
return _highestRole;
|
return _highestRole;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
@@ -19,7 +20,8 @@ namespace gaseous_server.Classes
|
|||||||
if (ObjectToCheck == null || ObjectToCheck == System.DBNull.Value)
|
if (ObjectToCheck == null || ObjectToCheck == System.DBNull.Value)
|
||||||
{
|
{
|
||||||
return IfNullValue;
|
return IfNullValue;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return ObjectToCheck;
|
return ObjectToCheck;
|
||||||
}
|
}
|
||||||
@@ -43,11 +45,13 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
var xmlStream = File.OpenRead(FileName);
|
var xmlStream = File.OpenRead(FileName);
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Hash File", "Generating MD5 hash for file: " + FileName);
|
||||||
var md5 = MD5.Create();
|
var md5 = MD5.Create();
|
||||||
byte[] md5HashByte = md5.ComputeHash(xmlStream);
|
byte[] md5HashByte = md5.ComputeHash(xmlStream);
|
||||||
string md5Hash = BitConverter.ToString(md5HashByte).Replace("-", "").ToLowerInvariant();
|
string md5Hash = BitConverter.ToString(md5HashByte).Replace("-", "").ToLowerInvariant();
|
||||||
_md5hash = md5Hash;
|
_md5hash = md5Hash;
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Hash File", "Generating SHA1 hash for file: " + FileName);
|
||||||
var sha1 = SHA1.Create();
|
var sha1 = SHA1.Create();
|
||||||
xmlStream.Position = 0;
|
xmlStream.Position = 0;
|
||||||
byte[] sha1HashByte = sha1.ComputeHash(xmlStream);
|
byte[] sha1HashByte = sha1.ComputeHash(xmlStream);
|
||||||
@@ -155,6 +159,50 @@ namespace gaseous_server.Classes
|
|||||||
return defaultValue;
|
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>
|
/// <summary>
|
||||||
|
@@ -80,7 +80,8 @@ namespace gaseous_server.Classes
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
string logPath = Path.Combine(ConfigurationPath, "Logs");
|
string logPath = Path.Combine(ConfigurationPath, "Logs");
|
||||||
if (!Directory.Exists(logPath)) {
|
if (!Directory.Exists(logPath))
|
||||||
|
{
|
||||||
Directory.CreateDirectory(logPath);
|
Directory.CreateDirectory(logPath);
|
||||||
}
|
}
|
||||||
return logPath;
|
return logPath;
|
||||||
@@ -131,7 +132,7 @@ namespace gaseous_server.Classes
|
|||||||
_config.DatabaseConfiguration.DatabaseName = (string)Common.GetEnvVar("dbname", _config.DatabaseConfiguration.DatabaseName);
|
_config.DatabaseConfiguration.DatabaseName = (string)Common.GetEnvVar("dbname", _config.DatabaseConfiguration.DatabaseName);
|
||||||
_config.DatabaseConfiguration.Port = int.Parse((string)Common.GetEnvVar("dbport", _config.DatabaseConfiguration.Port.ToString()));
|
_config.DatabaseConfiguration.Port = int.Parse((string)Common.GetEnvVar("dbport", _config.DatabaseConfiguration.Port.ToString()));
|
||||||
_config.MetadataConfiguration.MetadataSource = (HasheousClient.Models.MetadataModel.MetadataSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.MetadataSources), (string)Common.GetEnvVar("metadatasource", _config.MetadataConfiguration.MetadataSource.ToString()));
|
_config.MetadataConfiguration.MetadataSource = (HasheousClient.Models.MetadataModel.MetadataSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.MetadataSources), (string)Common.GetEnvVar("metadatasource", _config.MetadataConfiguration.MetadataSource.ToString()));
|
||||||
_config.MetadataConfiguration.SignatureSource = (HasheousClient.Models.MetadataModel.SignatureSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.SignatureSources), (string)Common.GetEnvVar("signaturesource", _config.MetadataConfiguration.SignatureSource.ToString()));;
|
_config.MetadataConfiguration.SignatureSource = (HasheousClient.Models.MetadataModel.SignatureSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.SignatureSources), (string)Common.GetEnvVar("signaturesource", _config.MetadataConfiguration.SignatureSource.ToString())); ;
|
||||||
_config.MetadataConfiguration.MaxLibraryScanWorkers = int.Parse((string)Common.GetEnvVar("maxlibraryscanworkers", _config.MetadataConfiguration.MaxLibraryScanWorkers.ToString()));
|
_config.MetadataConfiguration.MaxLibraryScanWorkers = int.Parse((string)Common.GetEnvVar("maxlibraryscanworkers", _config.MetadataConfiguration.MaxLibraryScanWorkers.ToString()));
|
||||||
_config.MetadataConfiguration.HasheousHost = (string)Common.GetEnvVar("hasheoushost", _config.MetadataConfiguration.HasheousHost);
|
_config.MetadataConfiguration.HasheousHost = (string)Common.GetEnvVar("hasheoushost", _config.MetadataConfiguration.HasheousHost);
|
||||||
_config.IGDBConfiguration.ClientId = (string)Common.GetEnvVar("igdbclientid", _config.IGDBConfiguration.ClientId);
|
_config.IGDBConfiguration.ClientId = (string)Common.GetEnvVar("igdbclientid", _config.IGDBConfiguration.ClientId);
|
||||||
@@ -153,8 +154,8 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Using configuration:");
|
// Console.WriteLine("Using configuration:");
|
||||||
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(_config, Formatting.Indented));
|
// Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(_config, Formatting.Indented));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdateConfig()
|
public static void UpdateConfig()
|
||||||
@@ -196,17 +197,12 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
string SettingName = (string)dataRow["Setting"];
|
string SettingName = (string)dataRow["Setting"];
|
||||||
|
|
||||||
if (SettingName.StartsWith("LastRun_"))
|
|
||||||
{
|
|
||||||
Console.WriteLine("Break");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AppSettings.ContainsKey(SettingName))
|
if (AppSettings.ContainsKey(SettingName))
|
||||||
{
|
{
|
||||||
AppSettings.Remove(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
|
try
|
||||||
{
|
{
|
||||||
@@ -427,7 +423,8 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public class Database
|
public class Database
|
||||||
{
|
{
|
||||||
private static string _DefaultHostName {
|
private static string _DefaultHostName
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("dbhost")))
|
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("dbhost")))
|
||||||
@@ -643,7 +640,7 @@ namespace gaseous_server.Classes
|
|||||||
return MetadataPath;
|
return MetadataPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string LibrarySignatureImportDirectory
|
public string LibrarySignaturesDirectory
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -651,6 +648,14 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string LibrarySignaturesProcessedDirectory
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Path.Combine(LibraryRootDirectory, "Signatures - Processed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void InitLibrary()
|
public void InitLibrary()
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(LibraryRootDirectory)) { Directory.CreateDirectory(LibraryRootDirectory); }
|
if (!Directory.Exists(LibraryRootDirectory)) { Directory.CreateDirectory(LibraryRootDirectory); }
|
||||||
@@ -660,7 +665,8 @@ namespace gaseous_server.Classes
|
|||||||
if (!Directory.Exists(LibraryMetadataDirectory)) { Directory.CreateDirectory(LibraryMetadataDirectory); }
|
if (!Directory.Exists(LibraryMetadataDirectory)) { Directory.CreateDirectory(LibraryMetadataDirectory); }
|
||||||
if (!Directory.Exists(LibraryTempDirectory)) { Directory.CreateDirectory(LibraryTempDirectory); }
|
if (!Directory.Exists(LibraryTempDirectory)) { Directory.CreateDirectory(LibraryTempDirectory); }
|
||||||
if (!Directory.Exists(LibraryCollectionsDirectory)) { Directory.CreateDirectory(LibraryCollectionsDirectory); }
|
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); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,6 +702,10 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool _HasheousSubmitFixes { get; set; } = false;
|
||||||
|
|
||||||
|
private static string _HasheousAPIKey { get; set; } = "";
|
||||||
|
|
||||||
private static int _MaxLibraryScanWorkers
|
private static int _MaxLibraryScanWorkers
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -730,6 +740,10 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public HasheousClient.Models.MetadataModel.SignatureSources SignatureSource = _SignatureSource;
|
public HasheousClient.Models.MetadataModel.SignatureSources SignatureSource = _SignatureSource;
|
||||||
|
|
||||||
|
public bool HasheousSubmitFixes = _HasheousSubmitFixes;
|
||||||
|
|
||||||
|
public string HasheousAPIKey = _HasheousAPIKey;
|
||||||
|
|
||||||
public int MaxLibraryScanWorkers = _MaxLibraryScanWorkers;
|
public int MaxLibraryScanWorkers = _MaxLibraryScanWorkers;
|
||||||
|
|
||||||
public string HasheousHost = _HasheousHost;
|
public string HasheousHost = _HasheousHost;
|
||||||
|
@@ -73,6 +73,8 @@ namespace gaseous_server.Classes
|
|||||||
// load resources
|
// load resources
|
||||||
var assembly = Assembly.GetExecutingAssembly();
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
|
||||||
|
DatabaseMemoryCacheOptions? CacheOptions = new DatabaseMemoryCacheOptions(false);
|
||||||
|
|
||||||
switch (_ConnectorType)
|
switch (_ConnectorType)
|
||||||
{
|
{
|
||||||
case databaseType.MySql:
|
case databaseType.MySql:
|
||||||
@@ -80,22 +82,22 @@ namespace gaseous_server.Classes
|
|||||||
string sql = "CREATE DATABASE IF NOT EXISTS `" + Config.DatabaseConfiguration.DatabaseName + "`;";
|
string sql = "CREATE DATABASE IF NOT EXISTS `" + Config.DatabaseConfiguration.DatabaseName + "`;";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
Logging.Log(Logging.LogType.Information, "Database", "Creating database if it doesn't exist");
|
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
|
// 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';";
|
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)
|
if (SchemaVersionPresent.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// no schema table present - create it
|
// no schema table present - create it
|
||||||
Logging.Log(Logging.LogType.Information, "Database", "Schema version table doesn't exist. Creating 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);";
|
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;";
|
sql = "SELECT schema_version FROM schema_version;";
|
||||||
dbDict = new Dictionary<string, object>();
|
dbDict = new Dictionary<string, object>();
|
||||||
DataTable SchemaVersion = ExecuteCMD(sql, dbDict);
|
DataTable SchemaVersion = ExecuteCMD(sql, dbDict, CacheOptions);
|
||||||
int OuterSchemaVer = (int)SchemaVersion.Rows[0][0];
|
int OuterSchemaVer = (int)SchemaVersion.Rows[0][0];
|
||||||
if (OuterSchemaVer == 0)
|
if (OuterSchemaVer == 0)
|
||||||
{
|
{
|
||||||
@@ -118,7 +120,7 @@ namespace gaseous_server.Classes
|
|||||||
// apply script
|
// apply script
|
||||||
sql = "SELECT schema_version FROM schema_version;";
|
sql = "SELECT schema_version FROM schema_version;";
|
||||||
dbDict = new Dictionary<string, object>();
|
dbDict = new Dictionary<string, object>();
|
||||||
SchemaVersion = ExecuteCMD(sql, dbDict);
|
SchemaVersion = ExecuteCMD(sql, dbDict, CacheOptions);
|
||||||
if (SchemaVersion.Rows.Count == 0)
|
if (SchemaVersion.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// something is broken here... where's the table?
|
// something is broken here... where's the table?
|
||||||
@@ -140,12 +142,12 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// apply schema!
|
// apply schema!
|
||||||
Logging.Log(Logging.LogType.Information, "Database", "Updating schema to version " + i);
|
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";
|
sql = "UPDATE schema_version SET schema_version=@schemaver";
|
||||||
dbDict = new Dictionary<string, object>();
|
dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("schemaver", i);
|
dbDict.Add("schemaver", i);
|
||||||
ExecuteCMD(sql, dbDict);
|
ExecuteCMD(sql, dbDict, CacheOptions);
|
||||||
|
|
||||||
// run post-upgrade code
|
// run post-upgrade code
|
||||||
DatabaseMigration.PostUpgradeScript(i, _ConnectorType);
|
DatabaseMigration.PostUpgradeScript(i, _ConnectorType);
|
||||||
@@ -170,39 +172,83 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public DataTable ExecuteCMD(string Command)
|
public DataTable ExecuteCMD(string Command)
|
||||||
{
|
{
|
||||||
|
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||||
|
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
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)
|
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 = "")
|
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)
|
public List<Dictionary<string, object>> ExecuteCMDDict(string Command)
|
||||||
{
|
{
|
||||||
|
DatabaseMemoryCacheOptions? CacheOptions = null;
|
||||||
|
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
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)
|
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 = "")
|
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
|
// convert datatable to dictionary
|
||||||
List<Dictionary<string, object?>> rows = new List<Dictionary<string, object?>>();
|
List<Dictionary<string, object?>> rows = new List<Dictionary<string, object?>>();
|
||||||
@@ -228,14 +274,45 @@ namespace gaseous_server.Classes
|
|||||||
return rows;
|
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; }
|
if (ConnectionString == "") { ConnectionString = _ConnectionString; }
|
||||||
switch (_ConnectorType)
|
switch (_ConnectorType)
|
||||||
{
|
{
|
||||||
case databaseType.MySql:
|
case databaseType.MySql:
|
||||||
MySQLServerConnector conn = new MySQLServerConnector(ConnectionString);
|
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:
|
default:
|
||||||
return new DataTable();
|
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()
|
public int GetDatabaseSchemaVersion()
|
||||||
{
|
{
|
||||||
switch (_ConnectorType)
|
switch (_ConnectorType)
|
||||||
@@ -384,7 +603,9 @@ namespace gaseous_server.Classes
|
|||||||
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
||||||
}
|
}
|
||||||
RetTable.Load(cmd.ExecuteReader());
|
RetTable.Load(cmd.ExecuteReader());
|
||||||
} catch (Exception ex) {
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
||||||
Trace.WriteLine("Error executing " + SQL);
|
Trace.WriteLine("Error executing " + SQL);
|
||||||
Trace.WriteLine("Full exception: " + ex.ToString());
|
Trace.WriteLine("Full exception: " + ex.ToString());
|
||||||
@@ -397,7 +618,7 @@ namespace gaseous_server.Classes
|
|||||||
return RetTable;
|
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;
|
int result = 0;
|
||||||
|
|
||||||
@@ -427,7 +648,9 @@ namespace gaseous_server.Classes
|
|||||||
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
Logging.Log(Logging.LogType.Debug, "Database", "Parameters: " + dictValues, null, true);
|
||||||
}
|
}
|
||||||
result = cmd.ExecuteNonQuery();
|
result = cmd.ExecuteNonQuery();
|
||||||
} catch (Exception ex) {
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
Logging.Log(Logging.LogType.Critical, "Database", "Error while executing '" + SQL + "'", ex);
|
||||||
Trace.WriteLine("Error executing " + SQL);
|
Trace.WriteLine("Error executing " + SQL);
|
||||||
Trace.WriteLine("Full exception: " + ex.ToString());
|
Trace.WriteLine("Full exception: " + ex.ToString());
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using gaseous_server.Classes.Metadata;
|
||||||
|
using gaseous_server.Models;
|
||||||
|
using IGDB.Models;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
@@ -20,7 +23,7 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Database", "Checking for pre-upgrade for schema version " + TargetSchemaVersion);
|
Logging.Log(Logging.LogType.Information, "Database", "Checking for pre-upgrade for schema version " + TargetSchemaVersion);
|
||||||
|
|
||||||
switch(DatabaseType)
|
switch (DatabaseType)
|
||||||
{
|
{
|
||||||
case Database.databaseType.MySql:
|
case Database.databaseType.MySql:
|
||||||
switch (TargetSchemaVersion)
|
switch (TargetSchemaVersion)
|
||||||
@@ -64,12 +67,14 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public static void PostUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
public static void PostUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
||||||
{
|
{
|
||||||
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
string sql = "";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
DataTable data;
|
DataTable data;
|
||||||
|
|
||||||
switch(DatabaseType)
|
switch (DatabaseType)
|
||||||
{
|
{
|
||||||
case Database.databaseType.MySql:
|
case Database.databaseType.MySql:
|
||||||
switch (TargetSchemaVersion)
|
switch (TargetSchemaVersion)
|
||||||
@@ -103,6 +108,80 @@ namespace gaseous_server.Classes
|
|||||||
sql = "DELETE FROM Settings WHERE Setting LIKE 'LastRun_%';";
|
sql = "DELETE FROM Settings WHERE Setting LIKE 'LastRun_%';";
|
||||||
db.ExecuteNonQuery(sql);
|
db.ExecuteNonQuery(sql);
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -117,11 +196,16 @@ namespace gaseous_server.Classes
|
|||||||
case 1002:
|
case 1002:
|
||||||
MySql_1002_MigrateMetadataVersion();
|
MySql_1002_MigrateMetadataVersion();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 1023:
|
||||||
|
MySql_1023_MigrateMetadataVersion();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MySql_1002_MigrateMetadataVersion() {
|
public static void MySql_1002_MigrateMetadataVersion()
|
||||||
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
string sql = "";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
@@ -216,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.Collections.Concurrent;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using System.Net;
|
||||||
|
using gaseous_server.Classes.Metadata;
|
||||||
using HasheousClient.Models;
|
using HasheousClient.Models;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using NuGet.Common;
|
using NuGet.Common;
|
||||||
using SevenZip;
|
using SevenZip;
|
||||||
using SharpCompress.Archives;
|
using SharpCompress.Archives;
|
||||||
@@ -31,7 +34,7 @@ namespace gaseous_server.Classes
|
|||||||
if (!Directory.Exists(ExtractPath)) { Directory.CreateDirectory(ExtractPath); }
|
if (!Directory.Exists(ExtractPath)) { Directory.CreateDirectory(ExtractPath); }
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch(ImportedFileExtension)
|
switch (ImportedFileExtension)
|
||||||
{
|
{
|
||||||
case ".zip":
|
case ".zip":
|
||||||
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing using zip");
|
Logging.Log(Logging.LogType.Information, "Get Signature", "Decompressing using zip");
|
||||||
@@ -110,8 +113,10 @@ namespace gaseous_server.Classes
|
|||||||
// loop through contents until we find the first signature match
|
// loop through contents until we find the first signature match
|
||||||
List<ArchiveData> archiveFiles = new List<ArchiveData>();
|
List<ArchiveData> archiveFiles = new List<ArchiveData>();
|
||||||
bool signatureFound = false;
|
bool signatureFound = false;
|
||||||
|
bool signatureSelectorAlreadyApplied = false;
|
||||||
foreach (string file in Directory.GetFiles(ExtractPath, "*.*", SearchOption.AllDirectories))
|
foreach (string file in Directory.GetFiles(ExtractPath, "*.*", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
|
bool signatureSelector = false;
|
||||||
if (File.Exists(file))
|
if (File.Exists(file))
|
||||||
{
|
{
|
||||||
FileInfo zfi = new FileInfo(file);
|
FileInfo zfi = new FileInfo(file);
|
||||||
@@ -121,15 +126,6 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
if (zfi != null)
|
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)
|
if (signatureFound == false)
|
||||||
{
|
{
|
||||||
gaseous_server.Models.Signatures_Games zDiscoveredSignature = _GetFileSignature(zhash, zfi.Name, zfi.Extension, zfi.Length, file, true);
|
gaseous_server.Models.Signatures_Games zDiscoveredSignature = _GetFileSignature(zhash, zfi.Name, zfi.Extension, zfi.Length, file, true);
|
||||||
@@ -151,15 +147,37 @@ namespace gaseous_server.Classes
|
|||||||
discoveredSignature = zDiscoveredSignature;
|
discoveredSignature = zDiscoveredSignature;
|
||||||
|
|
||||||
signatureFound = true;
|
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)
|
"ZipContents", Newtonsoft.Json.JsonConvert.SerializeObject(archiveFiles)
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -175,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);
|
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
|
// begin signature search
|
||||||
gaseous_server.Models.Signatures_Games? dbSignature = _GetFileSignatureFromDatabase(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
switch (Config.MetadataConfiguration.SignatureSource)
|
||||||
|
|
||||||
if (dbSignature != null)
|
|
||||||
{
|
{
|
||||||
// local signature found
|
case HasheousClient.Models.MetadataModel.SignatureSources.LocalOnly:
|
||||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature found in local database for game: " + dbSignature.Game.Name);
|
Logging.Log(Logging.LogType.Information, "Import Game", "Hasheous disabled - searching local database only");
|
||||||
discoveredSignature = dbSignature;
|
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
// no local signature attempt to pull from Hasheous
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature retrieved from Hasheous for game: " + discoveredSignature.Game.Name);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (discoveredSignature == null)
|
||||||
{
|
{
|
||||||
// construct a signature from file data
|
// construct a signature from file data
|
||||||
dbSignature = _GetFileSignatureFromFileData(hash, ImageName, ImageExtension, ImageSize, GameFileImportPath);
|
Logging.Log(Logging.LogType.Information, "Import Game", "Signature not found in local database or Hasheous (if enabled) - generating from file data");
|
||||||
Logging.Log(Logging.LogType.Information, "Import Game", "Signature generated from provided file for game: " + dbSignature.Game.Name);
|
|
||||||
|
|
||||||
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);
|
gaseous_server.Models.PlatformMapping.GetIGDBPlatformMapping(ref discoveredSignature, ImageExtension, false);
|
||||||
@@ -264,7 +290,12 @@ namespace gaseous_server.Classes
|
|||||||
if (Config.MetadataConfiguration.SignatureSource == HasheousClient.Models.MetadataModel.SignatureSources.Hasheous)
|
if (Config.MetadataConfiguration.SignatureSource == HasheousClient.Models.MetadataModel.SignatureSources.Hasheous)
|
||||||
{
|
{
|
||||||
HasheousClient.Hasheous hasheous = new HasheousClient.Hasheous();
|
HasheousClient.Hasheous hasheous = new HasheousClient.Hasheous();
|
||||||
SignatureLookupItem? HasheousResult = hasheous.RetrieveFromHasheousAsync(new HashLookupModel{
|
Console.WriteLine(HasheousClient.WebApp.HttpHelper.BaseUri);
|
||||||
|
LookupItemModel? HasheousResult = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HasheousResult = hasheous.RetrieveFromHasheous(new HashLookupModel
|
||||||
|
{
|
||||||
MD5 = hash.md5hash,
|
MD5 = hash.md5hash,
|
||||||
SHA1 = hash.sha1hash
|
SHA1 = hash.sha1hash
|
||||||
});
|
});
|
||||||
@@ -274,19 +305,46 @@ namespace gaseous_server.Classes
|
|||||||
if (HasheousResult.Signature != null)
|
if (HasheousResult.Signature != null)
|
||||||
{
|
{
|
||||||
gaseous_server.Models.Signatures_Games signature = new Models.Signatures_Games();
|
gaseous_server.Models.Signatures_Games signature = new Models.Signatures_Games();
|
||||||
signature.Game = HasheousResult.Signature.Game;
|
string gameJson = Newtonsoft.Json.JsonConvert.SerializeObject(HasheousResult.Signature.Game);
|
||||||
signature.Rom = HasheousResult.Signature.Rom;
|
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;
|
switch (metadataResult.Source)
|
||||||
signature.Flags.IGDBGameId = (long)metadataResult.GameId;
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,6 +354,34 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -368,6 +454,7 @@ namespace gaseous_server.Classes
|
|||||||
public long Size { get; set; }
|
public long Size { get; set; }
|
||||||
public string MD5 { get; set; }
|
public string MD5 { get; set; }
|
||||||
public string SHA1 { 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`;";
|
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)
|
foreach (DataRow dr in dbResponse.Rows)
|
||||||
{
|
{
|
||||||
@@ -83,7 +83,7 @@ namespace gaseous_server.Classes
|
|||||||
// age groups
|
// age groups
|
||||||
List<FilterItem> agegroupings = new List<FilterItem>();
|
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";
|
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)
|
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`;";
|
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);
|
sql = sql.Replace("<ITEMNAME>", Name);
|
||||||
DataTable dbResponse = db.ExecuteCMD(sql);
|
DataTable dbResponse = db.ExecuteCMD(sql, new Database.DatabaseMemoryCacheOptions(CacheEnabled: true, ExpirationSeconds: 300));
|
||||||
|
|
||||||
return dbResponse;
|
return dbResponse;
|
||||||
}
|
}
|
||||||
|
@@ -13,31 +13,31 @@ namespace gaseous_server
|
|||||||
public class PathExists : Exception
|
public class PathExists : Exception
|
||||||
{
|
{
|
||||||
public PathExists(string path) : base("The library path " + path + " already exists.")
|
public PathExists(string path) : base("The library path " + path + " already exists.")
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PathNotFound : Exception
|
public class PathNotFound : Exception
|
||||||
{
|
{
|
||||||
public PathNotFound(string path) : base("The path " + path + " does not exist.")
|
public PathNotFound(string path) : base("The path " + path + " does not exist.")
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LibraryNotFound : Exception
|
public class LibraryNotFound : Exception
|
||||||
{
|
{
|
||||||
public LibraryNotFound(int LibraryId) : base("Library id " + LibraryId + " does not exist.")
|
public LibraryNotFound(int LibraryId) : base("Library id " + LibraryId + " does not exist.")
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CannotDeleteDefaultLibrary : Exception
|
public class CannotDeleteDefaultLibrary : Exception
|
||||||
{
|
{
|
||||||
public CannotDeleteDefaultLibrary() : base("Unable to delete the default library.")
|
public CannotDeleteDefaultLibrary() : base("Unable to delete the default library.")
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CannotDeleteLibraryWhileScanIsActive : Exception
|
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")
|
public CannotDeleteLibraryWhileScanIsActive() : base("Unable to delete library while a library scan is active. Wait for all scans to complete and try again")
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
// code
|
// code
|
||||||
@@ -66,7 +66,7 @@ namespace gaseous_server
|
|||||||
{
|
{
|
||||||
List<LibraryItem> libraryItems = new List<LibraryItem>();
|
List<LibraryItem> libraryItems = new List<LibraryItem>();
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
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);
|
DataTable data = db.ExecuteCMD(sql);
|
||||||
foreach (DataRow row in data.Rows)
|
foreach (DataRow row in data.Rows)
|
||||||
{
|
{
|
||||||
@@ -129,7 +129,7 @@ namespace gaseous_server
|
|||||||
if (library.IsDefaultLibrary == false)
|
if (library.IsDefaultLibrary == false)
|
||||||
{
|
{
|
||||||
// check for active library scans
|
// check for active library scans
|
||||||
foreach(ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
(item.ItemType == ProcessQueue.QueueItemType.LibraryScan && item.ItemState == ProcessQueue.QueueItemState.Running) ||
|
(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 class LibraryItem
|
||||||
{
|
{
|
||||||
public LibraryItem(int Id, string Name, string Path, long DefaultPlatformId, bool IsDefaultLibrary)
|
public LibraryItem(int Id, string Name, string Path, long DefaultPlatformId, bool IsDefaultLibrary)
|
||||||
|
@@ -28,7 +28,8 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// import files first
|
// import files first
|
||||||
int importCount = 1;
|
int importCount = 1;
|
||||||
foreach (string importContent in importContents) {
|
foreach (string importContent in importContents)
|
||||||
|
{
|
||||||
SetStatus(importCount, importContents.Length, "Importing file: " + importContent);
|
SetStatus(importCount, importContents.Length, "Importing file: " + importContent);
|
||||||
|
|
||||||
ImportGameFile(importContent, null);
|
ImportGameFile(importContent, null);
|
||||||
@@ -46,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);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
string sql = "";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
@@ -66,6 +70,8 @@ namespace gaseous_server.Classes
|
|||||||
if (IsBios == null)
|
if (IsBios == null)
|
||||||
{
|
{
|
||||||
// file is a rom
|
// file is a rom
|
||||||
|
RetVal.Add("type", "rom");
|
||||||
|
|
||||||
// check to make sure we don't already have this file imported
|
// 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";
|
sql = "SELECT COUNT(Id) AS count FROM Games_Roms WHERE MD5=@md5 AND SHA1=@sha1";
|
||||||
dbDict.Add("md5", hash.md5hash);
|
dbDict.Add("md5", hash.md5hash);
|
||||||
@@ -93,6 +99,8 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Import Game", " " + GameFileImportPath + " already in database - skipping import");
|
Logging.Log(Logging.LogType.Warning, "Import Game", " " + GameFileImportPath + " already in database - skipping import");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RetVal.Add("status", "duplicate");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -121,17 +129,27 @@ namespace gaseous_server.Classes
|
|||||||
IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature, discoveredSignature.Flags.IGDBPlatformId, true);
|
IGDB.Models.Game determinedGame = SearchForGame(discoveredSignature, discoveredSignature.Flags.IGDBPlatformId, true);
|
||||||
|
|
||||||
// add to database
|
// 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
|
else
|
||||||
{
|
{
|
||||||
// file is a bios
|
// 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())
|
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, "");
|
string biosPath = biosItem.biosPath.Replace(biosItem.filename, "");
|
||||||
if (!Directory.Exists(biosPath))
|
if (!Directory.Exists(biosPath))
|
||||||
@@ -141,12 +159,26 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
File.Move(GameFileImportPath, biosItem.biosPath, true);
|
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)
|
public static IGDB.Models.Game SearchForGame(gaseous_server.Models.Signatures_Games Signature, long PlatformId, bool FullDownload)
|
||||||
@@ -197,8 +229,10 @@ namespace gaseous_server.Classes
|
|||||||
Logging.Log(Logging.LogType.Information, "Import Game", " " + games.Length + " search results found");
|
Logging.Log(Logging.LogType.Information, "Import Game", " " + games.Length + " search results found");
|
||||||
|
|
||||||
// quite likely we've found sequels and alternate types
|
// quite likely we've found sequels and alternate types
|
||||||
foreach (Game game in games) {
|
foreach (Game game in games)
|
||||||
if (game.Name == SearchCandidate) {
|
{
|
||||||
|
if (game.Name == SearchCandidate)
|
||||||
|
{
|
||||||
// found game title matches the search candidate
|
// found game title matches the search candidate
|
||||||
determinedGame = Metadata.Games.GetGame((long)games[0].Id, false, false, false);
|
determinedGame = Metadata.Games.GetGame((long)games[0].Id, false, false, false);
|
||||||
Logging.Log(Logging.LogType.Information, "Import Game", "Found exact match!");
|
Logging.Log(Logging.LogType.Information, "Import Game", "Found exact match!");
|
||||||
@@ -273,7 +307,8 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// assumption: no games have () in their titles so we'll remove them
|
// assumption: no games have () in their titles so we'll remove them
|
||||||
int idx = GameName.IndexOf('(');
|
int idx = GameName.IndexOf('(');
|
||||||
if (idx >= 0) {
|
if (idx >= 0)
|
||||||
|
{
|
||||||
GameName = GameName.Substring(0, idx);
|
GameName = GameName.Substring(0, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,10 +339,11 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
if (UpdateId == 0)
|
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
|
}
|
||||||
|
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("id", UpdateId);
|
||||||
}
|
}
|
||||||
dbDict.Add("platformid", Common.ReturnValueIfNull(determinedPlatform.Id, 0));
|
dbDict.Add("platformid", Common.ReturnValueIfNull(determinedPlatform.Id, 0));
|
||||||
@@ -322,6 +358,7 @@ namespace gaseous_server.Classes
|
|||||||
dbDict.Add("metadatagamename", discoveredSignature.Game.Name);
|
dbDict.Add("metadatagamename", discoveredSignature.Game.Name);
|
||||||
dbDict.Add("metadataversion", 2);
|
dbDict.Add("metadataversion", 2);
|
||||||
dbDict.Add("libraryid", library.Id);
|
dbDict.Add("libraryid", library.Id);
|
||||||
|
dbDict.Add("romdataversion", 2);
|
||||||
|
|
||||||
if (discoveredSignature.Rom.Attributes != null)
|
if (discoveredSignature.Rom.Attributes != null)
|
||||||
{
|
{
|
||||||
@@ -348,7 +385,8 @@ namespace gaseous_server.Classes
|
|||||||
if (UpdateId == 0)
|
if (UpdateId == 0)
|
||||||
{
|
{
|
||||||
romId = (long)romInsert.Rows[0][0];
|
romId = (long)romInsert.Rows[0][0];
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
romId = UpdateId;
|
romId = UpdateId;
|
||||||
}
|
}
|
||||||
@@ -485,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;
|
int maxWorkers = Config.MetadataConfiguration.MaxLibraryScanWorkers;
|
||||||
|
|
||||||
List<GameLibrary.LibraryItem> libraries = new List<GameLibrary.LibraryItem>();
|
if (LibrariesToScan.Count == 0)
|
||||||
if (singleLibrary == null)
|
|
||||||
{
|
{
|
||||||
libraries.AddRange(GameLibrary.GetLibraries);
|
LibrariesToScan.AddRange(GameLibrary.GetLibraries);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
libraries.Add(singleLibrary);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup background tasks for each library
|
// 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);
|
Logging.Log(Logging.LogType.Information, "Library Scan", "Starting worker process for library " + library.Name);
|
||||||
ProcessQueue.QueueItem queue = new ProcessQueue.QueueItem(
|
ProcessQueue.QueueItem queue = new ProcessQueue.QueueItem(
|
||||||
@@ -512,8 +568,10 @@ namespace gaseous_server.Classes
|
|||||||
ProcessQueue.QueueItemType.Rematcher
|
ProcessQueue.QueueItemType.Rematcher
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
true);
|
true)
|
||||||
queue.Options = library;
|
{
|
||||||
|
Options = library
|
||||||
|
};
|
||||||
queue.ForceExecute();
|
queue.ForceExecute();
|
||||||
|
|
||||||
ProcessQueue.QueueItems.Add(queue);
|
ProcessQueue.QueueItems.Add(queue);
|
||||||
@@ -524,9 +582,9 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
allowContinue = true;
|
allowContinue = true;
|
||||||
int currentWorkerCount = 0;
|
int currentWorkerCount = 0;
|
||||||
List<ProcessQueue.QueueItem> queueItems = new List<ProcessQueue.QueueItem>();
|
List<ProcessQueue.QueueItem> LibraryScan_QueueItems = new List<ProcessQueue.QueueItem>();
|
||||||
queueItems.AddRange(ProcessQueue.QueueItems);
|
LibraryScan_QueueItems.AddRange(ProcessQueue.QueueItems);
|
||||||
foreach (ProcessQueue.QueueItem item in queueItems)
|
foreach (ProcessQueue.QueueItem item in LibraryScan_QueueItems)
|
||||||
{
|
{
|
||||||
if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker)
|
if (item.ItemType == ProcessQueue.QueueItemType.LibraryScanWorker)
|
||||||
{
|
{
|
||||||
@@ -540,6 +598,7 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
} while (allowContinue == false);
|
} while (allowContinue == false);
|
||||||
}
|
}
|
||||||
|
} while (LibrariesToScan.Count > 0);
|
||||||
|
|
||||||
bool WorkersStillWorking;
|
bool WorkersStillWorking;
|
||||||
do
|
do
|
||||||
@@ -559,6 +618,12 @@ namespace gaseous_server.Classes
|
|||||||
} while (WorkersStillWorking == true);
|
} while (WorkersStillWorking == true);
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Library Scan", "Library scan complete. All workers stopped");
|
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)
|
public void LibrarySpecificScan(GameLibrary.LibraryItem library)
|
||||||
@@ -645,7 +710,7 @@ namespace gaseous_server.Classes
|
|||||||
long PlatformId;
|
long PlatformId;
|
||||||
IGDB.Models.Platform determinedPlatform;
|
IGDB.Models.Platform determinedPlatform;
|
||||||
|
|
||||||
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0 )
|
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0)
|
||||||
{
|
{
|
||||||
// no platform discovered in the signature
|
// no platform discovered in the signature
|
||||||
PlatformId = library.DefaultPlatformId;
|
PlatformId = library.DefaultPlatformId;
|
||||||
@@ -771,7 +836,7 @@ namespace gaseous_server.Classes
|
|||||||
long PlatformId;
|
long PlatformId;
|
||||||
IGDB.Models.Platform determinedPlatform;
|
IGDB.Models.Platform determinedPlatform;
|
||||||
|
|
||||||
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0 )
|
if (sig.Flags.IGDBPlatformId == null || sig.Flags.IGDBPlatformId == 0)
|
||||||
{
|
{
|
||||||
// no platform discovered in the signature
|
// no platform discovered in the signature
|
||||||
PlatformId = library.DefaultPlatformId;
|
PlatformId = library.DefaultPlatformId;
|
||||||
|
@@ -3,6 +3,7 @@ using System.Data;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Metadata.Ecma335;
|
using System.Reflection.Metadata.Ecma335;
|
||||||
|
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages;
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
public class Logging
|
public class Logging
|
||||||
@@ -21,8 +22,13 @@ namespace gaseous_server.Classes
|
|||||||
ExceptionValue = Common.ReturnValueIfNull(ExceptionValue, "").ToString()
|
ExceptionValue = Common.ReturnValueIfNull(ExceptionValue, "").ToString()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_ = Task.Run(() => WriteLogAsync(logItem, LogToDiskOnly));
|
||||||
|
}
|
||||||
|
|
||||||
|
static async Task WriteLogAsync(LogItem logItem, bool LogToDiskOnly)
|
||||||
|
{
|
||||||
bool AllowWrite = false;
|
bool AllowWrite = false;
|
||||||
if (EventType == LogType.Debug)
|
if (logItem.EventType == LogType.Debug)
|
||||||
{
|
{
|
||||||
if (Config.LoggingConfiguration.DebugLogging == true)
|
if (Config.LoggingConfiguration.DebugLogging == true)
|
||||||
{
|
{
|
||||||
@@ -42,26 +48,32 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
TraceOutput += Environment.NewLine + logItem.ExceptionValue.ToString();
|
TraceOutput += Environment.NewLine + logItem.ExceptionValue.ToString();
|
||||||
}
|
}
|
||||||
switch(logItem.EventType) {
|
string consoleColour = "";
|
||||||
|
switch (logItem.EventType)
|
||||||
|
{
|
||||||
case LogType.Information:
|
case LogType.Information:
|
||||||
Console.ForegroundColor = ConsoleColor.Blue;
|
// Console.ForegroundColor = ConsoleColor.Blue;
|
||||||
|
consoleColour = "\u001b[1;34m]";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LogType.Warning:
|
case LogType.Warning:
|
||||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
// Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
consoleColour = "\u001b[1;33m]";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LogType.Critical:
|
case LogType.Critical:
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
// Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
consoleColour = "\u001b[1;31m]";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LogType.Debug:
|
case LogType.Debug:
|
||||||
Console.ForegroundColor = ConsoleColor.Magenta;
|
// Console.ForegroundColor = ConsoleColor.Magenta;
|
||||||
|
consoleColour = "\u001b[1;36m]";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
Console.WriteLine(TraceOutput);
|
Console.WriteLine(consoleColour + TraceOutput);
|
||||||
Console.ResetColor();
|
// Console.ResetColor();
|
||||||
|
|
||||||
if (WriteToDiskOnly == true)
|
if (WriteToDiskOnly == true)
|
||||||
{
|
{
|
||||||
|
@@ -16,6 +16,7 @@ namespace gaseous_server.Classes
|
|||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
|
||||||
// remove any entries from the library that have an invalid id
|
// remove any entries from the library that have an invalid id
|
||||||
|
Logging.Log(Logging.LogType.Information, "Maintenance", "Removing any entries from the library that have an invalid id");
|
||||||
string LibraryWhereClause = "";
|
string LibraryWhereClause = "";
|
||||||
foreach (GameLibrary.LibraryItem library in GameLibrary.GetLibraries)
|
foreach (GameLibrary.LibraryItem library in GameLibrary.GetLibraries)
|
||||||
{
|
{
|
||||||
@@ -33,9 +34,29 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete old logs
|
// delete old logs
|
||||||
sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRetentionDate;";
|
Logging.Log(Logging.LogType.Information, "Maintenance", "Removing logs older than " + Config.LoggingConfiguration.LogRetention + " days");
|
||||||
|
long deletedCount = 1;
|
||||||
|
long deletedEventCount = 0;
|
||||||
|
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));
|
dbDict.Add("EventRetentionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
|
||||||
db.ExecuteCMD(sql, dbDict);
|
while (deletedCount > 0)
|
||||||
|
{
|
||||||
|
DataTable deletedCountTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Maintenance", "Hit the maximum number of loops for deleting logs. Stopping.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Logging.Log(Logging.LogType.Information, "Maintenance", "Deleted " + deletedEventCount + " log entries");
|
||||||
|
|
||||||
// delete files and directories older than 7 days in PathsToClean
|
// delete files and directories older than 7 days in PathsToClean
|
||||||
List<string> PathsToClean = new List<string>();
|
List<string> PathsToClean = new List<string>();
|
||||||
@@ -87,7 +108,7 @@ namespace gaseous_server.Classes
|
|||||||
SetStatus(StatusCounter, tables.Rows.Count, "Optimising table " + row[0].ToString());
|
SetStatus(StatusCounter, tables.Rows.Count, "Optimising table " + row[0].ToString());
|
||||||
|
|
||||||
sql = "OPTIMIZE TABLE " + row[0].ToString();
|
sql = "OPTIMIZE TABLE " + row[0].ToString();
|
||||||
DataTable response = db.ExecuteCMD(sql);
|
DataTable response = db.ExecuteCMD(sql, new Dictionary<string, object>(), 240);
|
||||||
foreach (DataRow responseRow in response.Rows)
|
foreach (DataRow responseRow in response.Rows)
|
||||||
{
|
{
|
||||||
string retVal = "";
|
string retVal = "";
|
||||||
|
@@ -216,44 +216,48 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly static AgeGroupItem Adult_Item = new AgeGroupItem{
|
readonly static AgeGroupItem Adult_Item = new AgeGroupItem
|
||||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC },
|
{
|
||||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_Z },
|
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_R18, AgeRatingTitle.ACB_RC },
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Eighteen },
|
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_Z },
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.RP, AgeRatingTitle.AO },
|
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Eighteen },
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Eighteen },
|
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.RP, AgeRatingTitle.AO },
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Eighteen},
|
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Eighteen },
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_18}
|
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Eighteen },
|
||||||
|
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_18 }
|
||||||
};
|
};
|
||||||
|
|
||||||
readonly static AgeGroupItem Mature_Item = new AgeGroupItem{
|
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 },
|
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_M, AgeRatingTitle.ACB_MA15 },
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Sixteen },
|
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_C, AgeRatingTitle.CERO_D },
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.M },
|
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Sixteen },
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Fifteen },
|
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.M },
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Sixteen},
|
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Fifteen },
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_16}
|
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Sixteen },
|
||||||
|
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_16 }
|
||||||
};
|
};
|
||||||
|
|
||||||
readonly static AgeGroupItem Teen_Item = new AgeGroupItem{
|
readonly static AgeGroupItem Teen_Item = new AgeGroupItem
|
||||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_PG },
|
{
|
||||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_B },
|
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_PG },
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_Twelve, AgeRatingTitle.CLASS_IND_Fourteen },
|
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_B },
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.T },
|
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_Twelve, AgeRatingTitle.CLASS_IND_Fourteen },
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_Twelve },
|
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.T },
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Twelve},
|
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_Twelve },
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_12}
|
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Twelve },
|
||||||
|
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_12 }
|
||||||
};
|
};
|
||||||
|
|
||||||
readonly static AgeGroupItem Child_Item = new AgeGroupItem{
|
readonly static AgeGroupItem Child_Item = new AgeGroupItem
|
||||||
ACB = new List<AgeRatingTitle>{ AgeRatingTitle.ACB_G },
|
{
|
||||||
CERO = new List<AgeRatingTitle>{ AgeRatingTitle.CERO_A },
|
ACB = new List<AgeRatingTitle> { AgeRatingTitle.ACB_G },
|
||||||
CLASS_IND = new List<AgeRatingTitle>{ AgeRatingTitle.CLASS_IND_L, AgeRatingTitle.CLASS_IND_Ten },
|
CERO = new List<AgeRatingTitle> { AgeRatingTitle.CERO_A },
|
||||||
ESRB = new List<AgeRatingTitle>{ AgeRatingTitle.E, AgeRatingTitle.E10 },
|
CLASS_IND = new List<AgeRatingTitle> { AgeRatingTitle.CLASS_IND_L, AgeRatingTitle.CLASS_IND_Ten },
|
||||||
GRAC = new List<AgeRatingTitle>{ AgeRatingTitle.GRAC_All },
|
ESRB = new List<AgeRatingTitle> { AgeRatingTitle.EC, AgeRatingTitle.E, AgeRatingTitle.E10 },
|
||||||
PEGI = new List<AgeRatingTitle>{ AgeRatingTitle.Three, AgeRatingTitle.Seven},
|
GRAC = new List<AgeRatingTitle> { AgeRatingTitle.GRAC_All },
|
||||||
USK = new List<AgeRatingTitle>{ AgeRatingTitle.USK_0, AgeRatingTitle.USK_6}
|
PEGI = new List<AgeRatingTitle> { AgeRatingTitle.Three, AgeRatingTitle.Seven },
|
||||||
|
USK = new List<AgeRatingTitle> { AgeRatingTitle.USK_0, AgeRatingTitle.USK_6 }
|
||||||
};
|
};
|
||||||
|
|
||||||
public class AgeGroupItem
|
public class AgeGroupItem
|
||||||
|
@@ -74,8 +74,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
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;
|
forceImageDownload = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, 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)
|
if (InRateLimitAvoidanceMode == true)
|
||||||
{
|
{
|
||||||
// sleep for a moment to help avoid hitting the rate limiter
|
// 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);
|
Thread.Sleep(RateLimitAvoidanceWait);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +246,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "API Connection", "Exception when accessing endpoint " + Endpoint, ex);
|
Logging.Log(Logging.LogType.Warning, "API Connection", "Exception when accessing endpoint " + Endpoint, ex);
|
||||||
throw;
|
throw;
|
||||||
@@ -393,6 +394,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
if (InRateLimitAvoidanceMode == true)
|
if (InRateLimitAvoidanceMode == true)
|
||||||
{
|
{
|
||||||
// sleep for a moment to help avoid hitting the rate limiter
|
// 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);
|
Thread.Sleep(RateLimitAvoidanceWait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -76,8 +76,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
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;
|
forceImageDownload = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, 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);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
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;
|
forceImageDownload = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, 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;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
using gaseous_server.Models;
|
||||||
using IGDB;
|
using IGDB;
|
||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
|
|
||||||
@@ -7,7 +8,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
public class Games
|
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()
|
public Games()
|
||||||
{
|
{
|
||||||
@@ -17,7 +18,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
public class InvalidGameId : Exception
|
public class InvalidGameId : Exception
|
||||||
{
|
{
|
||||||
public InvalidGameId(long Id) : base("Unable to find Game by id " + Id)
|
public InvalidGameId(long Id) : base("Unable to find Game by id " + Id)
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Game? GetGame(long Id, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
public static Game? GetGame(long Id, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
||||||
@@ -78,15 +79,17 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
if (cacheStatus == Storage.CacheStatus.Current) { cacheStatus = Storage.CacheStatus.Expired; }
|
if (cacheStatus == Storage.CacheStatus.Current) { cacheStatus = Storage.CacheStatus.Expired; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// set up where clause
|
|
||||||
string WhereClause = "";
|
string WhereClause = "";
|
||||||
|
string searchField = "";
|
||||||
switch (searchUsing)
|
switch (searchUsing)
|
||||||
{
|
{
|
||||||
case SearchUsing.id:
|
case SearchUsing.id:
|
||||||
WhereClause = "where id = " + searchValue;
|
WhereClause = "where id = " + searchValue;
|
||||||
|
searchField = "id";
|
||||||
break;
|
break;
|
||||||
case SearchUsing.slug:
|
case SearchUsing.slug:
|
||||||
WhereClause = "where slug = " + searchValue;
|
WhereClause = "where slug = \"" + searchValue + "\"";
|
||||||
|
searchField = "slug";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception("Invalid search type");
|
throw new Exception("Invalid search type");
|
||||||
@@ -110,11 +113,11 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||||
returnValue = Storage.GetCacheValue<Game>(returnValue, "id", (long)searchValue);
|
returnValue = Storage.GetCacheValue<Game>(returnValue, searchField, searchValue);
|
||||||
}
|
}
|
||||||
return returnValue;
|
return returnValue;
|
||||||
case Storage.CacheStatus.Current:
|
case Storage.CacheStatus.Current:
|
||||||
returnValue = Storage.GetCacheValue<Game>(returnValue, "id", (long)searchValue);
|
returnValue = Storage.GetCacheValue<Game>(returnValue, searchField, searchValue);
|
||||||
UpdateSubClasses(returnValue, false, false, false);
|
UpdateSubClasses(returnValue, false, false, false);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
default:
|
default:
|
||||||
@@ -125,17 +128,17 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
private static void UpdateSubClasses(Game Game, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
private static void UpdateSubClasses(Game Game, bool getAllMetadata, bool followSubGames, bool forceRefresh)
|
||||||
{
|
{
|
||||||
// required metadata
|
// required metadata
|
||||||
if (Game.Cover != null)
|
// if (Game.Cover != null)
|
||||||
{
|
// {
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
Cover GameCover = Covers.GetCover(Game.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game), forceRefresh);
|
// Cover GameCover = Covers.GetCover(Game.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(Game), forceRefresh);
|
||||||
}
|
// }
|
||||||
catch (Exception ex)
|
// catch (Exception ex)
|
||||||
{
|
// {
|
||||||
Logging.Log(Logging.LogType.Critical, "Game Metadata", "Unable to fetch cover artwork.", ex);
|
// Logging.Log(Logging.LogType.Critical, "Game Metadata", "Unable to fetch cover artwork.", ex);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (Game.Genres != null)
|
if (Game.Genres != null)
|
||||||
{
|
{
|
||||||
@@ -439,7 +442,8 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
foreach (DataRow row in data.Rows)
|
foreach (DataRow row in data.Rows)
|
||||||
{
|
{
|
||||||
Game game = new Game{
|
Game game = new Game
|
||||||
|
{
|
||||||
Id = (long)row["Id"],
|
Id = (long)row["Id"],
|
||||||
Name = (string)Common.ReturnValueIfNull(row["Name"], ""),
|
Name = (string)Common.ReturnValueIfNull(row["Name"], ""),
|
||||||
Slug = (string)Common.ReturnValueIfNull(row["Slug"], ""),
|
Slug = (string)Common.ReturnValueIfNull(row["Slug"], ""),
|
||||||
@@ -501,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);
|
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`;";
|
string sql = @"
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
SELECT DISTINCT
|
||||||
dbDict.Add("gameid", GameId);
|
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);
|
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)
|
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);
|
platforms.Add(valuePair);
|
||||||
}
|
}
|
||||||
|
|
||||||
return platforms;
|
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
|
public enum SearchType
|
||||||
{
|
{
|
||||||
where = 0,
|
where = 0,
|
||||||
@@ -539,6 +674,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
this.Id = gameObject.Id;
|
this.Id = gameObject.Id;
|
||||||
this.Name = gameObject.Name;
|
this.Name = gameObject.Name;
|
||||||
this.Slug = gameObject.Slug;
|
this.Slug = gameObject.Slug;
|
||||||
|
this.Summary = gameObject.Summary;
|
||||||
this.TotalRating = gameObject.TotalRating;
|
this.TotalRating = gameObject.TotalRating;
|
||||||
this.TotalRatingCount = gameObject.TotalRatingCount;
|
this.TotalRatingCount = gameObject.TotalRatingCount;
|
||||||
this.Cover = gameObject.Cover;
|
this.Cover = gameObject.Cover;
|
||||||
@@ -564,6 +700,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
public long Index { get; set; }
|
public long Index { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Slug { get; set; }
|
public string Slug { get; set; }
|
||||||
|
public string Summary { get; set; }
|
||||||
public double? TotalRating { get; set; }
|
public double? TotalRating { get; set; }
|
||||||
public int? TotalRatingCount { get; set; }
|
public int? TotalRatingCount { get; set; }
|
||||||
public bool HasSavedGame { get; set; } = false;
|
public bool HasSavedGame { get; set; } = false;
|
||||||
|
@@ -76,8 +76,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
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;
|
forceImageDownload = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||||
|
@@ -13,7 +13,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlatformVersion? GetPlatformVersion(long Id, Platform ParentPlatform)
|
public static PlatformVersion? GetPlatformVersion(long Id, Platform ParentPlatform, bool GetImages = false)
|
||||||
{
|
{
|
||||||
if (Id == 0)
|
if (Id == 0)
|
||||||
{
|
{
|
||||||
@@ -21,18 +21,18 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.id, Id, ParentPlatform);
|
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.id, Id, ParentPlatform, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlatformVersion GetPlatformVersion(string Slug, Platform ParentPlatform)
|
public static PlatformVersion GetPlatformVersion(string Slug, Platform ParentPlatform, bool GetImages = false)
|
||||||
{
|
{
|
||||||
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.slug, Slug, ParentPlatform);
|
Task<PlatformVersion> RetVal = _GetPlatformVersion(SearchUsing.slug, Slug, ParentPlatform, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<PlatformVersion> _GetPlatformVersion(SearchUsing searchUsing, object searchValue, Platform ParentPlatform)
|
private static async Task<PlatformVersion> _GetPlatformVersion(SearchUsing searchUsing, object searchValue, Platform ParentPlatform, bool GetImages)
|
||||||
{
|
{
|
||||||
// check database first
|
// check database first
|
||||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||||
@@ -67,7 +67,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
if (returnValue != null)
|
if (returnValue != null)
|
||||||
{
|
{
|
||||||
Storage.NewCacheValue(returnValue);
|
Storage.NewCacheValue(returnValue);
|
||||||
UpdateSubClasses(ParentPlatform, returnValue);
|
UpdateSubClasses(ParentPlatform, returnValue, GetImages);
|
||||||
}
|
}
|
||||||
return returnValue;
|
return returnValue;
|
||||||
case Storage.CacheStatus.Expired:
|
case Storage.CacheStatus.Expired:
|
||||||
@@ -75,7 +75,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause);
|
returnValue = await GetObjectFromServer(WhereClause);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
UpdateSubClasses(ParentPlatform, returnValue);
|
UpdateSubClasses(ParentPlatform, returnValue, GetImages);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -90,7 +90,9 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateSubClasses(Platform ParentPlatform, PlatformVersion platformVersion)
|
private static void UpdateSubClasses(Platform ParentPlatform, PlatformVersion platformVersion, bool GetImages)
|
||||||
|
{
|
||||||
|
if (GetImages == true)
|
||||||
{
|
{
|
||||||
if (platformVersion.PlatformLogo != null)
|
if (platformVersion.PlatformLogo != null)
|
||||||
{
|
{
|
||||||
@@ -104,6 +106,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private enum SearchUsing
|
private enum SearchUsing
|
||||||
{
|
{
|
||||||
|
@@ -15,7 +15,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Platform? GetPlatform(long Id, bool forceRefresh = false)
|
public static Platform? GetPlatform(long Id, bool forceRefresh = false, bool GetImages = false)
|
||||||
{
|
{
|
||||||
if (Id == 0)
|
if (Id == 0)
|
||||||
{
|
{
|
||||||
@@ -41,10 +41,10 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Task<Platform> RetVal = _GetPlatform(SearchUsing.id, Id, forceRefresh);
|
Task<Platform> RetVal = _GetPlatform(SearchUsing.id, Id, forceRefresh, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Metadata", "An error occurred fetching Platform Id " + Id, ex);
|
Logging.Log(Logging.LogType.Warning, "Metadata", "An error occurred fetching Platform Id " + Id, ex);
|
||||||
return null;
|
return null;
|
||||||
@@ -52,13 +52,13 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Platform GetPlatform(string Slug, bool forceRefresh = false)
|
public static Platform GetPlatform(string Slug, bool forceRefresh = false, bool GetImages = false)
|
||||||
{
|
{
|
||||||
Task<Platform> RetVal = _GetPlatform(SearchUsing.slug, Slug, forceRefresh);
|
Task<Platform> RetVal = _GetPlatform(SearchUsing.slug, Slug, forceRefresh, GetImages);
|
||||||
return RetVal.Result;
|
return RetVal.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Platform> _GetPlatform(SearchUsing searchUsing, object searchValue, bool forceRefresh)
|
private static async Task<Platform> _GetPlatform(SearchUsing searchUsing, object searchValue, bool forceRefresh, bool GetImages)
|
||||||
{
|
{
|
||||||
// check database first
|
// check database first
|
||||||
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
Storage.CacheStatus? cacheStatus = new Storage.CacheStatus();
|
||||||
@@ -78,13 +78,16 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
// set up where clause
|
// set up where clause
|
||||||
string WhereClause = "";
|
string WhereClause = "";
|
||||||
|
string searchField = "";
|
||||||
switch (searchUsing)
|
switch (searchUsing)
|
||||||
{
|
{
|
||||||
case SearchUsing.id:
|
case SearchUsing.id:
|
||||||
WhereClause = "where id = " + searchValue;
|
WhereClause = "where id = " + searchValue;
|
||||||
|
searchField = "id";
|
||||||
break;
|
break;
|
||||||
case SearchUsing.slug:
|
case SearchUsing.slug:
|
||||||
WhereClause = "where slug = " + searchValue;
|
WhereClause = "where slug = \"" + searchValue + "\"";
|
||||||
|
searchField = "slug";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception("Invalid search type");
|
throw new Exception("Invalid search type");
|
||||||
@@ -96,7 +99,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
case Storage.CacheStatus.NotPresent:
|
case Storage.CacheStatus.NotPresent:
|
||||||
returnValue = await GetObjectFromServer(WhereClause);
|
returnValue = await GetObjectFromServer(WhereClause);
|
||||||
Storage.NewCacheValue(returnValue);
|
Storage.NewCacheValue(returnValue);
|
||||||
UpdateSubClasses(returnValue);
|
UpdateSubClasses(returnValue, GetImages);
|
||||||
AddPlatformMapping(returnValue);
|
AddPlatformMapping(returnValue);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
case Storage.CacheStatus.Expired:
|
case Storage.CacheStatus.Expired:
|
||||||
@@ -104,23 +107,23 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause);
|
returnValue = await GetObjectFromServer(WhereClause);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
Storage.NewCacheValue(returnValue, true);
|
||||||
UpdateSubClasses(returnValue);
|
UpdateSubClasses(returnValue, GetImages);
|
||||||
AddPlatformMapping(returnValue);
|
AddPlatformMapping(returnValue);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, ex);
|
||||||
return Storage.GetCacheValue<Platform>(returnValue, "id", (long)searchValue);
|
return Storage.GetCacheValue<Platform>(returnValue, searchField, searchValue);
|
||||||
}
|
}
|
||||||
case Storage.CacheStatus.Current:
|
case Storage.CacheStatus.Current:
|
||||||
return Storage.GetCacheValue<Platform>(returnValue, "id", (long)searchValue);
|
return Storage.GetCacheValue<Platform>(returnValue, searchField, searchValue);
|
||||||
default:
|
default:
|
||||||
throw new Exception("How did you get here?");
|
throw new Exception("How did you get here?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateSubClasses(Platform platform)
|
private static void UpdateSubClasses(Platform platform, bool GetImages)
|
||||||
{
|
{
|
||||||
if (platform.Versions != null)
|
if (platform.Versions != null)
|
||||||
{
|
{
|
||||||
@@ -130,6 +133,8 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GetImages == true)
|
||||||
|
{
|
||||||
if (platform.PlatformLogo != null)
|
if (platform.PlatformLogo != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -142,6 +147,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void AddPlatformMapping(Platform platform)
|
private static void AddPlatformMapping(Platform platform)
|
||||||
{
|
{
|
||||||
@@ -158,11 +164,12 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Platform Map", "Importing " + platform.Name + " from predefined data.");
|
Logging.Log(Logging.LogType.Information, "Platform Map", "Importing " + platform.Name + " from predefined data.");
|
||||||
// doesn't exist - add it
|
// doesn't exist - add it
|
||||||
item = new Models.PlatformMapping.PlatformMapItem{
|
item = new Models.PlatformMapping.PlatformMapItem
|
||||||
|
{
|
||||||
IGDBId = (long)platform.Id,
|
IGDBId = (long)platform.Id,
|
||||||
IGDBName = platform.Name,
|
IGDBName = platform.Name,
|
||||||
IGDBSlug = platform.Slug,
|
IGDBSlug = platform.Slug,
|
||||||
AlternateNames = new List<string>{ platform.AlternativeName }
|
AlternateNames = new List<string> { platform.AlternativeName }
|
||||||
};
|
};
|
||||||
Models.PlatformMapping.WritePlatformMap(item, false, true);
|
Models.PlatformMapping.WritePlatformMap(item, false, true);
|
||||||
}
|
}
|
||||||
|
@@ -74,8 +74,14 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
returnValue = await GetObjectFromServer(WhereClause, ImagePath);
|
||||||
Storage.NewCacheValue(returnValue, true);
|
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;
|
forceImageDownload = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Metadata: " + returnValue.GetType().Name, "An error occurred while connecting to IGDB. WhereClause: " + WhereClause, 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("Endpoint", Endpoint);
|
||||||
dbDict.Add(SearchField, SearchValue);
|
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)
|
if (dt.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// no data stored for this item
|
// no data stored for this item
|
||||||
@@ -428,6 +428,30 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void CreateRelationsTables<T>()
|
||||||
|
{
|
||||||
|
string PrimaryTable = typeof(T).Name;
|
||||||
|
foreach (PropertyInfo property in typeof(T).GetProperties())
|
||||||
|
{
|
||||||
|
string SecondaryTable = property.Name;
|
||||||
|
|
||||||
|
if (property.PropertyType.Name == "IdentitiesOrValues`1")
|
||||||
|
{
|
||||||
|
|
||||||
|
string TableName = "Relation_" + PrimaryTable + "_" + SecondaryTable;
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT * FROM information_schema.tables WHERE table_schema = '" + Config.DatabaseConfiguration.DatabaseName + "' AND table_name = '" + TableName + "';";
|
||||||
|
DataTable data = db.ExecuteCMD(sql);
|
||||||
|
if (data.Rows.Count == 0)
|
||||||
|
{
|
||||||
|
// table doesn't exist, create it
|
||||||
|
sql = "CREATE TABLE `" + Config.DatabaseConfiguration.DatabaseName + "`.`" + TableName + "` (`" + PrimaryTable + "Id` BIGINT NOT NULL, `" + SecondaryTable + "Id` BIGINT NOT NULL, PRIMARY KEY (`" + PrimaryTable + "Id`, `" + SecondaryTable + "Id`), INDEX `idx_PrimaryColumn` (`" + PrimaryTable + "Id` ASC) VISIBLE);";
|
||||||
|
db.ExecuteCMD(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class MemoryCacheObject
|
private class MemoryCacheObject
|
||||||
{
|
{
|
||||||
public object Object { get; set; }
|
public object Object { get; set; }
|
||||||
|
@@ -16,7 +16,7 @@ namespace gaseous_server.Classes
|
|||||||
public class InvalidMediaGroupId : Exception
|
public class InvalidMediaGroupId : Exception
|
||||||
{
|
{
|
||||||
public InvalidMediaGroupId(long Id) : base("Unable to find media group by id " + Id)
|
public InvalidMediaGroupId(long Id) : base("Unable to find media group by id " + Id)
|
||||||
{}
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameRomMediaGroupItem CreateMediaGroup(long GameId, long PlatformId, List<long> RomIds)
|
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);
|
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>
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ "gameid", GameId },
|
{ "gameid", GameId },
|
||||||
{ "userid", userid }
|
{ "userid", userid },
|
||||||
|
{ "platformid", PlatformId }
|
||||||
};
|
};
|
||||||
|
|
||||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -165,7 +193,7 @@ namespace gaseous_server.Classes
|
|||||||
public static void DeleteMediaGroup(long Id)
|
public static void DeleteMediaGroup(long Id)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
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>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", Id);
|
dbDict.Add("id", Id);
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -188,14 +216,34 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem();
|
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem
|
||||||
mediaGroupItem.Id = (long)row["Id"];
|
{
|
||||||
mediaGroupItem.Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"];
|
Id = (long)row["Id"],
|
||||||
mediaGroupItem.PlatformId = (long)row["PlatformId"];
|
Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"],
|
||||||
mediaGroupItem.GameId = (long)row["GameId"];
|
PlatformId = (long)row["PlatformId"],
|
||||||
mediaGroupItem.RomIds = new List<long>();
|
GameId = (long)row["GameId"],
|
||||||
mediaGroupItem.Roms = new List<Roms.GameRomItem>();
|
RomIds = new List<long>(),
|
||||||
mediaGroupItem.HasSaveStates = hasSaveStates;
|
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
|
// get members
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
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;
|
return mediaGroupItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,7 +337,7 @@ namespace gaseous_server.Classes
|
|||||||
if (File.Exists(rom.Path))
|
if (File.Exists(rom.Path))
|
||||||
{
|
{
|
||||||
string romExt = Path.GetExtension(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);
|
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 Id { get; set; }
|
||||||
public long GameId { get; set; }
|
public long GameId { get; set; }
|
||||||
public long PlatformId { get; set; }
|
public long PlatformId { get; set; }
|
||||||
public string Platform {
|
public string Platform
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
try
|
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<long> RomIds { get; set; }
|
||||||
public List<Roms.GameRomItem> Roms { get; set; }
|
public List<Roms.GameRomItem> Roms { get; set; }
|
||||||
public bool HasSaveStates { get; set; } = false;
|
public bool HasSaveStates { get; set; } = false;
|
||||||
|
public bool RomUserLastUsed { get; set; }
|
||||||
|
public bool RomUserFavourite { get; set; }
|
||||||
private GroupBuildStatus _Status { get; set; }
|
private GroupBuildStatus _Status { get; set; }
|
||||||
public GroupBuildStatus Status {
|
public GroupBuildStatus Status
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_Status == GroupBuildStatus.Completed)
|
if (_Status == GroupBuildStatus.Completed)
|
||||||
@@ -557,7 +596,8 @@ namespace gaseous_server.Classes
|
|||||||
_Status = value;
|
_Status = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public long? Size {
|
public long? Size
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (Status == GroupBuildStatus.Completed)
|
if (Status == GroupBuildStatus.Completed)
|
||||||
|
@@ -4,6 +4,9 @@ using gaseous_signature_parser.models.RomSignatureObject;
|
|||||||
using static gaseous_server.Classes.RomMediaGroup;
|
using static gaseous_server.Classes.RomMediaGroup;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
|
using static HasheousClient.Models.FixMatchModel;
|
||||||
|
using NuGet.Protocol.Core.Types;
|
||||||
|
using static gaseous_server.Classes.FileSignature;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
@@ -12,7 +15,13 @@ namespace gaseous_server.Classes
|
|||||||
public class InvalidRomId : Exception
|
public class InvalidRomId : Exception
|
||||||
{
|
{
|
||||||
public InvalidRomId(long Id) : base("Unable to find ROM by id " + Id)
|
public InvalidRomId(long Id) : base("Unable to find ROM by id " + Id)
|
||||||
{}
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InvalidRomHash : Exception
|
||||||
|
{
|
||||||
|
public InvalidRomHash(String Hash) : base("Unable to find ROM by hash " + Hash)
|
||||||
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameRomObject GetRoms(long GameId, long PlatformId = -1, string NameSearch = "", int pageNumber = 0, int pageSize = 0, string userid = "")
|
public static GameRomObject GetRoms(long GameId, long PlatformId = -1, string NameSearch = "", int pageNumber = 0, int pageSize = 0, string userid = "")
|
||||||
@@ -34,27 +43,50 @@ namespace gaseous_server.Classes
|
|||||||
dbDict.Add("namesearch", '%' + NameSearch + '%');
|
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
|
// 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`;";
|
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) {
|
if (PlatformId == -1)
|
||||||
|
{
|
||||||
// data query
|
// 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
|
// count query
|
||||||
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id" + NameSearchWhere + ";";
|
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id" + NameSearchWhere + ";";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// data query
|
// 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
|
// count query
|
||||||
sqlCount = "SELECT COUNT(Games_Roms.Id) AS RomCount FROM Games_Roms WHERE Games_Roms.GameId = @id AND Games_Roms.PlatformId = @platformid" + NameSearchWhere + ";";
|
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);
|
dbDict.Add("platformid", PlatformId);
|
||||||
}
|
}
|
||||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
DataTable romDT = db.ExecuteCMD(sql, dbDict, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromMinutes(1).Ticks));
|
||||||
Dictionary<string, object> rowCount = db.ExecuteCMDDict(sqlCount, dbDict)[0];
|
Dictionary<string, object> rowCount = db.ExecuteCMDDict(sqlCount, dbDict, new Database.DatabaseMemoryCacheOptions(true, (int)TimeSpan.FromMinutes(1).Ticks))[0];
|
||||||
DataTable platformDT = db.ExecuteCMD(sqlPlatform, dbDict);
|
|
||||||
|
|
||||||
if (romDT.Rows.Count > 0)
|
if (romDT.Rows.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -64,10 +96,9 @@ namespace gaseous_server.Classes
|
|||||||
int pageOffset = pageSize * (pageNumber - 1);
|
int pageOffset = pageSize * (pageNumber - 1);
|
||||||
for (int i = 0; i < romDT.Rows.Count; i++)
|
for (int i = 0; i < romDT.Rows.Count; i++)
|
||||||
{
|
{
|
||||||
GameRomItem gameRomItem = BuildRom(romDT.Rows[i]);
|
|
||||||
|
|
||||||
if ((i >= pageOffset && i < pageOffset + pageSize) || pageSize == 0)
|
if ((i >= pageOffset && i < pageOffset + pageSize) || pageSize == 0)
|
||||||
{
|
{
|
||||||
|
GameRomItem gameRomItem = BuildRom(romDT.Rows[i]);
|
||||||
GameRoms.GameRomItems.Add(gameRomItem);
|
GameRoms.GameRomItems.Add(gameRomItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,7 +114,7 @@ namespace gaseous_server.Classes
|
|||||||
public static GameRomItem GetRom(long RomId)
|
public static GameRomItem GetRom(long RomId)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
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>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", RomId);
|
dbDict.Add("id", RomId);
|
||||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -100,6 +131,26 @@ 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, 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);
|
||||||
|
|
||||||
|
if (romDT.Rows.Count > 0)
|
||||||
|
{
|
||||||
|
DataRow romDR = romDT.Rows[0];
|
||||||
|
GameRomItem romItem = BuildRom(romDR);
|
||||||
|
return romItem;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidRomHash(MD5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static GameRomItem UpdateRom(long RomId, long PlatformId, long GameId)
|
public static GameRomItem UpdateRom(long RomId, long PlatformId, long GameId)
|
||||||
{
|
{
|
||||||
// ensure metadata for platformid is present
|
// ensure metadata for platformid is present
|
||||||
@@ -118,6 +169,53 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
GameRomItem rom = GetRom(RomId);
|
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;
|
return rom;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +230,7 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
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>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", RomId);
|
dbDict.Add("id", RomId);
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -150,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
|
GameRomItem romItem = new GameRomItem
|
||||||
{
|
{
|
||||||
Id = (long)romDR["id"],
|
Id = (long)romDR["id"],
|
||||||
PlatformId = (long)romDR["platformid"],
|
PlatformId = (long)romDR["platformid"],
|
||||||
Platform = (string)romDR["platformname"],
|
Platform = (string)romDR["platformname"],
|
||||||
GameId = (long)romDR["gameid"],
|
GameId = (long)romDR["gameid"],
|
||||||
|
Game = (string)romDR["gamename"],
|
||||||
Name = (string)romDR["name"],
|
Name = (string)romDR["name"],
|
||||||
Size = (long)romDR["size"],
|
Size = (long)romDR["size"],
|
||||||
Crc = ((string)romDR["crc"]).ToLower(),
|
Crc = ((string)romDR["crc"]).ToLower(),
|
||||||
Md5 = ((string)romDR["md5"]).ToLower(),
|
Md5 = ((string)romDR["md5"]).ToLower(),
|
||||||
Sha1 = ((string)romDR["sha1"]).ToLower(),
|
Sha1 = ((string)romDR["sha1"]).ToLower(),
|
||||||
DevelopmentStatus = (string)romDR["developmentstatus"],
|
DevelopmentStatus = (string)romDR["developmentstatus"],
|
||||||
Attributes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<KeyValuePair<string, object>>>((string)Common.ReturnValueIfNull(romDR["attributes"], "[ ]")),
|
Attributes = romAttributes,
|
||||||
RomType = (HasheousClient.Models.LookupResponseModel.RomItem.RomTypes)(int)romDR["romtype"],
|
RomType = (HasheousClient.Models.SignatureModel.RomItem.RomTypes)(int)romDR["romtype"],
|
||||||
RomTypeMedia = (string)romDR["romtypemedia"],
|
RomTypeMedia = (string)romDR["romtypemedia"],
|
||||||
MediaLabel = (string)romDR["medialabel"],
|
MediaLabel = (string)romDR["medialabel"],
|
||||||
Path = (string)romDR["path"],
|
Path = (string)romDR["path"],
|
||||||
@@ -173,16 +288,22 @@ namespace gaseous_server.Classes
|
|||||||
Library = GameLibrary.GetLibrary((int)romDR["LibraryId"])
|
Library = GameLibrary.GetLibrary((int)romDR["LibraryId"])
|
||||||
};
|
};
|
||||||
|
|
||||||
// check for a web emulator and update the romItem
|
romItem.RomUserLastUsed = false;
|
||||||
foreach (Models.PlatformMapping.PlatformMapItem platformMapping in Models.PlatformMapping.PlatformMap)
|
if (romDR.Table.Columns.Contains("MostRecentRomId"))
|
||||||
{
|
{
|
||||||
if (platformMapping.IGDBId == romItem.PlatformId)
|
if (romDR["MostRecentRomId"] != DBNull.Value)
|
||||||
{
|
{
|
||||||
if (platformMapping.WebEmulator != null)
|
romItem.RomUserLastUsed = true;
|
||||||
{
|
|
||||||
romItem.Emulator = platformMapping.WebEmulator;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
romItem.RomUserFavourite = false;
|
||||||
|
if (romDR.Table.Columns.Contains("FavouriteRomId"))
|
||||||
|
{
|
||||||
|
if (romDR["FavouriteRomId"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
romItem.RomUserFavourite = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return romItem;
|
return romItem;
|
||||||
@@ -194,16 +315,18 @@ namespace gaseous_server.Classes
|
|||||||
public int Count { get; set; }
|
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 long PlatformId { get; set; }
|
||||||
public string Platform { get; set; }
|
public string Platform { get; set; }
|
||||||
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
|
||||||
public long GameId { get; set; }
|
public long GameId { get; set; }
|
||||||
|
public string Game { get; set; }
|
||||||
public string? Path { get; set; }
|
public string? Path { get; set; }
|
||||||
public string? SignatureSourceGameTitle { get; set;}
|
public string? SignatureSourceGameTitle { get; set; }
|
||||||
public bool HasSaveStates { get; set; } = false;
|
public bool HasSaveStates { get; set; } = false;
|
||||||
public GameLibrary.LibraryItem Library { get; set; }
|
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 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
|
// connect to database
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
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
|
// process provided files
|
||||||
Logging.Log(Logging.LogType.Information, "Signature Ingestor - XML", "Importing from " + SearchPath);
|
|
||||||
if (!Directory.Exists(SearchPath))
|
if (!Directory.Exists(SearchPath))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(SearchPath);
|
Directory.CreateDirectory(SearchPath);
|
||||||
}
|
}
|
||||||
|
if (!Directory.Exists(ProcessedDirectory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(ProcessedDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
string[] PathContents = Directory.GetFiles(SearchPath);
|
string[] PathContents = Directory.GetFiles(SearchPath);
|
||||||
Array.Sort(PathContents);
|
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 = "";
|
string sql = "";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
System.Data.DataTable sigDB;
|
System.Data.DataTable sigDB;
|
||||||
@@ -33,12 +61,28 @@ namespace gaseous_server.SignatureIngestors.XML
|
|||||||
|
|
||||||
SetStatus(i + 1, PathContents.Length, "Processing signature file: " + XMLFile);
|
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
|
// check xml file md5
|
||||||
Common.hashObject hashObject = new Common.hashObject(XMLFile);
|
Common.hashObject hashObject = new Common.hashObject(XMLFile);
|
||||||
sql = "SELECT * FROM Signatures_Sources WHERE SourceMD5=@sourcemd5";
|
sql = "SELECT * FROM Signatures_Sources WHERE SourceMD5=@sourcemd5";
|
||||||
@@ -50,11 +94,9 @@ namespace gaseous_server.SignatureIngestors.XML
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Signature Ingestor - XML", "Importing file: " + XMLFile);
|
|
||||||
|
|
||||||
// start parsing file
|
// start parsing file
|
||||||
gaseous_signature_parser.parser Parser = new gaseous_signature_parser.parser();
|
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
|
// store in database
|
||||||
string[] flipNameAndDescription = {
|
string[] flipNameAndDescription = {
|
||||||
@@ -66,21 +108,27 @@ namespace gaseous_server.SignatureIngestors.XML
|
|||||||
bool processGames = false;
|
bool processGames = false;
|
||||||
if (Object.SourceMd5 != null)
|
if (Object.SourceMd5 != null)
|
||||||
{
|
{
|
||||||
sql = "SELECT * FROM Signatures_Sources WHERE SourceMD5=@sourcemd5";
|
int sourceId = 0;
|
||||||
dbDict = new Dictionary<string, object>();
|
|
||||||
string sourceUriStr = "";
|
sql = "SELECT * FROM Signatures_Sources WHERE `SourceMD5`=@sourcemd5";
|
||||||
if (Object.Url != null)
|
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("sourcetype", Common.ReturnValueIfNull(Object.SourceType, ""));
|
||||||
dbDict.Add("sourcemd5", Object.SourceMd5);
|
dbDict.Add("sourcemd5", Object.SourceMd5);
|
||||||
dbDict.Add("sourcesha1", Object.SourceSHA1);
|
dbDict.Add("sourcesha1", Object.SourceSHA1);
|
||||||
@@ -89,9 +137,11 @@ namespace gaseous_server.SignatureIngestors.XML
|
|||||||
if (sigDB.Rows.Count == 0)
|
if (sigDB.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// entry not present, insert it
|
// 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;
|
processGames = true;
|
||||||
}
|
}
|
||||||
@@ -121,21 +171,88 @@ namespace gaseous_server.SignatureIngestors.XML
|
|||||||
dbDict.Add("platform", Common.ReturnValueIfNull(gameObject.System, ""));
|
dbDict.Add("platform", Common.ReturnValueIfNull(gameObject.System, ""));
|
||||||
dbDict.Add("systemvariant", Common.ReturnValueIfNull(gameObject.SystemVariant, ""));
|
dbDict.Add("systemvariant", Common.ReturnValueIfNull(gameObject.SystemVariant, ""));
|
||||||
dbDict.Add("video", Common.ReturnValueIfNull(gameObject.Video, ""));
|
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, ""));
|
dbDict.Add("copyright", Common.ReturnValueIfNull(gameObject.Copyright, ""));
|
||||||
|
|
||||||
// store platform
|
// store platform
|
||||||
int gameSystem = 0;
|
int gameSystem = 0;
|
||||||
if (gameObject.System != null)
|
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);
|
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||||
if (sigDB.Rows.Count == 0)
|
if (sigDB.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// entry not present, insert it
|
// 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);
|
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
gameSystem = Convert.ToInt32(sigDB.Rows[0][0]);
|
gameSystem = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||||
@@ -151,13 +268,13 @@ namespace gaseous_server.SignatureIngestors.XML
|
|||||||
int gamePublisher = 0;
|
int gamePublisher = 0;
|
||||||
if (gameObject.Publisher != null)
|
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);
|
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||||
if (sigDB.Rows.Count == 0)
|
if (sigDB.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// entry not present, insert it
|
// 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);
|
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||||
gamePublisher = Convert.ToInt32(sigDB.Rows[0][0]);
|
gamePublisher = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||||
}
|
}
|
||||||
@@ -169,16 +286,16 @@ namespace gaseous_server.SignatureIngestors.XML
|
|||||||
dbDict.Add("publisherid", gamePublisher);
|
dbDict.Add("publisherid", gamePublisher);
|
||||||
|
|
||||||
// store game
|
// store game
|
||||||
int gameId = 0;
|
long 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";
|
sql = "SELECT * FROM Signatures_Games WHERE `Name`=@name AND `Year`=@year AND `PublisherId`=@publisherid AND `SystemId`=@systemid";
|
||||||
|
|
||||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||||
if (sigDB.Rows.Count == 0)
|
if (sigDB.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// entry not present, insert it
|
// entry not present, insert it
|
||||||
sql = "INSERT INTO Signatures_Games " +
|
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`, `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); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||||
sigDB = db.ExecuteCMD(sql, dbDict);
|
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
gameId = Convert.ToInt32(sigDB.Rows[0][0]);
|
gameId = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||||
@@ -188,13 +305,57 @@ namespace gaseous_server.SignatureIngestors.XML
|
|||||||
gameId = (int)sigDB.Rows[0][0];
|
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
|
// store rom
|
||||||
foreach (RomSignatureObject.Game.Rom romObject in gameObject.Roms)
|
foreach (RomSignatureObject.Game.Rom romObject in gameObject.Roms)
|
||||||
{
|
{
|
||||||
if (romObject.Md5 != null || romObject.Sha1 != null)
|
if (romObject.Md5 != null || romObject.Sha1 != null)
|
||||||
{
|
{
|
||||||
int romId = 0;
|
long romId = 0;
|
||||||
sql = "SELECT * FROM Signatures_Roms WHERE GameId=@gameid AND MD5=@md5";
|
sql = "SELECT * FROM Signatures_Roms WHERE `GameId`=@gameid AND (`MD5`=@md5 OR `SHA1`=@sha1)";
|
||||||
dbDict = new Dictionary<string, object>();
|
dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("gameid", gameId);
|
dbDict.Add("gameid", gameId);
|
||||||
dbDict.Add("name", Common.ReturnValueIfNull(romObject.Name, ""));
|
dbDict.Add("name", Common.ReturnValueIfNull(romObject.Name, ""));
|
||||||
@@ -212,12 +373,12 @@ namespace gaseous_server.SignatureIngestors.XML
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dbDict.Add("attributes", "[ ]");
|
dbDict.Add("attributes", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dbDict.Add("attributes", "[ ]");
|
dbDict.Add("attributes", "");
|
||||||
}
|
}
|
||||||
dbDict.Add("romtype", (int)romObject.RomType);
|
dbDict.Add("romtype", (int)romObject.RomType);
|
||||||
dbDict.Add("romtypemedia", Common.ReturnValueIfNull(romObject.RomTypeMedia, ""));
|
dbDict.Add("romtypemedia", Common.ReturnValueIfNull(romObject.RomTypeMedia, ""));
|
||||||
@@ -229,30 +390,51 @@ namespace gaseous_server.SignatureIngestors.XML
|
|||||||
if (sigDB.Rows.Count == 0)
|
if (sigDB.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// entry not present, insert it
|
// 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);
|
sigDB = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
|
||||||
romId = Convert.ToInt32(sigDB.Rows[0][0]);
|
romId = Convert.ToInt32(sigDB.Rows[0][0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
romId = (int)sigDB.Rows[0][0];
|
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)
|
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
|
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 System.Data;
|
||||||
|
using gaseous_server.Models;
|
||||||
using gaseous_signature_parser.models.RomSignatureObject;
|
using gaseous_signature_parser.models.RomSignatureObject;
|
||||||
|
using static gaseous_server.Classes.Common;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
@@ -10,7 +12,8 @@ namespace gaseous_server.Classes
|
|||||||
if (md5.Length > 0)
|
if (md5.Length > 0)
|
||||||
{
|
{
|
||||||
return _GetSignature("Signatures_Roms.md5 = @searchstring", md5);
|
return _GetSignature("Signatures_Roms.md5 = @searchstring", md5);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return _GetSignature("Signatures_Roms.sha1 = @searchstring", sha1);
|
return _GetSignature("Signatures_Roms.sha1 = @searchstring", sha1);
|
||||||
}
|
}
|
||||||
@@ -21,7 +24,8 @@ namespace gaseous_server.Classes
|
|||||||
if (TosecName.Length > 0)
|
if (TosecName.Length > 0)
|
||||||
{
|
{
|
||||||
return _GetSignature("Signatures_Roms.name = @searchstring", TosecName);
|
return _GetSignature("Signatures_Roms.name = @searchstring", TosecName);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -44,7 +48,7 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
Game = new gaseous_server.Models.Signatures_Games.GameItem
|
Game = new gaseous_server.Models.Signatures_Games.GameItem
|
||||||
{
|
{
|
||||||
Id = (Int32)sigDbRow["Id"],
|
Id = (long)(int)sigDbRow["Id"],
|
||||||
Name = (string)sigDbRow["Name"],
|
Name = (string)sigDbRow["Name"],
|
||||||
Description = (string)sigDbRow["Description"],
|
Description = (string)sigDbRow["Description"],
|
||||||
Year = (string)sigDbRow["Year"],
|
Year = (string)sigDbRow["Year"],
|
||||||
@@ -53,20 +57,20 @@ namespace gaseous_server.Classes
|
|||||||
System = (string)sigDbRow["Platform"],
|
System = (string)sigDbRow["Platform"],
|
||||||
SystemVariant = (string)sigDbRow["SystemVariant"],
|
SystemVariant = (string)sigDbRow["SystemVariant"],
|
||||||
Video = (string)sigDbRow["Video"],
|
Video = (string)sigDbRow["Video"],
|
||||||
Country = (string)sigDbRow["Country"],
|
Countries = new Dictionary<string, string>(GetLookup(LookupTypes.Country, (long)(int)sigDbRow["Id"])),
|
||||||
Language = (string)sigDbRow["Language"],
|
Languages = new Dictionary<string, string>(GetLookup(LookupTypes.Language, (long)(int)sigDbRow["Id"])),
|
||||||
Copyright = (string)sigDbRow["Copyright"]
|
Copyright = (string)sigDbRow["Copyright"]
|
||||||
},
|
},
|
||||||
Rom = new gaseous_server.Models.Signatures_Games.RomItem
|
Rom = new gaseous_server.Models.Signatures_Games.RomItem
|
||||||
{
|
{
|
||||||
Id = (Int32)sigDbRow["romid"],
|
Id = (long)(int)sigDbRow["romid"],
|
||||||
Name = (string)sigDbRow["romname"],
|
Name = (string)sigDbRow["romname"],
|
||||||
Size = (Int64)sigDbRow["Size"],
|
Size = (Int64)sigDbRow["Size"],
|
||||||
Crc = (string)sigDbRow["CRC"],
|
Crc = (string)sigDbRow["CRC"],
|
||||||
Md5 = ((string)sigDbRow["MD5"]).ToLower(),
|
Md5 = ((string)sigDbRow["MD5"]).ToLower(),
|
||||||
Sha1 = ((string)sigDbRow["SHA1"]).ToLower(),
|
Sha1 = ((string)sigDbRow["SHA1"]).ToLower(),
|
||||||
DevelopmentStatus = (string)sigDbRow["DevelopmentStatus"],
|
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"],
|
RomType = (gaseous_server.Models.Signatures_Games.RomItem.RomTypes)(int)sigDbRow["RomType"],
|
||||||
RomTypeMedia = (string)sigDbRow["RomTypeMedia"],
|
RomTypeMedia = (string)sigDbRow["RomTypeMedia"],
|
||||||
MediaLabel = (string)sigDbRow["MediaLabel"],
|
MediaLabel = (string)sigDbRow["MediaLabel"],
|
||||||
@@ -77,5 +81,77 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
return GamesList;
|
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 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);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql;
|
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)
|
if (SessionId == Guid.Empty)
|
||||||
{
|
{
|
||||||
// new session required
|
// new session required
|
||||||
SessionId = Guid.NewGuid();
|
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>{
|
dbDict = new Dictionary<string, object>{
|
||||||
{ "gameid", GameId },
|
{ "gameid", GameId },
|
||||||
{ "userid", UserId },
|
{ "userid", UserId },
|
||||||
{ "sessionid", SessionId },
|
{ "sessionid", SessionId },
|
||||||
{ "sessiontime", DateTime.UtcNow },
|
{ "sessiontime", DateTime.UtcNow },
|
||||||
{ "sessionlength", 1 }
|
{ "sessionlength", 1 },
|
||||||
|
{ "platformid", PlatformId },
|
||||||
|
{ "ismediagroup", IsMediaGroup },
|
||||||
|
{ "romid", RomId }
|
||||||
};
|
};
|
||||||
|
|
||||||
db.ExecuteNonQuery(sql, dbDict);
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
|
||||||
return new StatisticsModel{
|
return new StatisticsModel
|
||||||
|
{
|
||||||
GameId = GameId,
|
GameId = GameId,
|
||||||
SessionId = SessionId,
|
SessionId = SessionId,
|
||||||
SessionStart = (DateTime)dbDict["sessiontime"],
|
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;";
|
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid AND SessionId = @sessionid;";
|
||||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
return new StatisticsModel{
|
return new StatisticsModel
|
||||||
|
{
|
||||||
GameId = (long)data.Rows[0]["GameId"],
|
GameId = (long)data.Rows[0]["GameId"],
|
||||||
SessionId = Guid.Parse(data.Rows[0]["SessionId"].ToString()),
|
SessionId = Guid.Parse(data.Rows[0]["SessionId"].ToString()),
|
||||||
SessionStart = (DateTime)data.Rows[0]["SessionTime"],
|
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;";
|
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid ORDER BY SessionTime DESC LIMIT 1;";
|
||||||
data = db.ExecuteCMD(sql, dbDict);
|
data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
return new StatisticsModel{
|
return new StatisticsModel
|
||||||
|
{
|
||||||
GameId = GameId,
|
GameId = GameId,
|
||||||
SessionLength = TotalTime,
|
SessionLength = TotalTime,
|
||||||
SessionStart = (DateTime)data.Rows[0]["SessionTime"]
|
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.Roles = new List<string>(await _userManager.GetRolesAsync(user));
|
||||||
profile.SecurityProfile = user.SecurityProfile;
|
profile.SecurityProfile = user.SecurityProfile;
|
||||||
profile.UserPreferences = user.UserPreferences;
|
profile.UserPreferences = user.UserPreferences;
|
||||||
profile.Avatar = user.Avatar;
|
profile.ProfileId = user.ProfileId;
|
||||||
profile.Roles.Sort();
|
profile.Roles.Sort();
|
||||||
|
|
||||||
return Ok(profile);
|
return Ok(profile);
|
||||||
@@ -188,7 +188,7 @@ namespace gaseous_server.Controllers
|
|||||||
user.LockoutEnabled = rawUser.LockoutEnabled;
|
user.LockoutEnabled = rawUser.LockoutEnabled;
|
||||||
user.LockoutEnd = rawUser.LockoutEnd;
|
user.LockoutEnd = rawUser.LockoutEnd;
|
||||||
user.SecurityProfile = rawUser.SecurityProfile;
|
user.SecurityProfile = rawUser.SecurityProfile;
|
||||||
user.Avatar = rawUser.Avatar;
|
user.ProfileId = rawUser.ProfileId;
|
||||||
|
|
||||||
// get roles
|
// get roles
|
||||||
ApplicationUser? aUser = await _userManager.FindByIdAsync(rawUser.Id);
|
ApplicationUser? aUser = await _userManager.FindByIdAsync(rawUser.Id);
|
||||||
@@ -220,6 +220,10 @@ namespace gaseous_server.Controllers
|
|||||||
Email = model.Email,
|
Email = model.Email,
|
||||||
NormalizedEmail = model.Email.ToUpper()
|
NormalizedEmail = model.Email.ToUpper()
|
||||||
};
|
};
|
||||||
|
if (await _userManager.FindByEmailAsync(model.Email) != null)
|
||||||
|
{
|
||||||
|
return NotFound("User already exists");
|
||||||
|
}
|
||||||
var result = await _userManager.CreateAsync(user, model.Password);
|
var result = await _userManager.CreateAsync(user, model.Password);
|
||||||
if (result.Succeeded)
|
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]
|
[HttpGet]
|
||||||
[Route("Users/{UserId}")]
|
[Route("Users/{UserId}")]
|
||||||
[Authorize(Roles = "Admin")]
|
[Authorize(Roles = "Admin")]
|
||||||
@@ -256,6 +277,7 @@ namespace gaseous_server.Controllers
|
|||||||
user.LockoutEnabled = rawUser.LockoutEnabled;
|
user.LockoutEnabled = rawUser.LockoutEnabled;
|
||||||
user.LockoutEnd = rawUser.LockoutEnd;
|
user.LockoutEnd = rawUser.LockoutEnd;
|
||||||
user.SecurityProfile = rawUser.SecurityProfile;
|
user.SecurityProfile = rawUser.SecurityProfile;
|
||||||
|
user.ProfileId = rawUser.ProfileId;
|
||||||
|
|
||||||
// get roles
|
// get roles
|
||||||
IList<string> aUserRoles = await _userManager.GetRolesAsync(rawUser);
|
IList<string> aUserRoles = await _userManager.GetRolesAsync(rawUser);
|
||||||
@@ -306,7 +328,7 @@ namespace gaseous_server.Controllers
|
|||||||
// delete all roles
|
// delete all roles
|
||||||
foreach (string role in userRoles)
|
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);
|
await _userManager.RemoveFromRoleAsync(user, role);
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,9 @@ using gaseous_server.Classes;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Asp.Versioning;
|
using Asp.Versioning;
|
||||||
|
using Authentication;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using gaseous_server.Models;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -17,6 +20,15 @@ namespace gaseous_server.Controllers
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public class BiosController : Controller
|
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.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -43,11 +55,14 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpHead]
|
[HttpHead]
|
||||||
[Route("zip/{PlatformId}")]
|
[Route("zip/{PlatformId}")]
|
||||||
|
[Route("zip/{PlatformId}/{GameId}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GetBiosCompressed(long PlatformId)
|
public async Task<ActionResult> GetBiosCompressedAsync(long PlatformId, long GameId = -1, bool filtered = false)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
if (GameId == -1 || filtered == false)
|
||||||
{
|
{
|
||||||
IGDB.Models.Platform platform = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
IGDB.Models.Platform platform = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||||
|
|
||||||
@@ -67,6 +82,33 @@ namespace gaseous_server.Controllers
|
|||||||
var stream = new FileStream(tempFile, FileMode.Open);
|
var stream = new FileStream(tempFile, FileMode.Open);
|
||||||
return File(stream, "application/zip", platform.Slug + ".zip");
|
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
|
catch
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.CodeAnalysis.Scripting;
|
using Microsoft.CodeAnalysis.Scripting;
|
||||||
using static gaseous_server.Classes.Metadata.AgeRatings;
|
using static gaseous_server.Classes.Metadata.AgeRatings;
|
||||||
using Asp.Versioning;
|
using Asp.Versioning;
|
||||||
|
using static gaseous_server.Models.PlatformMapping;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
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.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -562,32 +496,103 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{GameId}/cover/image/{size}")]
|
[Route("{GameId}/{ImageType}/{ImageId}/image/{size}")]
|
||||||
[Route("{GameId}/cover/image/{size}/{imagename}")]
|
[Route("{GameId}/{ImageType}/{ImageId}/image/{size}/{imagename}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[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
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
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 != null)
|
||||||
{
|
{
|
||||||
if (gameObject.Cover.Id != null)
|
if (gameObject.Cover.Id != null)
|
||||||
{
|
{
|
||||||
IGDB.Models.Cover cover = Classes.Metadata.Covers.GetCover(gameObject.Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
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();
|
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)) {
|
if (!System.IO.File.Exists(imagePath))
|
||||||
string filename = cover.ImageId + ".jpg";
|
{
|
||||||
string filepath = coverFilePath;
|
Communications comms = new Communications();
|
||||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
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";
|
string contentType = "image/jpg";
|
||||||
|
|
||||||
var cd = new System.Net.Mime.ContentDisposition
|
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("Content-Disposition", cd.ToString());
|
||||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
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 File(filedata, contentType);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -611,6 +624,13 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum MetadataImageType
|
||||||
|
{
|
||||||
|
cover,
|
||||||
|
screenshots,
|
||||||
|
artwork
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
@@ -796,7 +816,8 @@ namespace gaseous_server.Controllers
|
|||||||
companyData.Add("company", company);
|
companyData.Add("company", company);
|
||||||
|
|
||||||
return Ok(companyData);
|
return Ok(companyData);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return NotFound();
|
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.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{GameId}/platforms")]
|
[Route("{GameId}/platforms")]
|
||||||
[ProducesResponseType(typeof(List<KeyValuePair<long, string>>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<Games.AvailablePlatformItem>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult> GamePlatforms(long GameId)
|
public async Task<ActionResult> GamePlatforms(long GameId)
|
||||||
{
|
{
|
||||||
try
|
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
|
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.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -1137,11 +1348,10 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Authorize(Roles = "Admin,Gamer")]
|
|
||||||
[Route("{GameId}/romgroup")]
|
[Route("{GameId}/romgroup")]
|
||||||
[ProducesResponseType(typeof(List<RomMediaGroup.GameRomMediaGroupItem>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<RomMediaGroup.GameRomMediaGroupItem>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[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);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
@@ -1151,7 +1361,7 @@ namespace gaseous_server.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId, user.Id));
|
return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId, user.Id, PlatformId));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -1388,7 +1598,8 @@ namespace gaseous_server.Controllers
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
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);
|
IGDB.Models.Screenshot screenshotObject = Screenshots.GetScreenshot(ScreenshotId, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(gameObject), false);
|
||||||
if (screenshotObject != null)
|
if (screenshotObject != null)
|
||||||
{
|
{
|
||||||
@@ -1410,56 +1621,56 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
// [MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
// [MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
// [HttpGet]
|
||||||
[Route("{GameId}/screenshots/{ScreenshotId}/image/{size}")]
|
// [Route("{GameId}/screenshots/{ScreenshotId}/image/{size}")]
|
||||||
[Route("{GameId}/screenshots/{ScreenshotId}/image/{size}/{ImageName}")]
|
// [Route("{GameId}/screenshots/{ScreenshotId}/image/{size}/{ImageName}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
// [ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
// [ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult> GameScreenshotImage(long GameId, long ScreenshotId, Communications.IGDBAPI_ImageSize Size, string ImageName)
|
// public async Task<ActionResult> GameScreenshotImage(long GameId, long ScreenshotId, Communications.IGDBAPI_ImageSize Size, string ImageName)
|
||||||
{
|
// {
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
// 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();
|
// Communications comms = new Communications();
|
||||||
Task<string> ImgFetch = comms.GetSpecificImageFromServer(basePath, screenshotObject.ImageId, Size, new List<Communications.IGDBAPI_ImageSize>{ Communications.IGDBAPI_ImageSize.original });
|
// 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))
|
// if (System.IO.File.Exists(coverFilePath))
|
||||||
{
|
// {
|
||||||
string filename = screenshotObject.ImageId + ".jpg";
|
// string filename = screenshotObject.ImageId + ".jpg";
|
||||||
string filepath = coverFilePath;
|
// string filepath = coverFilePath;
|
||||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
// byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
||||||
string contentType = "image/jpg";
|
// string contentType = "image/jpg";
|
||||||
|
|
||||||
var cd = new System.Net.Mime.ContentDisposition
|
// var cd = new System.Net.Mime.ContentDisposition
|
||||||
{
|
// {
|
||||||
FileName = filename,
|
// FileName = filename,
|
||||||
Inline = true,
|
// Inline = true,
|
||||||
};
|
// };
|
||||||
|
|
||||||
Response.Headers.Add("Content-Disposition", cd.ToString());
|
// Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||||
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
// Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||||
|
|
||||||
return File(filedata, contentType);
|
// return File(filedata, contentType);
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
return NotFound();
|
// return NotFound();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
catch
|
// catch
|
||||||
{
|
// {
|
||||||
return NotFound();
|
// return NotFound();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
|
@@ -86,5 +86,24 @@ namespace gaseous_server.Controllers
|
|||||||
return NotFound(exLNF.ToString());
|
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 });
|
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.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpPatch]
|
[HttpPatch]
|
||||||
|
@@ -114,22 +114,64 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{PlatformId}/platformlogo/image")]
|
[Route("{PlatformId}/platformlogo/{size}/logo.png")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult PlatformLogoImage(long PlatformId)
|
public async Task<ActionResult> GameImage(long PlatformId, Communications.IGDBAPI_ImageSize size)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
IGDB.Models.Platform platformObject = Classes.Metadata.Platforms.GetPlatform(PlatformId);
|
||||||
|
IGDB.Models.PlatformLogo? logoObject = null;
|
||||||
string logoFilePath = Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject), "Logo_Medium.png");
|
try
|
||||||
if (System.IO.File.Exists(logoFilePath))
|
|
||||||
{
|
{
|
||||||
string filename = "Logo.png";
|
logoObject = PlatformLogos.GetPlatformLogo(platformObject.PlatformLogo.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Platform(platformObject));
|
||||||
string filepath = logoFilePath;
|
}
|
||||||
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
|
catch
|
||||||
string contentType = "image/png";
|
{
|
||||||
|
// 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
|
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("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 File(filedata, contentType);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@@ -31,41 +31,34 @@ namespace gaseous_server.Controllers
|
|||||||
[Authorize(Roles = "Admin,Gamer")]
|
[Authorize(Roles = "Admin,Gamer")]
|
||||||
[ProducesResponseType(typeof(List<IFormFile>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<IFormFile>), StatusCodes.Status200OK)]
|
||||||
[RequestSizeLimit(long.MaxValue)]
|
[RequestSizeLimit(long.MaxValue)]
|
||||||
|
[Consumes("multipart/form-data")]
|
||||||
[DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, ValueLengthLimit = int.MaxValue)]
|
[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();
|
Guid sessionid = Guid.NewGuid();
|
||||||
|
|
||||||
string workPath = Path.Combine(Config.LibraryConfiguration.LibraryUploadDirectory, sessionid.ToString());
|
string workPath = Path.Combine(Config.LibraryConfiguration.LibraryUploadDirectory, sessionid.ToString());
|
||||||
|
|
||||||
long size = files.Sum(f => f.Length);
|
if (file.Length > 0)
|
||||||
|
|
||||||
List<Dictionary<string, object>> UploadedFiles = new List<Dictionary<string, object>>();
|
|
||||||
|
|
||||||
foreach (IFormFile formFile in files)
|
|
||||||
{
|
|
||||||
if (formFile.Length > 0)
|
|
||||||
{
|
{
|
||||||
Guid FileId = Guid.NewGuid();
|
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))
|
if (!Directory.Exists(workPath))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(workPath);
|
Directory.CreateDirectory(workPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dictionary<string, object> UploadedFile = new Dictionary<string, object>();
|
||||||
|
|
||||||
using (var stream = System.IO.File.Create(filePath))
|
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("id", FileId.ToString());
|
||||||
UploadedFile.Add("originalname", Path.GetFileName(formFile.FileName));
|
UploadedFile.Add("originalname", Path.GetFileName(file.FileName));
|
||||||
UploadedFile.Add("fullpath", filePath);
|
UploadedFile.Add("fullpath", filePath);
|
||||||
UploadedFiles.Add(UploadedFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get override platform if specified
|
// get override platform if specified
|
||||||
@@ -75,11 +68,22 @@ namespace gaseous_server.Controllers
|
|||||||
OverridePlatform = Platforms.GetPlatform((long)OverridePlatformId);
|
OverridePlatform = Platforms.GetPlatform((long)OverridePlatformId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process uploaded files
|
// Process uploaded file
|
||||||
foreach (Dictionary<string, object> UploadedFile in UploadedFiles)
|
|
||||||
{
|
|
||||||
Classes.ImportGame uploadImport = new ImportGame();
|
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))
|
if (Directory.Exists(workPath))
|
||||||
@@ -87,7 +91,10 @@ namespace gaseous_server.Controllers
|
|||||||
Directory.Delete(workPath, true);
|
Directory.Delete(workPath, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(new { count = files.Count, size });
|
return Ok(RetVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -73,7 +73,7 @@ namespace gaseous_server.Controllers
|
|||||||
private static async Task<List<GaseousGame>> _SearchForGame(long PlatformId, string SearchString)
|
private static async Task<List<GaseousGame>> _SearchForGame(long PlatformId, string SearchString)
|
||||||
{
|
{
|
||||||
string searchBody = "";
|
string searchBody = "";
|
||||||
string searchFields = "fields cover,first_release_date,name,platforms,slug; ";
|
string searchFields = "fields *; ";
|
||||||
searchBody += "search \"" + SearchString + "\";";
|
searchBody += "search \"" + SearchString + "\";";
|
||||||
searchBody += "where platforms = (" + PlatformId + ");";
|
searchBody += "where platforms = (" + PlatformId + ");";
|
||||||
searchBody += "limit 100;";
|
searchBody += "limit 100;";
|
||||||
@@ -91,7 +91,7 @@ namespace gaseous_server.Controllers
|
|||||||
foreach (Game game in results.ToList())
|
foreach (Game game in results.ToList())
|
||||||
{
|
{
|
||||||
Storage.CacheStatus cacheStatus = Storage.GetCacheStatus("Game", (long)game.Id);
|
Storage.CacheStatus cacheStatus = Storage.GetCacheStatus("Game", (long)game.Id);
|
||||||
switch(cacheStatus)
|
switch (cacheStatus)
|
||||||
{
|
{
|
||||||
case Storage.CacheStatus.NotPresent:
|
case Storage.CacheStatus.NotPresent:
|
||||||
Storage.NewCacheValue(game, false);
|
Storage.NewCacheValue(game, false);
|
||||||
|
@@ -9,6 +9,7 @@ using gaseous_signature_parser.models.RomSignatureObject;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Asp.Versioning;
|
using Asp.Versioning;
|
||||||
|
using gaseous_server.Models;
|
||||||
|
|
||||||
// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
// 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();
|
SignatureManagement signatureManagement = new SignatureManagement();
|
||||||
return signatureManagement.GetByTosecName(TosecName);
|
return signatureManagement.GetByTosecName(TosecName);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return null;
|
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>();
|
List<SystemInfo.PathItem> Disks = new List<SystemInfo.PathItem>();
|
||||||
foreach (GameLibrary.LibraryItem libraryItem in GameLibrary.GetLibraries)
|
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;
|
ReturnValue.Paths = Disks;
|
||||||
|
|
||||||
@@ -70,7 +73,8 @@ namespace gaseous_server.Controllers
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("Version")]
|
[Route("Version")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public Version GetSystemVersion() {
|
public Version GetSystemVersion()
|
||||||
|
{
|
||||||
return Assembly.GetExecutingAssembly().GetName().Version;
|
return Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,32 +84,36 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("VersionFile")]
|
[Route("VersionFile")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public FileContentResult GetSystemVersionAsFile() {
|
public FileContentResult GetSystemVersionAsFile()
|
||||||
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
|
||||||
// get age ratings dictionary
|
// get age ratings dictionary
|
||||||
Dictionary<int, string> ClassificationBoardsStrings = new Dictionary<int, string>();
|
Dictionary<int, string> ClassificationBoardsStrings = new Dictionary<int, string>();
|
||||||
foreach(IGDB.Models.AgeRatingCategory ageRatingCategory in Enum.GetValues(typeof(IGDB.Models.AgeRatingCategory)) )
|
foreach (IGDB.Models.AgeRatingCategory ageRatingCategory in Enum.GetValues(typeof(IGDB.Models.AgeRatingCategory)))
|
||||||
{
|
{
|
||||||
ClassificationBoardsStrings.Add((int)ageRatingCategory, ageRatingCategory.ToString());
|
ClassificationBoardsStrings.Add((int)ageRatingCategory, ageRatingCategory.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<int, string> AgeRatingsStrings = new Dictionary<int, string>();
|
Dictionary<int, string> AgeRatingsStrings = new Dictionary<int, string>();
|
||||||
foreach(IGDB.Models.AgeRatingTitle ageRatingTitle in Enum.GetValues(typeof(IGDB.Models.AgeRatingTitle)) )
|
foreach (IGDB.Models.AgeRatingTitle ageRatingTitle in Enum.GetValues(typeof(IGDB.Models.AgeRatingTitle)))
|
||||||
{
|
{
|
||||||
AgeRatingsStrings.Add((int)ageRatingTitle, ageRatingTitle.ToString());
|
AgeRatingsStrings.Add((int)ageRatingTitle, ageRatingTitle.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
string ver = "var AppVersion = \"" + Assembly.GetExecutingAssembly().GetName().Version.ToString() + "\";" + Environment.NewLine +
|
string ver = "var AppVersion = \"" + Assembly.GetExecutingAssembly().GetName().Version.ToString() + "\";" + Environment.NewLine +
|
||||||
"var DBSchemaVersion = \"" + db.GetDatabaseSchemaVersion() + "\";" + Environment.NewLine +
|
"var DBSchemaVersion = \"" + db.GetDatabaseSchemaVersion() + "\";" + Environment.NewLine +
|
||||||
"var FirstRunStatus = " + Config.ReadSetting<string>("FirstRunStatus", "0") + ";" + Environment.NewLine +
|
"var FirstRunStatus = \"" + Config.ReadSetting<string>("FirstRunStatus", "0") + "\";" + Environment.NewLine +
|
||||||
"var AgeRatingBoardsStrings = " + JsonSerializer.Serialize(ClassificationBoardsStrings, new JsonSerializerOptions{
|
"var AgeRatingBoardsStrings = " + JsonSerializer.Serialize(ClassificationBoardsStrings, new JsonSerializerOptions
|
||||||
|
{
|
||||||
WriteIndented = true
|
WriteIndented = true
|
||||||
}) + ";" + Environment.NewLine +
|
}) + ";" + Environment.NewLine +
|
||||||
"var AgeRatingStrings = " + JsonSerializer.Serialize(AgeRatingsStrings, new JsonSerializerOptions{
|
"var AgeRatingStrings = " + JsonSerializer.Serialize(AgeRatingsStrings, new JsonSerializerOptions
|
||||||
|
{
|
||||||
WriteIndented = true
|
WriteIndented = true
|
||||||
}) + ";" + Environment.NewLine +
|
}) + ";" + Environment.NewLine +
|
||||||
"var AgeRatingGroups = " + JsonSerializer.Serialize(AgeGroups.AgeGroupingsFlat, new JsonSerializerOptions{
|
"var AgeRatingGroups = " + JsonSerializer.Serialize(AgeGroups.AgeGroupingsFlat, new JsonSerializerOptions
|
||||||
|
{
|
||||||
WriteIndented = true
|
WriteIndented = true
|
||||||
}) + ";" + Environment.NewLine +
|
}) + ";" + Environment.NewLine +
|
||||||
"var emulatorDebugMode = " + Config.ReadSetting<string>("emulatorDebugMode", false.ToString()).ToLower() + ";";
|
"var emulatorDebugMode = " + Config.ReadSetting<string>("emulatorDebugMode", false.ToString()).ToLower() + ";";
|
||||||
@@ -251,10 +259,18 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public ActionResult GetSystemSettings()
|
public ActionResult GetSystemSettings()
|
||||||
{
|
{
|
||||||
SystemSettingsModel systemSettingsModel = new SystemSettingsModel{
|
SystemSettingsModel systemSettingsModel = new SystemSettingsModel
|
||||||
|
{
|
||||||
AlwaysLogToDisk = Config.LoggingConfiguration.AlwaysLogToDisk,
|
AlwaysLogToDisk = Config.LoggingConfiguration.AlwaysLogToDisk,
|
||||||
MinimumLogRetentionPeriod = Config.LoggingConfiguration.LogRetention,
|
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);
|
return Ok(systemSettingsModel);
|
||||||
@@ -273,6 +289,10 @@ namespace gaseous_server.Controllers
|
|||||||
Config.LoggingConfiguration.AlwaysLogToDisk = model.AlwaysLogToDisk;
|
Config.LoggingConfiguration.AlwaysLogToDisk = model.AlwaysLogToDisk;
|
||||||
Config.LoggingConfiguration.LogRetention = model.MinimumLogRetentionPeriod;
|
Config.LoggingConfiguration.LogRetention = model.MinimumLogRetentionPeriod;
|
||||||
Config.SetSetting<string>("emulatorDebugMode", model.EmulatorDebugMode.ToString());
|
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();
|
Config.UpdateConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,7 +301,8 @@ namespace gaseous_server.Controllers
|
|||||||
|
|
||||||
private SystemInfo.PathItem GetDisk(string Path)
|
private SystemInfo.PathItem GetDisk(string Path)
|
||||||
{
|
{
|
||||||
SystemInfo.PathItem pathItem = new SystemInfo.PathItem {
|
SystemInfo.PathItem pathItem = new SystemInfo.PathItem
|
||||||
|
{
|
||||||
LibraryPath = Path,
|
LibraryPath = Path,
|
||||||
SpaceUsed = Common.DirSize(new DirectoryInfo(Path)),
|
SpaceUsed = Common.DirSize(new DirectoryInfo(Path)),
|
||||||
SpaceAvailable = new DriveInfo(Path).AvailableFreeSpace,
|
SpaceAvailable = new DriveInfo(Path).AvailableFreeSpace,
|
||||||
@@ -293,7 +314,8 @@ namespace gaseous_server.Controllers
|
|||||||
|
|
||||||
public class SystemInfo
|
public class SystemInfo
|
||||||
{
|
{
|
||||||
public Version ApplicationVersion {
|
public Version ApplicationVersion
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Assembly.GetExecutingAssembly().GetName().Version;
|
return Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
@@ -305,6 +327,7 @@ namespace gaseous_server.Controllers
|
|||||||
|
|
||||||
public class PathItem
|
public class PathItem
|
||||||
{
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
public string LibraryPath { get; set; }
|
public string LibraryPath { get; set; }
|
||||||
public long SpaceUsed { get; set; }
|
public long SpaceUsed { get; set; }
|
||||||
public long SpaceAvailable { get; set; }
|
public long SpaceAvailable { get; set; }
|
||||||
@@ -589,7 +612,8 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
private bool _UserManageable;
|
private bool _UserManageable;
|
||||||
public bool UserManageable => _UserManageable;
|
public bool UserManageable => _UserManageable;
|
||||||
public int Interval {
|
public int Interval
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return int.Parse(Config.ReadSetting<string>("Interval_" + Task, DefaultInterval.ToString()));
|
return int.Parse(Config.ReadSetting<string>("Interval_" + Task, DefaultInterval.ToString()));
|
||||||
@@ -710,5 +734,14 @@ namespace gaseous_server.Controllers
|
|||||||
public bool AlwaysLogToDisk { get; set; }
|
public bool AlwaysLogToDisk { get; set; }
|
||||||
public int MinimumLogRetentionPeriod { get; set; }
|
public int MinimumLogRetentionPeriod { get; set; }
|
||||||
public bool EmulatorDebugMode { 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")]
|
[ApiVersion("1.1")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class GamesController: ControllerBase
|
public class GamesController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
@@ -106,7 +106,8 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
string IncludeUnrated = "";
|
string IncludeUnrated = "";
|
||||||
if (user.SecurityProfile.AgeRestrictionPolicy.IncludeUnrated == true) {
|
if (user.SecurityProfile.AgeRestrictionPolicy.IncludeUnrated == true)
|
||||||
|
{
|
||||||
IncludeUnrated = " OR view_Games.AgeGroupId IS NULL";
|
IncludeUnrated = " OR view_Games.AgeGroupId IS NULL";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,7 +447,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
string orderByOrder = "ASC";
|
string orderByOrder = "ASC";
|
||||||
if (model.Sorting != null)
|
if (model.Sorting != null)
|
||||||
{
|
{
|
||||||
switch(model.Sorting.SortBy)
|
switch (model.Sorting.SortBy)
|
||||||
{
|
{
|
||||||
case GameSearchModel.GameSortingItem.SortField.NameThe:
|
case GameSearchModel.GameSortingItem.SortField.NameThe:
|
||||||
orderByField = "NameThe";
|
orderByField = "NameThe";
|
||||||
@@ -485,6 +486,7 @@ SELECT DISTINCT
|
|||||||
Game.`Name`,
|
Game.`Name`,
|
||||||
Game.NameThe,
|
Game.NameThe,
|
||||||
Game.Slug,
|
Game.Slug,
|
||||||
|
Game.Summary,
|
||||||
Game.PlatformId,
|
Game.PlatformId,
|
||||||
Game.TotalRating,
|
Game.TotalRating,
|
||||||
Game.TotalRatingCount,
|
Game.TotalRatingCount,
|
||||||
@@ -551,7 +553,7 @@ FROM
|
|||||||
Favourites ON Game.Id = Favourites.GameId AND Favourites.UserId = @userid " + whereClause + " " + havingClause + " " + orderByClause;
|
Favourites ON Game.Id = Favourites.GameId AND Favourites.UserId = @userid " + whereClause + " " + havingClause + " " + orderByClause;
|
||||||
List<Games.MinimalGameItem> RetVal = new List<Games.MinimalGameItem>();
|
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
|
// get count
|
||||||
int RecordCount = dbResponse.Rows.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);
|
Games.MinimalGameItem retMinGame = new Games.MinimalGameItem(retGame);
|
||||||
retMinGame.Index = i;
|
retMinGame.Index = i;
|
||||||
if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value)
|
if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value)
|
||||||
@@ -593,28 +595,43 @@ FROM
|
|||||||
|
|
||||||
// build alpha list
|
// build alpha list
|
||||||
Dictionary<string, int> AlphaList = new Dictionary<string, int>();
|
Dictionary<string, int> AlphaList = new Dictionary<string, int>();
|
||||||
|
if (orderByField == "NameThe" || orderByField == "Name")
|
||||||
|
{
|
||||||
int CurrentPage = 1;
|
int CurrentPage = 1;
|
||||||
int NextPageIndex = pageSize;
|
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();
|
alphaSearchField = "NameThe";
|
||||||
if (!"ABCDEFGHIJKLMNOPQRSTUVWXYZ".Contains(firstChar))
|
|
||||||
{
|
|
||||||
if (!AlphaList.ContainsKey("#"))
|
|
||||||
{
|
|
||||||
AlphaList.Add("#", 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
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))
|
if (!AlphaList.ContainsKey(firstChar))
|
||||||
{
|
{
|
||||||
AlphaList.Add(firstChar, CurrentPage);
|
AlphaList.Add(firstChar, CurrentPage);
|
||||||
}
|
}
|
||||||
if (NextPageIndex == i + 1)
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
NextPageIndex += pageSize;
|
if (!AlphaList.ContainsKey("#"))
|
||||||
CurrentPage += 1;
|
{
|
||||||
|
AlphaList.Add("#", 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,8 @@ using Authentication;
|
|||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using Asp.Versioning;
|
using Asp.Versioning;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using gaseous_server.Classes.Metadata;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers.v1_1
|
namespace gaseous_server.Controllers.v1_1
|
||||||
{
|
{
|
||||||
@@ -13,7 +15,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
[ApiVersion("1.0")]
|
[ApiVersion("1.0")]
|
||||||
[ApiVersion("1.1")]
|
[ApiVersion("1.1")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class StateManagerController: ControllerBase
|
public class StateManagerController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
@@ -233,11 +235,11 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[Route("{RomId}/{StateId}/State/")]
|
[Route("{RomId}/{StateId}/State/")]
|
||||||
[Route("{RomId}/{StateId}/State/savestate.state")]
|
[Route("{RomId}/{StateId}/State/savestate.state")]
|
||||||
public async Task<ActionResult> GetStateDataAsync(long RomId, long StateId, bool IsMediaGroup = false)
|
public async Task<ActionResult> GetStateDataAsync(long RomId, long StateId, bool IsMediaGroup = false, bool StateOnly = false)
|
||||||
{
|
{
|
||||||
var user = await _userManager.GetUserAsync(User);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT Zipped, State FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
string sql = "SELECT * FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ "id", StateId },
|
{ "id", StateId },
|
||||||
@@ -254,7 +256,27 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string filename = "savestate.state";
|
// 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;
|
byte[] bytes;
|
||||||
if ((bool)data.Rows[0]["Zipped"] == false)
|
if ((bool)data.Rows[0]["Zipped"] == false)
|
||||||
{
|
{
|
||||||
@@ -264,7 +286,85 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
{
|
{
|
||||||
bytes = Common.Decompress((byte[])data.Rows[0]["State"]);
|
bytes = Common.Decompress((byte[])data.Rows[0]["State"]);
|
||||||
}
|
}
|
||||||
string contentType = "application/octet-stream";
|
string contentType = "";
|
||||||
|
string filename = ((DateTime)data.Rows[0]["StateDateTime"]).ToString("yyyy-MM-ddTHH-mm-ss") + "-" + Path.GetFileNameWithoutExtension(romName);
|
||||||
|
|
||||||
|
|
||||||
|
if (StateOnly == true)
|
||||||
|
{
|
||||||
|
contentType = "application/octet-stream";
|
||||||
|
filename = filename + ".state";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
contentType = "application/zip";
|
||||||
|
filename = filename + ".zip";
|
||||||
|
|
||||||
|
Dictionary<string, object> RomInfo = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "Name", romName },
|
||||||
|
{ "StateDateTime", data.Rows[0]["StateDateTime"] },
|
||||||
|
{ "StateName", data.Rows[0]["Name"] }
|
||||||
|
};
|
||||||
|
if ((int)data.Rows[0]["IsMediaGroup"] == 0)
|
||||||
|
{
|
||||||
|
RomInfo.Add("MD5", romMd5);
|
||||||
|
RomInfo.Add("SHA1", romSha1);
|
||||||
|
RomInfo.Add("Type", "ROM");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RomInfo.Add("Type", "Media Group");
|
||||||
|
RomInfo.Add("MediaGroupId", (long)data.Rows[0]["RomId"]);
|
||||||
|
}
|
||||||
|
string RomInfoString = Newtonsoft.Json.JsonConvert.SerializeObject(RomInfo, Newtonsoft.Json.Formatting.Indented, new Newtonsoft.Json.JsonSerializerSettings { NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore });
|
||||||
|
|
||||||
|
// compile zip file
|
||||||
|
using (var compressedFileStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
List<Dictionary<string, object>> Attachments = new List<Dictionary<string, object>>();
|
||||||
|
Attachments.Add(new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "Name", "savestate.state" },
|
||||||
|
{ "Body", bytes }
|
||||||
|
});
|
||||||
|
// check if value is dbnull
|
||||||
|
if (data.Rows[0]["Screenshot"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
Attachments.Add(new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "Name", "screenshot.jpg" },
|
||||||
|
{ "Body", (byte[])data.Rows[0]["Screenshot"] }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Attachments.Add(new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "Name", "rominfo.json" },
|
||||||
|
{ "Body", System.Text.Encoding.UTF8.GetBytes(RomInfoString) }
|
||||||
|
});
|
||||||
|
|
||||||
|
//Create an archive and store the stream in memory.
|
||||||
|
using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create, false))
|
||||||
|
{
|
||||||
|
foreach (var Attachment in Attachments)
|
||||||
|
{
|
||||||
|
//Create a zip entry for each attachment
|
||||||
|
var zipEntry = zipArchive.CreateEntry(Attachment["Name"].ToString());
|
||||||
|
|
||||||
|
//Get the stream of the attachment
|
||||||
|
using (var originalFileStream = new MemoryStream((byte[])Attachment["Body"]))
|
||||||
|
using (var zipEntryStream = zipEntry.Open())
|
||||||
|
{
|
||||||
|
//Copy the attachment stream to the zip entry stream
|
||||||
|
originalFileStream.CopyTo(zipEntryStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//return new FileContentResult(compressedFileStream.ToArray(), "application/zip") { FileDownloadName = filename };
|
||||||
|
bytes = compressedFileStream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var cd = new System.Net.Mime.ContentDisposition
|
var cd = new System.Net.Mime.ContentDisposition
|
||||||
{
|
{
|
||||||
@@ -279,6 +379,156 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[RequestSizeLimit(long.MaxValue)]
|
||||||
|
[Consumes("multipart/form-data")]
|
||||||
|
[DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, ValueLengthLimit = int.MaxValue)]
|
||||||
|
[Route("Upload")]
|
||||||
|
public async Task<ActionResult> UploadStateDataAsync(IFormFile file, long RomId = 0, bool IsMediaGroup = false)
|
||||||
|
{
|
||||||
|
// get user
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (file.Length > 0)
|
||||||
|
{
|
||||||
|
MemoryStream fileContent = new MemoryStream();
|
||||||
|
file.CopyTo(fileContent);
|
||||||
|
|
||||||
|
// test if file is a zip file
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var zipArchive = new ZipArchive(fileContent, ZipArchiveMode.Read, false))
|
||||||
|
{
|
||||||
|
foreach (var entry in zipArchive.Entries)
|
||||||
|
{
|
||||||
|
if (entry.FullName == "rominfo.json")
|
||||||
|
{
|
||||||
|
using (var stream = entry.Open())
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
string RomInfoString = reader.ReadToEnd();
|
||||||
|
Dictionary<string, object> RomInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(RomInfoString);
|
||||||
|
|
||||||
|
// get rom data
|
||||||
|
Roms.GameRomItem romItem;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
romItem = Roms.GetRom((string)RomInfo["MD5"]);
|
||||||
|
}
|
||||||
|
catch (Roms.InvalidRomHash)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get state data
|
||||||
|
byte[] StateData = null;
|
||||||
|
byte[] ScreenshotData = null;
|
||||||
|
string StateName = RomInfo["StateName"].ToString();
|
||||||
|
DateTime StateDateTime = DateTime.Parse(RomInfo["StateDateTime"].ToString());
|
||||||
|
IsMediaGroup = RomInfo["Type"].ToString() == "Media Group" ? true : false;
|
||||||
|
|
||||||
|
if (zipArchive.GetEntry("savestate.state") != null)
|
||||||
|
{
|
||||||
|
using (var stateStream = zipArchive.GetEntry("savestate.state").Open())
|
||||||
|
using (var stateReader = new MemoryStream())
|
||||||
|
{
|
||||||
|
stateStream.CopyTo(stateReader);
|
||||||
|
StateData = stateReader.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (zipArchive.GetEntry("screenshot.jpg") != null)
|
||||||
|
{
|
||||||
|
using (var screenshotStream = zipArchive.GetEntry("screenshot.jpg").Open())
|
||||||
|
using (var screenshotReader = new MemoryStream())
|
||||||
|
{
|
||||||
|
screenshotStream.CopyTo(screenshotReader);
|
||||||
|
ScreenshotData = screenshotReader.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save state
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "INSERT INTO GameState (UserId, RomId, IsMediaGroup, StateDateTime, Name, Screenshot, State, Zipped) VALUES (@userid, @romid, @ismediagroup, @statedatetime, @name, @screenshot, @state, @zipped); SELECT LAST_INSERT_ID();";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "userid", user.Id },
|
||||||
|
{ "romid", romItem.Id },
|
||||||
|
{ "ismediagroup", IsMediaGroup },
|
||||||
|
{ "statedatetime", StateDateTime },
|
||||||
|
{ "name", StateName },
|
||||||
|
{ "screenshot", ScreenshotData },
|
||||||
|
{ "state", Common.Compress(StateData) },
|
||||||
|
{ "zipped", true }
|
||||||
|
};
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
RomInfo.Add("RomId", romItem.Id);
|
||||||
|
RomInfo.Add("Management", "Managed");
|
||||||
|
return Ok(RomInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BadRequest("File is not a valid Gaseous state file.");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// not a zip file
|
||||||
|
if (RomId != 0)
|
||||||
|
{
|
||||||
|
// get rom data
|
||||||
|
Roms.GameRomItem romItem;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
romItem = Roms.GetRom(RomId);
|
||||||
|
}
|
||||||
|
catch (Roms.InvalidRomHash)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
// save state
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "INSERT INTO GameState (UserId, RomId, IsMediaGroup, StateDateTime, Name, Screenshot, State, Zipped) VALUES (@userid, @romid, @ismediagroup, @statedatetime, @name, @screenshot, @state, @zipped); SELECT LAST_INSERT_ID();";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "userid", user.Id },
|
||||||
|
{ "romid", RomId },
|
||||||
|
{ "ismediagroup", IsMediaGroup },
|
||||||
|
{ "statedatetime", DateTime.UtcNow },
|
||||||
|
{ "name", "" },
|
||||||
|
{ "screenshot", null },
|
||||||
|
{ "state", Common.Compress(fileContent.ToArray()) },
|
||||||
|
{ "zipped", true }
|
||||||
|
};
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
return Ok(new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "RomId", RomId },
|
||||||
|
{ "Management", "Unmanaged" }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest("No rom id provided.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest("File is empty.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Models.GameStateItem BuildGameStateItem(DataRow dr)
|
private Models.GameStateItem BuildGameStateItem(DataRow dr)
|
||||||
{
|
{
|
||||||
bool HasScreenshot = true;
|
bool HasScreenshot = true;
|
||||||
|
@@ -12,7 +12,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
[ApiVersion("1.0")]
|
[ApiVersion("1.0")]
|
||||||
[ApiVersion("1.1")]
|
[ApiVersion("1.1")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class StatisticsController: ControllerBase
|
public class StatisticsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
@@ -32,15 +32,15 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[Route("Games/{GameId}/")]
|
[Route("Games/{GameId}/{PlatformId}/{RomId}")]
|
||||||
public async Task<ActionResult> NewRecordStatistics(long GameId)
|
public async Task<ActionResult> NewRecordStatistics(long GameId, long PlatformId, long RomId, bool IsMediaGroup)
|
||||||
{
|
{
|
||||||
var user = await _userManager.GetUserAsync(User);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
Statistics statistics = new Statistics();
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -54,15 +54,15 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[Route("Games/{GameId}/{SessionId}")]
|
[Route("Games/{GameId}/{PlatformId}/{RomId}/{SessionId}")]
|
||||||
public async Task<ActionResult> SubsequentRecordStatistics(long GameId, Guid SessionId)
|
public async Task<ActionResult> SubsequentRecordStatistics(long GameId, long PlatformId, long RomId, Guid SessionId, bool IsMediaGroup)
|
||||||
{
|
{
|
||||||
var user = await _userManager.GetUserAsync(User);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
Statistics statistics = new Statistics();
|
Statistics statistics = new Statistics();
|
||||||
return Ok(statistics.RecordSession(SessionId, GameId, user.Id));
|
return Ok(statistics.RecordSession(SessionId, GameId, PlatformId, RomId, IsMediaGroup, user.Id));
|
||||||
}
|
}
|
||||||
else
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,7 +16,7 @@ namespace gaseous_server.Models
|
|||||||
{
|
{
|
||||||
var targetType = this.GetType();
|
var targetType = this.GetType();
|
||||||
var sourceType = game.GetType();
|
var sourceType = game.GetType();
|
||||||
foreach(var prop in targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public| BindingFlags.SetProperty))
|
foreach (var prop in targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty))
|
||||||
{
|
{
|
||||||
// check whether source object has the the property
|
// check whether source object has the the property
|
||||||
var sp = sourceType.GetProperty(prop.Name);
|
var sp = sourceType.GetProperty(prop.Name);
|
||||||
@@ -39,9 +39,11 @@ namespace gaseous_server.Models
|
|||||||
{
|
{
|
||||||
if (this.Cover.Id != null)
|
if (this.Cover.Id != null)
|
||||||
{
|
{
|
||||||
IGDB.Models.Cover cover = Covers.GetCover(Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(this), false);
|
// IGDB.Models.Cover cover = Covers.GetCover(Cover.Id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(this), false);
|
||||||
|
IGDB.Models.Cover cover = new IGDB.Models.Cover()
|
||||||
return cover;
|
{
|
||||||
|
Id = this.Cover.Id
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
public class PlatformMapping
|
||||||
{
|
{
|
||||||
private static Dictionary<string, PlatformMapItem> PlatformMapCache = new Dictionary<string, PlatformMapItem>();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the platform map from the embedded platform map resource
|
/// Updates the platform map from the embedded platform map resource
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -27,7 +25,8 @@ namespace gaseous_server.Models
|
|||||||
{
|
{
|
||||||
string rawJson = reader.ReadToEnd();
|
string rawJson = reader.ReadToEnd();
|
||||||
List<PlatformMapItem> platforms = new List<PlatformMapItem>();
|
List<PlatformMapItem> platforms = new List<PlatformMapItem>();
|
||||||
Newtonsoft.Json.JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings{
|
Newtonsoft.Json.JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings
|
||||||
|
{
|
||||||
MaxDepth = 64
|
MaxDepth = 64
|
||||||
};
|
};
|
||||||
platforms = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem>>(rawJson, jsonSerializerSettings);
|
platforms = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem>>(rawJson, jsonSerializerSettings);
|
||||||
@@ -73,8 +72,8 @@ namespace gaseous_server.Models
|
|||||||
|
|
||||||
foreach (PlatformMapItem mapItem in platforms)
|
foreach (PlatformMapItem mapItem in platforms)
|
||||||
{
|
{
|
||||||
// get the IGDB platform data
|
// insert dummy platform data - it'll be cleaned up on the first metadata refresh
|
||||||
Platform platform = Platforms.GetPlatform(mapItem.IGDBId);
|
Platform platform = CreateDummyPlatform(mapItem);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -93,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
|
public static List<PlatformMapItem> PlatformMap
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
// if (Database.DatabaseMemoryCache.GetCacheObject("PlatformMap") != null)
|
||||||
|
// {
|
||||||
|
// return (List<PlatformMapItem>)Database.DatabaseMemoryCache.GetCacheObject("PlatformMap");
|
||||||
|
// }
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM PlatformMap";
|
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>();
|
List<PlatformMapItem> platformMaps = new List<PlatformMapItem>();
|
||||||
foreach (DataRow row in data.Rows)
|
foreach (DataRow row in data.Rows)
|
||||||
{
|
{
|
||||||
long mapId = (long)row["Id"];
|
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);
|
PlatformMapItem mapItem = BuildPlatformMapItem(row);
|
||||||
if (mapItem != null)
|
if (mapItem != null)
|
||||||
{
|
{
|
||||||
platformMaps.Add(mapItem);
|
platformMaps.Add(mapItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
platformMaps.Sort((x, y) => x.IGDBName.CompareTo(y.IGDBName));
|
platformMaps.Sort((x, y) => x.IGDBName.CompareTo(y.IGDBName));
|
||||||
|
|
||||||
|
//Database.DatabaseMemoryCache.SetCacheObject("PlatformMap", platformMaps, 600);
|
||||||
|
|
||||||
return platformMaps;
|
return platformMaps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlatformMapItem GetPlatformMap(long Id)
|
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);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM PlatformMap WHERE Id = @Id";
|
string sql = "SELECT * FROM PlatformMap WHERE Id = @Id";
|
||||||
@@ -156,10 +163,11 @@ namespace gaseous_server.Models
|
|||||||
throw exception;
|
throw exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static void WritePlatformMap(PlatformMapItem item, bool Update, bool AllowAvailableEmulatorOverwrite)
|
public static void WritePlatformMap(PlatformMapItem item, bool Update, bool AllowAvailableEmulatorOverwrite)
|
||||||
{
|
{
|
||||||
|
CreateDummyPlatform(item);
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
string sql = "";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
@@ -238,23 +246,32 @@ namespace gaseous_server.Models
|
|||||||
{
|
{
|
||||||
foreach (PlatformMapItem.EmulatorBiosItem biosItem in item.Bios)
|
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.Clear();
|
||||||
dbDict.Add("Id", item.IGDBId);
|
dbDict.Add("Id", item.IGDBId);
|
||||||
dbDict.Add("Filename", biosItem.filename);
|
dbDict.Add("Filename", biosItem.filename);
|
||||||
dbDict.Add("Description", biosItem.description);
|
dbDict.Add("Description", biosItem.description);
|
||||||
dbDict.Add("Hash", biosItem.hash);
|
dbDict.Add("Hash", biosItem.hash);
|
||||||
|
dbDict.Add("Enabled", isEnabled);
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PlatformMapCache.ContainsKey(item.IGDBId.ToString()))
|
// clear cache
|
||||||
{
|
Database.DatabaseMemoryCache.RemoveCacheObject("PlatformMap");
|
||||||
PlatformMapCache.Remove(item.IGDBId.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WriteAvailableEmulators (PlatformMapItem item)
|
public static void WriteAvailableEmulators(PlatformMapItem item)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "";
|
string sql = "";
|
||||||
@@ -286,7 +303,16 @@ namespace gaseous_server.Models
|
|||||||
string sql = "";
|
string sql = "";
|
||||||
|
|
||||||
// get platform data
|
// get platform data
|
||||||
IGDB.Models.Platform? platform = Platforms.GetPlatform(IGDBId);
|
// 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)
|
if (platform != null)
|
||||||
{
|
{
|
||||||
@@ -352,6 +378,7 @@ namespace gaseous_server.Models
|
|||||||
DataTable biosTable = db.ExecuteCMD(sql, dbDict);
|
DataTable biosTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
List<PlatformMapItem.EmulatorBiosItem> bioss = new List<PlatformMapItem.EmulatorBiosItem>();
|
List<PlatformMapItem.EmulatorBiosItem> bioss = new List<PlatformMapItem.EmulatorBiosItem>();
|
||||||
|
List<string> enabledBios = new List<string>();
|
||||||
foreach (DataRow biosRow in biosTable.Rows)
|
foreach (DataRow biosRow in biosTable.Rows)
|
||||||
{
|
{
|
||||||
PlatformMapItem.EmulatorBiosItem bios = new PlatformMapItem.EmulatorBiosItem
|
PlatformMapItem.EmulatorBiosItem bios = new PlatformMapItem.EmulatorBiosItem
|
||||||
@@ -361,6 +388,11 @@ namespace gaseous_server.Models
|
|||||||
hash = ((string)Common.ReturnValueIfNull(biosRow["Hash"], "")).ToLower()
|
hash = ((string)Common.ReturnValueIfNull(biosRow["Hash"], "")).ToLower()
|
||||||
};
|
};
|
||||||
bioss.Add(bios);
|
bioss.Add(bios);
|
||||||
|
|
||||||
|
if ((bool)Common.ReturnValueIfNull(biosRow["Enabled"], true) == true)
|
||||||
|
{
|
||||||
|
enabledBios.Add(bios.hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// build item
|
// build item
|
||||||
@@ -369,26 +401,20 @@ namespace gaseous_server.Models
|
|||||||
mapItem.IGDBName = platform.Name;
|
mapItem.IGDBName = platform.Name;
|
||||||
mapItem.IGDBSlug = platform.Slug;
|
mapItem.IGDBSlug = platform.Slug;
|
||||||
mapItem.AlternateNames = alternateNames;
|
mapItem.AlternateNames = alternateNames;
|
||||||
mapItem.Extensions = new PlatformMapItem.FileExtensions{
|
mapItem.Extensions = new PlatformMapItem.FileExtensions
|
||||||
|
{
|
||||||
SupportedFileExtensions = knownExtensions,
|
SupportedFileExtensions = knownExtensions,
|
||||||
UniqueFileExtensions = uniqueExtensions
|
UniqueFileExtensions = uniqueExtensions
|
||||||
};
|
};
|
||||||
mapItem.RetroPieDirectoryName = (string)Common.ReturnValueIfNull(row["RetroPieDirectoryName"], "");
|
mapItem.RetroPieDirectoryName = (string)Common.ReturnValueIfNull(row["RetroPieDirectoryName"], "");
|
||||||
mapItem.WebEmulator = new PlatformMapItem.WebEmulatorItem{
|
mapItem.WebEmulator = new PlatformMapItem.WebEmulatorItem
|
||||||
|
{
|
||||||
Type = (string)Common.ReturnValueIfNull(row["WebEmulator_Type"], ""),
|
Type = (string)Common.ReturnValueIfNull(row["WebEmulator_Type"], ""),
|
||||||
Core = (string)Common.ReturnValueIfNull(row["WebEmulator_Core"], ""),
|
Core = (string)Common.ReturnValueIfNull(row["WebEmulator_Core"], ""),
|
||||||
AvailableWebEmulators = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem.WebEmulatorItem.AvailableWebEmulatorItem>>((string)Common.ReturnValueIfNull(row["AvailableWebEmulators"], "[]"))
|
AvailableWebEmulators = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PlatformMapItem.WebEmulatorItem.AvailableWebEmulatorItem>>((string)Common.ReturnValueIfNull(row["AvailableWebEmulators"], "[]"))
|
||||||
};
|
};
|
||||||
mapItem.Bios = bioss;
|
mapItem.Bios = bioss;
|
||||||
|
mapItem.EnabledBIOSHashes = enabledBios;
|
||||||
if (PlatformMapCache.ContainsKey(IGDBId.ToString()))
|
|
||||||
{
|
|
||||||
PlatformMapCache[IGDBId.ToString()] = mapItem;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PlatformMapCache.Add(IGDBId.ToString(), mapItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapItem;
|
return mapItem;
|
||||||
}
|
}
|
||||||
@@ -455,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 class PlatformMapItem
|
||||||
{
|
{
|
||||||
public long IGDBId { get; set; }
|
public long IGDBId { get; set; }
|
||||||
@@ -502,6 +596,15 @@ namespace gaseous_server.Models
|
|||||||
public string description { get; set; }
|
public string description { get; set; }
|
||||||
public string filename { 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
|
namespace gaseous_server.Models
|
||||||
{
|
{
|
||||||
public class Signatures_Games : HasheousClient.Models.LookupResponseModel
|
public class Signatures_Games : HasheousClient.Models.SignatureModel
|
||||||
{
|
{
|
||||||
public Signatures_Games()
|
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 SignatureFlags Flags = new SignatureFlags();
|
||||||
|
|
||||||
public class SignatureFlags
|
public class SignatureFlags
|
||||||
@@ -18,6 +42,213 @@ namespace gaseous_server.Models
|
|||||||
public string IGDBPlatformName { get; set; }
|
public string IGDBPlatformName { get; set; }
|
||||||
public long IGDBGameId { 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
|
CallingQueueItem = this
|
||||||
};
|
};
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Debug, "Signature Import", "Processing TOSEC files");
|
foreach (int i in Enum.GetValues(typeof(gaseous_signature_parser.parser.SignatureParser)))
|
||||||
tIngest.Import(Path.Combine(Config.LibraryConfiguration.LibrarySignatureImportDirectory, "TOSEC"), gaseous_signature_parser.parser.SignatureParser.TOSEC);
|
{
|
||||||
|
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");
|
string SignaturePath = Path.Combine(Config.LibraryConfiguration.LibrarySignaturesDirectory, parserType.ToString());
|
||||||
tIngest.Import(Path.Combine(Config.LibraryConfiguration.LibrarySignatureImportDirectory, "MAME Arcade"), gaseous_signature_parser.parser.SignatureParser.MAMEArcade);
|
string SignatureProcessedPath = Path.Combine(Config.LibraryConfiguration.LibrarySignaturesProcessedDirectory, parserType.ToString());
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Debug, "Signature Import", "Processing MAME MESS files");
|
if (!Directory.Exists(SignaturePath))
|
||||||
tIngest.Import(Path.Combine(Config.LibraryConfiguration.LibrarySignatureImportDirectory, "MAME MESS"), gaseous_signature_parser.parser.SignatureParser.MAMEMess);
|
{
|
||||||
|
Directory.CreateDirectory(SignaturePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(SignatureProcessedPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(SignatureProcessedPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
tIngest.Import(SignaturePath, SignatureProcessedPath, parserType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_SaveLastRunTime = true;
|
_SaveLastRunTime = true;
|
||||||
|
|
||||||
|
@@ -36,6 +36,9 @@ db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.Conn
|
|||||||
|
|
||||||
// set up db
|
// set up db
|
||||||
db.InitDB();
|
db.InitDB();
|
||||||
|
// create relation tables if they don't exist
|
||||||
|
Storage.CreateRelationsTables<IGDB.Models.Game>();
|
||||||
|
Storage.CreateRelationsTables<IGDB.Models.Platform>();
|
||||||
|
|
||||||
// populate db with static data for lookups
|
// populate db with static data for lookups
|
||||||
AgeRatings.PopulateAgeMap();
|
AgeRatings.PopulateAgeMap();
|
||||||
@@ -64,13 +67,14 @@ if (Directory.Exists(Config.LibraryConfiguration.LibraryUploadDirectory))
|
|||||||
// kick off any delayed upgrade tasks
|
// kick off any delayed upgrade tasks
|
||||||
// run 1002 background updates in the background on every start
|
// run 1002 background updates in the background on every start
|
||||||
DatabaseMigration.BackgroundUpgradeTargetSchemaVersions.Add(1002);
|
DatabaseMigration.BackgroundUpgradeTargetSchemaVersions.Add(1002);
|
||||||
|
DatabaseMigration.BackgroundUpgradeTargetSchemaVersions.Add(1023);
|
||||||
// start the task
|
// start the task
|
||||||
ProcessQueue.QueueItem queueItem = new ProcessQueue.QueueItem(
|
ProcessQueue.QueueItem queueItem = new ProcessQueue.QueueItem(
|
||||||
ProcessQueue.QueueItemType.BackgroundDatabaseUpgrade,
|
ProcessQueue.QueueItemType.BackgroundDatabaseUpgrade,
|
||||||
1,
|
1,
|
||||||
new List<ProcessQueue.QueueItemType>
|
new List<ProcessQueue.QueueItemType>
|
||||||
{
|
{
|
||||||
ProcessQueue.QueueItemType.All
|
ProcessQueue.QueueItemType.SignatureIngestor
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
true
|
true
|
||||||
@@ -307,7 +311,7 @@ app.Use(async (context, next) =>
|
|||||||
string userIdentity;
|
string userIdentity;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
userIdentity = context.User.Claims.Where(x=>x.Type==System.Security.Claims.ClaimTypes.NameIdentifier).FirstOrDefault().Value;
|
userIdentity = context.User.Claims.Where(x => x.Type == System.Security.Claims.ClaimTypes.NameIdentifier).FirstOrDefault().Value;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -319,72 +323,6 @@ app.Use(async (context, next) =>
|
|||||||
await 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
|
// setup library directories
|
||||||
Config.LibraryConfiguration.InitLibrary();
|
Config.LibraryConfiguration.InitLibrary();
|
||||||
|
|
||||||
@@ -397,9 +335,6 @@ gaseous_server.Classes.Metadata.Platforms.AssignAllPlatformsToGameIdZero();
|
|||||||
// extract platform map if not present
|
// extract platform map if not present
|
||||||
PlatformMapping.ExtractPlatformMap();
|
PlatformMapping.ExtractPlatformMap();
|
||||||
|
|
||||||
// force load platform map into cache
|
|
||||||
var platformMap = PlatformMapping.PlatformMap;
|
|
||||||
|
|
||||||
// add background tasks
|
// add background tasks
|
||||||
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
||||||
ProcessQueue.QueueItemType.SignatureIngestor)
|
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
|
1
gaseous-server/Support/Database/MySQL/gaseous-1022.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE `Platform` CHANGE `Name` `Name` varchar(255);
|
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>
|
<DocumentationFile>bin\Release\net8.0\gaseous-server.xml</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Asp.Versioning.Mvc" Version="8.0.0" />
|
<PackageReference Include="Asp.Versioning.Mvc" Version="8.1.0" />
|
||||||
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.0.0" />
|
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
|
||||||
<PackageReference Include="gaseous-signature-parser" Version="2.1.0" />
|
<PackageReference Include="gaseous-signature-parser" Version="2.2.1" />
|
||||||
<PackageReference Include="gaseous.IGDB" Version="1.0.2" />
|
<PackageReference Include="gaseous.IGDB" Version="1.0.2" />
|
||||||
<PackageReference Include="hasheous-client" Version="0.2.0" />
|
<PackageReference Include="hasheous-client" Version="1.0.2" />
|
||||||
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="13.5.0" />
|
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.0.0" />
|
||||||
<PackageReference Include="sharpcompress" Version="0.36.0" />
|
<PackageReference Include="sharpcompress" Version="0.37.2" />
|
||||||
<PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.1.23" />
|
<PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.2.24" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.1" />
|
||||||
<PackageReference Include="MySqlConnector" Version="2.3.5" />
|
<PackageReference Include="MySqlConnector" Version="2.3.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.5" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.5" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
<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" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -39,6 +39,8 @@
|
|||||||
<None Remove="Classes\" />
|
<None Remove="Classes\" />
|
||||||
<None Remove="Classes\SignatureIngestors\" />
|
<None Remove="Classes\SignatureIngestors\" />
|
||||||
<None Remove="Support\" />
|
<None Remove="Support\" />
|
||||||
|
<None Remove="Support\Country.txt" />
|
||||||
|
<None Remove="Support\Language.txt" />
|
||||||
<None Remove="Support\Database\" />
|
<None Remove="Support\Database\" />
|
||||||
<None Remove="Support\Database\MySQL\" />
|
<None Remove="Support\Database\MySQL\" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1000.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1000.sql" />
|
||||||
@@ -64,6 +66,9 @@
|
|||||||
<None Remove="Support\Database\MySQL\gaseous-1019.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1019.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1020.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1020.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1021.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\" />
|
<None Remove="Classes\Metadata\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -85,6 +90,8 @@
|
|||||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
</EmbeddedResource>
|
</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-1000.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1001.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1001.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1002.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1002.sql" />
|
||||||
@@ -108,5 +115,8 @@
|
|||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1019.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1019.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1020.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1020.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1021.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>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
BIN
gaseous-server/wwwroot/.DS_Store
vendored
@@ -22,9 +22,11 @@
|
|||||||
if (StateUrl) {
|
if (StateUrl) {
|
||||||
console.log('Loading saved state from: ' + StateUrl);
|
console.log('Loading saved state from: ' + StateUrl);
|
||||||
EJS_loadStateURL = StateUrl;
|
EJS_loadStateURL = StateUrl;
|
||||||
EJS_startOnLoaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start the emulator automatically when loaded
|
||||||
|
EJS_startOnLoaded = true;
|
||||||
|
|
||||||
// Path to the data directory
|
// Path to the data directory
|
||||||
EJS_pathtodata = '/emulators/EmulatorJS/data/';
|
EJS_pathtodata = '/emulators/EmulatorJS/data/';
|
||||||
|
|
||||||
@@ -42,10 +44,11 @@
|
|||||||
|
|
||||||
EJS_Buttons = {
|
EJS_Buttons = {
|
||||||
saveSavFiles: false,
|
saveSavFiles: false,
|
||||||
loadSavFiles: false
|
loadSavFiles: false,
|
||||||
|
exitEmulation: false
|
||||||
}
|
}
|
||||||
|
|
||||||
EJS_onSaveState = function(e) {
|
EJS_onSaveState = function (e) {
|
||||||
var returnValue = {
|
var returnValue = {
|
||||||
"ScreenshotByteArrayBase64": btoa(Uint8ToString(e.screenshot)),
|
"ScreenshotByteArrayBase64": btoa(Uint8ToString(e.screenshot)),
|
||||||
"StateByteArrayBase64": btoa(Uint8ToString(e.state))
|
"StateByteArrayBase64": btoa(Uint8ToString(e.state))
|
||||||
@@ -72,8 +75,12 @@
|
|||||||
returnValue = undefined;
|
returnValue = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
EJS_onLoadState = function(e) {
|
EJS_onLoadState = function (e) {
|
||||||
showDialog('emulatorloadstate', { "romId": romId, "IsMediaGroup": IsMediaGroup });
|
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>
|
||||||
<script src='/emulators/EmulatorJS/data/loader.js'></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 |