Compare commits
90 Commits
v1.7.0-pre
...
v1.7.7
Author | SHA1 | Date | |
---|---|---|---|
![]() |
928a1538ea | ||
![]() |
f4a8892cbb | ||
![]() |
c4435628e0 | ||
![]() |
933c624885 | ||
![]() |
06e344c74a | ||
![]() |
9150ce7377 | ||
![]() |
08a40e3dd9 | ||
![]() |
d7fca42057 | ||
![]() |
1672520a29 | ||
![]() |
3366d926f4 | ||
![]() |
6d7f6f63c6 | ||
![]() |
590a7829b1 | ||
![]() |
ae75fc1490 | ||
![]() |
0c645d04aa | ||
![]() |
13b3764fcf | ||
![]() |
57d4fe7cf9 | ||
![]() |
8519d4c745 | ||
![]() |
822a40b61b | ||
![]() |
b463bb6064 | ||
![]() |
3e8696e6e8 | ||
![]() |
d1f157ac08 | ||
![]() |
30be179367 | ||
![]() |
787bb47bd3 | ||
![]() |
ccf9afd561 | ||
![]() |
c7b6233ad6 | ||
![]() |
afb72c3d74 | ||
![]() |
299e24793f | ||
![]() |
de9b9bf706 | ||
![]() |
28bc50a82e | ||
![]() |
f9f65f3ffb | ||
![]() |
87f3a1aa89 | ||
![]() |
b3e7696292 | ||
![]() |
29c685c791 | ||
![]() |
f0020e5b1f | ||
![]() |
3897ed65ef | ||
![]() |
cebab38dd6 | ||
![]() |
fd7b354571 | ||
![]() |
be1d53b3b1 | ||
![]() |
e0cff36819 | ||
![]() |
cea654692e | ||
![]() |
c82ffb6c97 | ||
![]() |
7400a8c040 | ||
![]() |
eda171efa1 | ||
![]() |
f881459c0b | ||
![]() |
69da6ee346 | ||
![]() |
f85109abd2 | ||
![]() |
59173d8ae5 | ||
![]() |
178f70cb98 | ||
![]() |
080a823cda | ||
![]() |
60dbaf85a4 | ||
![]() |
8a80274030 | ||
![]() |
7e8679151b | ||
![]() |
123239cf58 | ||
![]() |
04419383aa | ||
![]() |
0bef298abf | ||
![]() |
a4d581b369 | ||
![]() |
16cb0c89dc | ||
![]() |
95b52c47dd | ||
![]() |
b1056299b8 | ||
![]() |
14c5761959 | ||
![]() |
d7b3711be6 | ||
![]() |
f2a58d23f0 | ||
![]() |
111c501911 | ||
![]() |
07c973cd75 | ||
![]() |
b94950fed0 | ||
![]() |
b5511a3c51 | ||
![]() |
73174a30f0 | ||
![]() |
a2d863dc7a | ||
![]() |
3c451f5558 | ||
![]() |
645327bdd1 | ||
![]() |
7754fd5dda | ||
![]() |
5e45fc1aa9 | ||
![]() |
36938ed2f8 | ||
![]() |
344d37c96a | ||
![]() |
60da78fa7d | ||
![]() |
cb3c7fa901 | ||
![]() |
b0c8075865 | ||
![]() |
0d8d2707cb | ||
![]() |
9fce071af6 | ||
![]() |
da0813b76f | ||
![]() |
5f6a71e065 | ||
![]() |
f65408a64d | ||
![]() |
3a9d3df013 | ||
![]() |
69863f8b61 | ||
![]() |
10be6c53ba | ||
![]() |
163aa7a446 | ||
![]() |
ec115b33de | ||
![]() |
9b8874902a | ||
![]() |
127eab683b | ||
![]() |
1efc47f9cd |
4
.devcontainer/.env
Normal file
4
.devcontainer/.env
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
DATABASE_HOST=mariadb
|
||||||
|
DATABASE_USER=root
|
||||||
|
DATABASE_PASSWORD=gaseous
|
||||||
|
DATABASE_DB=gaseous
|
10
.devcontainer/Dockerfile
Normal file
10
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
FROM mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm
|
||||||
|
|
||||||
|
# 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.1.1.7z
|
||||||
|
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.1.1.7z
|
46
.devcontainer/devcontainer.json
Normal file
46
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
|
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
|
||||||
|
{
|
||||||
|
"name": "C# (.NET)",
|
||||||
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
|
//"image": "mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm",
|
||||||
|
"dockerComposeFile": "docker-compose.yml",
|
||||||
|
"service": "development",
|
||||||
|
"workspaceFolder": "/workspace",
|
||||||
|
|
||||||
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
|
// "features": {},
|
||||||
|
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
"forwardPorts": [5198],
|
||||||
|
"portsAttributes": {
|
||||||
|
"5198": {
|
||||||
|
"protocol": "http"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
|
"postCreateCommand": "dotnet restore",
|
||||||
|
|
||||||
|
// Configure tool-specific properties.
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"cweijan.vscode-mysql-client2",
|
||||||
|
"ms-dotnettools.csdevkit",
|
||||||
|
"ms-dotnettools.csharp",
|
||||||
|
"ms-dotnettools.vscode-dotnet-runtime",
|
||||||
|
"ecmel.vscode-html-css",
|
||||||
|
"github.vscode-github-actions",
|
||||||
|
"GitHub.vscode-pull-request-github",
|
||||||
|
"AndersEAndersen.html-class-suggestions",
|
||||||
|
"george-alisson.html-preview-vscode",
|
||||||
|
"ms-dotnettools.vscodeintellicode-csharp",
|
||||||
|
"Zignd.html-css-class-completion"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
|
// "remoteUser": "root"
|
||||||
|
}
|
23
.devcontainer/docker-compose.yml
Normal file
23
.devcontainer/docker-compose.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
services:
|
||||||
|
development:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
volumes:
|
||||||
|
- ..:/workspace
|
||||||
|
stdin_open: true
|
||||||
|
environment:
|
||||||
|
- TZ=Australia/Sydney
|
||||||
|
- dbhost=${DATABASE_HOST}
|
||||||
|
- dbuser=${DATABASE_USER}
|
||||||
|
- dbpass=${DATABASE_PASSWORD}
|
||||||
|
- igdbclientid=<clientid>
|
||||||
|
- igdbclientsecret=<clientsecret>
|
||||||
|
mariadb:
|
||||||
|
hostname: mariadb
|
||||||
|
image: mariadb:latest
|
||||||
|
environment:
|
||||||
|
- MARIADB_ROOT_PASSWORD=${DATABASE_PASSWORD}
|
||||||
|
- MARIADB_DATABASE=${DATABASE_DB}
|
||||||
|
- MARIADB_USER=${DATABASE_USER}
|
||||||
|
- MARIADB_PASSWORD=${DATABASE_PASSWORD}
|
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@@ -9,9 +9,7 @@ updates:
|
|||||||
directory: "/" # Location of package manifests
|
directory: "/" # Location of package manifests
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
- package-ecosystem: "gitsubmodule"
|
- package-ecosystem: "devcontainers"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
allow:
|
|
||||||
- dependency-name: "gaseous-server/wwwroot/emulators/EmulatorJS"
|
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "weekly"
|
4
.github/release.yml
vendored
4
.github/release.yml
vendored
@@ -5,8 +5,12 @@ changelog:
|
|||||||
- '*'
|
- '*'
|
||||||
exclude:
|
exclude:
|
||||||
labels:
|
labels:
|
||||||
|
- note
|
||||||
- bug
|
- bug
|
||||||
- dependencies
|
- dependencies
|
||||||
|
- title: Notes
|
||||||
|
labels:
|
||||||
|
- note
|
||||||
- title: Bug Fixes
|
- title: Bug Fixes
|
||||||
labels:
|
labels:
|
||||||
- bug
|
- bug
|
||||||
|
@@ -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: .
|
||||||
platforms: linux/amd64 #,linux/arm64
|
file: ./build/Dockerfile
|
||||||
|
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
|
||||||
|
44
.github/workflows/BuildDockerOnTag-Release.yml
vendored
44
.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,41 @@ 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: .
|
||||||
platforms: linux/amd64 #,linux/arm64
|
file: ./build/Dockerfile
|
||||||
|
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:latest-embeddeddb
|
||||||
|
gaseousgames/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||||
|
ghcr.io/gaseous-project/gaseousserver:latest-embeddeddb
|
||||||
|
ghcr.io/gaseous-project/gaseousserver:${{ github.ref_name}}-embeddeddb
|
||||||
|
45
.github/workflows/BuildOnTestBranch.yml
vendored
Normal file
45
.github/workflows/BuildOnTestBranch.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
name: Build test branch
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [test]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
- name: Install dotnet tool
|
||||||
|
run: dotnet tool install -g dotnetCampus.TagToVersion
|
||||||
|
- name: Set tag to version
|
||||||
|
run: dotnet TagToVersion -t 0.0.1
|
||||||
|
- 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"
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
- name: Build and push standard image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./build/Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: gaseousgames/test:latest
|
||||||
|
- name: Build and push image with embedded mariadb
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./build/Dockerfile-EmbeddedDB
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: gaseousgames/test:latest-embeddeddb
|
85
.github/workflows/codeql.yml
vendored
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}}"
|
|
2
.github/workflows/dotnet.yml
vendored
2
.github/workflows/dotnet.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v1
|
uses: actions/setup-dotnet@v1
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.x
|
dotnet-version: 8.0.x
|
||||||
- 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: Restore dependencies
|
- name: Restore dependencies
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -404,3 +404,4 @@ ASALocalRun/
|
|||||||
# Local History for Visual Studio
|
# Local History for Visual Studio
|
||||||
.localhistory/
|
.localhistory/
|
||||||
gaseous-server/.DS_Store
|
gaseous-server/.DS_Store
|
||||||
|
gaseous-server/wwwroot/emulators/EmulatorJS
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
|||||||
[submodule "gaseous-server/wwwroot/emulators/EmulatorJS"]
|
|
||||||
path = gaseous-server/wwwroot/emulators/EmulatorJS
|
|
||||||
url = https://github.com/EmulatorJS/EmulatorJS.git
|
|
||||||
|
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -10,21 +10,22 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"preLaunchTask": "build",
|
"preLaunchTask": "build",
|
||||||
// If you have changed target frameworks, make sure to update the program path.
|
// If you have changed target frameworks, make sure to update the program path.
|
||||||
"program": "${workspaceFolder}/gaseous-server/bin/Debug/net7.0/gaseous-server.dll",
|
"program": "${workspaceFolder}/gaseous-server/bin/Debug/net8.0/gaseous-server.dll",
|
||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}/gaseous-server",
|
"cwd": "${workspaceFolder}/gaseous-server",
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||||
"serverReadyAction": {
|
"serverReadyAction": {
|
||||||
"action": "openExternally",
|
"action": "openExternally",
|
||||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
"pattern": "\\bNow listening on:\\s+(http?://\\S+)"
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
},
|
},
|
||||||
"sourceFileMap": {
|
"sourceFileMap": {
|
||||||
"/Views": "${workspaceFolder}/Views"
|
"/Views": "${workspaceFolder}/Views"
|
||||||
}
|
},
|
||||||
|
"enableStepFiltering": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": ".NET Core Attach",
|
"name": ".NET Core Attach",
|
||||||
|
16
Dockerfile
16
Dockerfile
@@ -1,16 +0,0 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env
|
|
||||||
WORKDIR /App
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
# Copy everything
|
|
||||||
COPY . ./
|
|
||||||
# Restore as distinct layers
|
|
||||||
RUN dotnet restore "gaseous-server/gaseous-server.csproj"
|
|
||||||
# Build and publish a release
|
|
||||||
RUN dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime --self-contained false -c Release -o out
|
|
||||||
|
|
||||||
# Build runtime image
|
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:7.0
|
|
||||||
WORKDIR /App
|
|
||||||
COPY --from=build-env /App/out .
|
|
||||||
ENTRYPOINT ["dotnet", "gaseous-server.dll"]
|
|
20
Gaseous.sln
20
Gaseous.sln
@@ -3,7 +3,7 @@ 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
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gaseous-server", "gaseous-server\gaseous-server.csproj", "{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "gaseous-server", "gaseous-server\gaseous-server.csproj", "{A01D2EFF-C82E-473B-84D7-7C25E736F5D2}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{17FA6F12-8532-420C-9489-CB8FDE42137C}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{17FA6F12-8532-420C-9489-CB8FDE42137C}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
@@ -27,30 +27,18 @@ Global
|
|||||||
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
|
|
||||||
{B07A4655-A003-416B-A790-ADAA5B548E1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{B07A4655-A003-416B-A790-ADAA5B548E1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{B07A4655-A003-416B-A790-ADAA5B548E1A}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
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
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>.
|
|
||||||
|
193
README.MD
193
README.MD
@@ -1,194 +1,53 @@
|
|||||||
|
[](https://github.com/gaseous-project/gaseous-server/actions/workflows/dotnet.yml) [](https://github.com/gaseous-project/gaseous-server/actions/workflows/codeql.yml) [](https://github.com/gaseous-project/gaseous-server/actions/workflows/BuildDockerOnTag-Release.yml)
|
||||||
# Gaseous Server
|
# Gaseous Server
|
||||||
|
|
||||||
This is the server for the Gaseous system. It offers ROM and title management, as well as some basic in browser emulation of those ROMs.
|
This is the server for the Gaseous system. It offers ROM and title management, as well as some basic in browser emulation of those ROMs.
|
||||||
|
|
||||||
## Warning
|
## Warning
|
||||||
|
|
||||||
This project is currently not suitable for being exposed to the internet.
|
Versions 1.6.1 and earlier are not suitable for being exposed to the internet, as:
|
||||||
1. there is currently no authentication support, meaning anyone could trash your library
|
1. there is no authentication support, meaning anyone could trash your library
|
||||||
2. the server has not been hardened for exposure to the internet - so there maybe unknown vulnerabilities
|
2. the server has not been hardened for exposure to the internet - so there maybe unknown vulnerabilities
|
||||||
|
|
||||||
If you expose the server to the internet, **you do so at your own risk**.
|
If you expose one of these earlier versions of the server to the internet, **you do so at your own risk**.
|
||||||
|
|
||||||
|
Version 1.7.0 and later contain user authentication, and can be exposed to the internet. However, it is recommended to no expose the server to the internet if you're not actively using it remotely, or if you have alternative means to access it remotely like a VPN.
|
||||||
|
|
||||||
|
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
|
||||||
* MariaDB 11.1.2 or MySQL Server 8+
|
* MariaDB 11.1.2 (preferred) or MySQL Server 8+
|
||||||
* These are the database versions Gaseous has been tested and developed against. Your mileage may vary with earlier versions.
|
* These are the database versions Gaseous has been tested and developed against. Your mileage may vary with earlier versions.
|
||||||
* Currently MariaDB is the preferred database server, while MySQL will continue to be supported for existing users (they should be interchangable).
|
* MariaDB is the preferred database server, while MySQL will continue to be supported for existing users (they should be interchangable).
|
||||||
* Note that due to the earlier database schema using MySQL specific features, moving to MariaDB from MySQL will require rebuilding your database from scratch. The "Library Scan" background task can be used to re-import all titles.
|
* Note that due to the earlier database schema using MySQL specific features, moving to MariaDB from MySQL will require rebuilding your database from scratch. The "Library Scan" background task can be used to re-import all titles.
|
||||||
* Internet Game Database API Key. See: https://api-docs.igdb.com/#account-creation
|
* Internet Game Database API Key. See: https://api-docs.igdb.com/#account-creation
|
||||||
|
|
||||||
|
If using the provided docker-compose.yml, MariaDB will be installed for you.
|
||||||
|
|
||||||
|
## Friends of Gaseous
|
||||||
|
* [EmulatorJS](https://github.com/EmulatorJS/EmulatorJS): A fantastic (and fast) Javascript based implementation of RetroArch, supporting a wide variety of platforms. Discord: https://discord.gg/6akryGkETU
|
||||||
|
* [RomM](https://github.com/zurdi15/romm): Another self hosted ROM manager. Discord: https://discord.gg/P5HtHnhUDH
|
||||||
|
|
||||||
## Third Party Projects
|
## Third Party Projects
|
||||||
The following projects are used by Gaseous
|
The following projects are used by Gaseous
|
||||||
* https://dotnet.microsoft.com/en-us/apps/aspnet
|
* [ASP.NET](https://dotnet.microsoft.com/en-us/apps/aspnet)
|
||||||
* https://github.com/JamesNK/Newtonsoft.Json
|
* [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json)
|
||||||
* https://www.nuget.org/packages/MySql.Data/8.0.32.1
|
* [MySQLConnector](https://mysqlconnector.net)
|
||||||
* https://github.com/kamranayub/igdb-dotnet
|
* [IGDB-DOTNET](https://github.com/kamranayub/igdb-dotnet)
|
||||||
* https://github.com/EmulatorJS/EmulatorJS
|
* [EmulatorJS](https://github.com/EmulatorJS/EmulatorJS)
|
||||||
|
|
||||||
## Discord Server
|
## Discord Server
|
||||||
[](https://discord.gg/Nhu7wpT3k4)
|
[](https://discord.gg/Nhu7wpT3k4)
|
||||||
|
|
||||||
# Setup
|
# Installation
|
||||||
|
See https://github.com/gaseous-project/gaseous-server/wiki/Installation for installation instructions.
|
||||||
## Configuration File
|
|
||||||
When Gaseous-Server is started for the first time, it creates a configuration file at ~/.gaseous-server/config.json if it doesn't exist. Some values can be filled in using environment variables (such as in the case of using docker).
|
|
||||||
|
|
||||||
### DatabaseConfiguration
|
|
||||||
| Attribute | Environment Variable |
|
|
||||||
| --------- | -------------------- |
|
|
||||||
| HostName | dbhost |
|
|
||||||
| UserName | dbuser |
|
|
||||||
| Password | dbpass |
|
|
||||||
|
|
||||||
### IGDBConfiguration
|
|
||||||
| Attribute | Environment Variable |
|
|
||||||
| --------- | -------------------- |
|
|
||||||
| ClientId | igdbclientid |
|
|
||||||
| Secret. | igdbclientsecret |
|
|
||||||
|
|
||||||
### config.json
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"DatabaseConfiguration": {
|
|
||||||
"HostName": "localhost",
|
|
||||||
"UserName": "gaseous",
|
|
||||||
"Password": "gaseous",
|
|
||||||
"DatabaseName": "gaseous",
|
|
||||||
"Port": 3306
|
|
||||||
},
|
|
||||||
"IGDBConfiguration": {
|
|
||||||
"ClientId": "<clientid>",
|
|
||||||
"Secret": "<secret>"
|
|
||||||
},
|
|
||||||
"LoggingConfiguration": {
|
|
||||||
"DebugLogging": false,
|
|
||||||
"LogRetention": 7
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Docker
|
|
||||||
### Deploy with the prebuilt Docker image
|
|
||||||
Dockerfile and docker-compose.yml files have been provided to make deployment of the server as easy as possible.
|
|
||||||
1. Download the docker-compose-{database}.yml file for the database type you would like to use.
|
|
||||||
2. Open the docker-compose.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account
|
|
||||||
3. Run the command ```docker-compose up -d```
|
|
||||||
4. Connect to the host on port 5198
|
|
||||||
|
|
||||||
### Build and deploy a Docker image from source
|
|
||||||
Dockerfile and docker-compose-build.yml files have been provided to make deployment of the server as easy as possible.
|
|
||||||
1. Clone the repo with ```git clone https://github.com/gaseous-project/gaseous-server.git```
|
|
||||||
2. Change into the gaseous-server directory
|
|
||||||
3. Clone the submodules with the command ```git submodule update --init```
|
|
||||||
4. Open the docker-compose-{database}-build.yml file and edit the igdbclientid and igdbclientsecret to the values retrieved from your IGDB account
|
|
||||||
5. Run the command ```docker-compose --file docker-compose-{database}-build.yml up -d```
|
|
||||||
6. Connect to the host on port 5198
|
|
||||||
|
|
||||||
## Source
|
|
||||||
### Build and deploy
|
|
||||||
1. Install and configure a MariaDB or MySQL instance - this is beyond the scope of this document
|
|
||||||
2. Install the dotnet 7.0 packages appropriate for your operating system
|
|
||||||
* See: https://learn.microsoft.com/en-us/dotnet/core/install/linux
|
|
||||||
3. Create a database user with permission to create a databse. Gaseous will create the new database and apply the database schema on it's first startup.
|
|
||||||
4. Clone the repo with ```git clone https://github.com/gaseous-project/gaseous-server.git```
|
|
||||||
5. Change into the gaseous-server directory
|
|
||||||
6. As the main branch is the development branch, you might want to change to a stable version - these are tagged with a version number. For example to change to the 1.5.0 release, use the command ```git checkout v1.5.0```
|
|
||||||
* Check the releases page for the version you would like to run: https://github.com/gaseous-project/gaseous-server/releases
|
|
||||||
7. Clone the submodules with the command ```git submodule update --init --recursive```
|
|
||||||
* This command will clone the code that the server uses from other projects (currently only EmulatorJS)
|
|
||||||
8. Create a directory in the home directory of the user that will run the server. For example, if running as the user ```gaseous```, create the directory ```/home/gaseous/.gaseous-server```
|
|
||||||
9. Change into the ```.gaseous-server``` directory created in the previous step
|
|
||||||
10. Copy the JSON from the config file above into a new file named ```config.json```
|
|
||||||
11. Update the database section with the database server hostname, username, password, and port
|
|
||||||
12. Compile the server by changing back to the repo cloned earlier and executing:
|
|
||||||
* ```dotnet restore "gaseous-server/gaseous-server.csproj"```
|
|
||||||
* ```dotnet publish "gaseous-server/gaseous-server.csproj" --use-current-runtime --self-contained false -c Release -o <output directory>```
|
|
||||||
* replace ```<output directory>``` with the directory of your choosing. The compiled application will be copied there. For this example we'll use ```/opt/gaseous-server```
|
|
||||||
13. The server can then be started by executing ```dotnet /opt/gaseous-server/gaseous-server.dll```
|
|
||||||
* If you would like the server to run on a different ip address and port (for example 0.0.0.0:8080), add the --urls argument: ```dotnet /opt/gaseous-server/gaseous-server.dll --urls http://0.0.0.0:8080```
|
|
||||||
|
|
||||||
**Note**: The above instructions were tested on macOS Ventura, and Ubuntu 22.04.3. There was a report that Debian 11 had an issue with the git submodule commands (see: https://github.com/gaseous-project/gaseous-server/issues/71). This was possibly due to an older git package.
|
|
||||||
|
|
||||||
If the git submodule commands aren't working, you can:
|
|
||||||
1. change to the ```gaseous-server/wwwroot/emulators``` directory
|
|
||||||
2. delete the ```EmulatorJS``` directory
|
|
||||||
3. clone the EmulatorJS repository with ```git clone https://github.com/EmulatorJS/EmulatorJS.git```
|
|
||||||
|
|
||||||
### Updating from source
|
|
||||||
1. Stop the server
|
|
||||||
2. Switch to the source directory
|
|
||||||
3. Update your repo:
|
|
||||||
* If running from the main branch, run ```git pull``` to update the repo
|
|
||||||
* If running from another branch or tag, run:
|
|
||||||
* ```git fetch```
|
|
||||||
* ```git checkout <branch or tag name>```
|
|
||||||
4. Update the submodules with ```git submodule update --recursive```
|
|
||||||
5. Run steps 12 and 13 from the above Build guide
|
|
||||||
|
|
||||||
# Adding Content
|
# Adding Content
|
||||||
While games can be added to the server without them, it is recommended adding some signature DAT files beforehand to allow for better matching of ROMs to games.
|
1. Import signatures: see https://github.com/gaseous-project/gaseous-server/wiki/Signatures
|
||||||
|
2. Add ROMs: see https://github.com/gaseous-project/gaseous-server/wiki/Adding-ROMs
|
||||||
These signature DAT files contain a list of titles with hashes for many of the ROM images that have been found by the community.
|
|
||||||
|
|
||||||
Currently supported DAT's:
|
|
||||||
* TOSEC: https://www.tosecdev.org/downloads/category/56-2023-01-23
|
|
||||||
* MAME Arcade and MAME Mess: https://www.progettosnaps.net/dats/MAME
|
|
||||||
|
|
||||||
If there are other DAT's you'd like to see support for, please raise an issue with a link to the DAT's.
|
|
||||||
|
|
||||||
## Adding signature DAT files
|
|
||||||
### TOSEC
|
|
||||||
1. Download the DAT files from the source website. For example; from https://www.tosecdev.org/downloads/category/56-2023-01-23
|
|
||||||
2. Extract the archive
|
|
||||||
3. Copy the DAT files to ~/.gaseous-server/Data/Signatures/TOSEC/
|
|
||||||
|
|
||||||
### MAME Arcade
|
|
||||||
1. Download the DAT files from the source website. For example; from https://www.progettosnaps.net/dats/MAME
|
|
||||||
2. Extract the archive
|
|
||||||
3. Copy the file name "MAME 0.257 (arcade).dat" files to ~/.gaseous-server/Data/Signatures/MAME Arcade/
|
|
||||||
|
|
||||||
### MAME MESS
|
|
||||||
1. Download the DAT files from the source website. For example; from https://www.progettosnaps.net/dats/MAME
|
|
||||||
2. Extract the archive
|
|
||||||
3. Copy the file name "MAME 0.257 (mess).dat" files to ~/.gaseous-server/Data/Signatures/MAME MESS/
|
|
||||||
|
|
||||||
# Adding Game Images
|
|
||||||
1. Files can be presented as either stand alone files, or as zip files - currently 7z is unsupported.
|
|
||||||
2. Name the file appropriately.
|
|
||||||
* Attempting a search for the game name on https://www.igdb.com can help with file naming. If a hash search is unsuccessful, Gaseous will fall back to attempting to search by the file name.
|
|
||||||
3. Add the file to the server:
|
|
||||||
* Click the Upload button in the top right of the main Gaseous web page, and drag the files into the modal. The files will be uploaded and analyzed.
|
|
||||||
* Copy the file to ~/.gaseous-server/Data/Import
|
|
||||||
|
|
||||||
# Game Image Title Matching
|
|
||||||
Image to game matching follows the following order of operations, stopping the process at the first match:
|
|
||||||
### Get the file signature
|
|
||||||
1. Attempt a hash search
|
|
||||||
2. Attempt to search the signature database for a rom matching the file name - sometimes the hash can not be matched as a highscore table for example was saved to the image
|
|
||||||
3. Attempt to parse the file name - clues such as the extension being used to define which platform the file belongs to are used to create a search criteria
|
|
||||||
|
|
||||||
**Note**: If the file being scanned is a zip, the file will be extracted and searched. The first file whose signature can be found will be used to match the entire zip archive - be sure that the zip only contains files related to one game.
|
|
||||||
|
|
||||||
### Create a list of search candidates
|
|
||||||
Before beginning, remove any version numbers, and anything in the search string that is between ()
|
|
||||||
1. Add the full name of the image
|
|
||||||
2. Add the name of the image with any " - " replaced by ": "
|
|
||||||
3. Add the name of the image with text after a " - " removed
|
|
||||||
4. Add the name of the image with text after a ": " removed
|
|
||||||
|
|
||||||
### Search IGDB for a game match
|
|
||||||
Loop through each of the search candidates searching using:
|
|
||||||
1. "where" - exact match as the search candidate
|
|
||||||
2. "wherefuzzy" - partial match using wildcards
|
|
||||||
3. "search" - uses a more flexible search method
|
|
||||||
4. "searchNoPlatform" - uses the "search" method, but does not constrain the search to the determined platform
|
|
||||||
|
|
||||||
**Note**: If more than one result is found, the seach will loop through the returned results:
|
|
||||||
* If an exact (case-insensitive) match is found, that result is used for the match
|
|
||||||
* If still no match, the image will be set as "Unknown" as there is no way for Gaseous to know which title is the correct one.
|
|
||||||
|
36
build/Dockerfile
Normal file
36
build/Dockerfile
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
# 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.1.1.7z
|
||||||
|
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.1.1.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 .
|
||||||
|
|
||||||
|
# start gaseous-server
|
||||||
|
ENTRYPOINT ["dotnet", "gaseous-server.dll"]
|
76
build/Dockerfile-EmbeddedDB
Normal file
76
build/Dockerfile-EmbeddedDB
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
# 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.1.1.7z
|
||||||
|
RUN 7z x -y -oout/wwwroot/emulators/EmulatorJS 4.1.1.7z
|
||||||
|
|
||||||
|
RUN wget --recursive --no-parent https://cdn.emulatorjs.org/latest/
|
||||||
|
RUN mkdir -p out/wwwroot/emulators/EmulatorJS
|
||||||
|
RUN cp -fr cdn.emulatorjs.org/latest/* out/wwwroot/emulators/EmulatorJS
|
||||||
|
RUN rm -Rf cdn.emulatorjs.org
|
||||||
|
|
||||||
|
# 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/mariadb.sh /usr/sbin/start-mariadb.sh
|
||||||
|
RUN chmod +x /usr/sbin/start-mariadb.sh
|
||||||
|
|
||||||
|
# install supervisord
|
||||||
|
RUN apt-get install -y supervisor
|
||||||
|
COPY ../build/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
RUN mkdir -p /var/run/supervisord
|
||||||
|
RUN mkdir -p /var/log/supervisord
|
||||||
|
|
||||||
|
# clean up apt-get
|
||||||
|
RUN apt-get clean && rm -rf /var/lib/apt/lists
|
||||||
|
|
||||||
|
# copy entrypoint
|
||||||
|
COPY ../build/entrypoint.sh /usr/sbin/entrypoint.sh
|
||||||
|
RUN chmod +x /usr/sbin/entrypoint.sh
|
||||||
|
|
||||||
|
# volumes
|
||||||
|
VOLUME /home/gaseous/.gaseous-server /var/lib/mysql
|
||||||
|
|
||||||
|
# start services
|
||||||
|
ENTRYPOINT [ "/usr/sbin/entrypoint.sh" ]
|
13
build/entrypoint.sh
Normal file
13
build/entrypoint.sh
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# create the user
|
||||||
|
echo "Creating user gaseous with UID ${PUID} and GID ${PGID}"
|
||||||
|
groupadd -g ${PGID} gaseous
|
||||||
|
useradd -u ${PUID} -g ${PGID} -m gaseous -d /home/gaseous -G sudo
|
||||||
|
usermod -p "*" gaseous
|
||||||
|
mkdir -p /home/gaseous/.gaseous-server /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||||
|
chown -R ${PUID} /App /home/gaseous/.gaseous-server /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||||
|
chgrp -R ${PGID} /App /home/gaseous/.gaseous-server /var/lib/mysql /var/log/mariadb /run/mysqld
|
||||||
|
|
||||||
|
# Start supervisord and services
|
||||||
|
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
20
build/mariadb.sh
Normal file
20
build/mariadb.sh
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# install the database
|
||||||
|
/usr/bin/mariadb-install-db --datadir=/var/lib/mysql --user=gaseous
|
||||||
|
|
||||||
|
# start the database server without network or grant tables
|
||||||
|
/usr/sbin/mariadbd --datadir=/var/lib/mysql --skip-grant-tables --skip-networking &
|
||||||
|
|
||||||
|
# wait for the server to start
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# change the root password
|
||||||
|
mariadb -u root -e "FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY '$MARIADB_ROOT_PASSWORD'; ALTER USER 'gaseous'@'localhost' IDENTIFIED BY '$MARIADB_ROOT_PASSWORD'; FLUSH PRIVILEGES; SHUTDOWN;"
|
||||||
|
|
||||||
|
# stop the server
|
||||||
|
sleep 5
|
||||||
|
killall mariadbd
|
||||||
|
|
||||||
|
# start the server normally
|
||||||
|
/usr/sbin/mariadbd --datadir=/var/lib/mysql
|
37
build/supervisord.conf
Normal file
37
build/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
|
@@ -14,6 +14,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- gs:/root/.gaseous-server
|
- gs:/root/.gaseous-server
|
||||||
environment:
|
environment:
|
||||||
|
- TZ=Australia/Sydney
|
||||||
- dbhost=gsdb
|
- dbhost=gsdb
|
||||||
- dbuser=root
|
- dbuser=root
|
||||||
- dbpass=gaseous
|
- dbpass=gaseous
|
@@ -1,39 +0,0 @@
|
|||||||
version: '2'
|
|
||||||
services:
|
|
||||||
gaseous-server:
|
|
||||||
container_name: gaseous-server
|
|
||||||
build:
|
|
||||||
context: ./
|
|
||||||
restart: unless-stopped
|
|
||||||
networks:
|
|
||||||
- gaseous
|
|
||||||
depends_on:
|
|
||||||
- gsdb
|
|
||||||
ports:
|
|
||||||
- 5198:80
|
|
||||||
volumes:
|
|
||||||
- gs:/root/.gaseous-server
|
|
||||||
environment:
|
|
||||||
- dbhost=gsdb
|
|
||||||
- dbuser=root
|
|
||||||
- dbpass=gaseous
|
|
||||||
- igdbclientid=<clientid>
|
|
||||||
- igdbclientsecret=<clientsecret>
|
|
||||||
gsdb:
|
|
||||||
container_name: gsdb
|
|
||||||
image: mysql:8
|
|
||||||
restart: unless-stopped
|
|
||||||
networks:
|
|
||||||
- gaseous
|
|
||||||
volumes:
|
|
||||||
- gsdb:/var/lib/mysql
|
|
||||||
environment:
|
|
||||||
- MYSQL_ROOT_PASSWORD=gaseous
|
|
||||||
- MYSQL_USER=gaseous
|
|
||||||
- MYSQL_PASSWORD=gaseous
|
|
||||||
networks:
|
|
||||||
gaseous:
|
|
||||||
driver: bridge
|
|
||||||
volumes:
|
|
||||||
gs:
|
|
||||||
gsdb:
|
|
@@ -1,38 +0,0 @@
|
|||||||
version: '2'
|
|
||||||
services:
|
|
||||||
gaseous-server:
|
|
||||||
container_name: gaseous-server
|
|
||||||
image: gaseousgames/gaseousserver:latest
|
|
||||||
restart: unless-stopped
|
|
||||||
networks:
|
|
||||||
- gaseous
|
|
||||||
depends_on:
|
|
||||||
- gsdb
|
|
||||||
ports:
|
|
||||||
- 5198:80
|
|
||||||
volumes:
|
|
||||||
- gs:/root/.gaseous-server
|
|
||||||
environment:
|
|
||||||
- dbhost=gsdb
|
|
||||||
- dbuser=root
|
|
||||||
- dbpass=gaseous
|
|
||||||
- igdbclientid=<clientid>
|
|
||||||
- igdbclientsecret=<clientsecret>
|
|
||||||
gsdb:
|
|
||||||
container_name: gsdb
|
|
||||||
image: mysql:8
|
|
||||||
restart: unless-stopped
|
|
||||||
networks:
|
|
||||||
- gaseous
|
|
||||||
volumes:
|
|
||||||
- gsdb:/var/lib/mysql
|
|
||||||
environment:
|
|
||||||
- MYSQL_ROOT_PASSWORD=gaseous
|
|
||||||
- MYSQL_USER=gaseous
|
|
||||||
- MYSQL_PASSWORD=gaseous
|
|
||||||
networks:
|
|
||||||
gaseous:
|
|
||||||
driver: bridge
|
|
||||||
volumes:
|
|
||||||
gs:
|
|
||||||
gsdb:
|
|
@@ -13,6 +13,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- gs:/root/.gaseous-server
|
- gs:/root/.gaseous-server
|
||||||
environment:
|
environment:
|
||||||
|
- TZ=Australia/Sydney
|
||||||
- dbhost=gsdb
|
- dbhost=gsdb
|
||||||
- dbuser=root
|
- dbuser=root
|
||||||
- dbpass=gaseous
|
- dbpass=gaseous
|
BIN
gaseous-server/.DS_Store
vendored
BIN
gaseous-server/.DS_Store
vendored
Binary file not shown.
@@ -12,5 +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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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 where Id = @id";
|
string commandText = "Select * from Users LEFT JOIN (SELECT UserId, Id AS AvatarId FROM UserAvatars) UserAvatars ON Users.Id = UserAvatars.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);
|
||||||
@@ -100,6 +100,7 @@ namespace Authentication
|
|||||||
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"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
@@ -113,7 +114,7 @@ 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 where NormalizedEmail = @name";
|
string commandText = "Select * from Users LEFT JOIN (SELECT UserId, Id AS AvatarId FROM UserAvatars) UserAvatars ON Users.Id = UserAvatars.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);
|
||||||
@@ -137,6 +138,7 @@ namespace Authentication
|
|||||||
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"]);
|
||||||
users.Add(user);
|
users.Add(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +148,7 @@ 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 order by NormalizedUserName";
|
string commandText = "Select * from Users LEFT JOIN (SELECT UserId, Id AS AvatarId FROM UserAvatars) UserAvatars ON Users.Id = UserAvatars.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)
|
||||||
@@ -169,6 +171,7 @@ namespace Authentication
|
|||||||
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"]);
|
||||||
users.Add(user);
|
users.Add(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,7 +292,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;";
|
string commandText = "Delete from Users where Id = @userId; Delete from User_Settings where Id = @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);
|
||||||
|
|
||||||
@@ -437,5 +440,30 @@ namespace Authentication
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Guid SetAvatar(TUser user, byte[] bytes)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql;
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "userid", user.Id }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (bytes.Length == 0)
|
||||||
|
{
|
||||||
|
sql = "DELETE FROM UserAvatars WHERE UserId = @userid";
|
||||||
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
return Guid.Empty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sql = "DELETE FROM UserAvatars WHERE UserId = @userid; INSERT INTO UserAvatars (UserId, Id, Avatar) VALUES (@userid, @id, @avatar);";
|
||||||
|
dbDict.Add("id", Guid.NewGuid());
|
||||||
|
dbDict.Add("avatar", bytes);
|
||||||
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
return (Guid)dbDict["id"];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@ 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 string HighestRole {
|
public string HighestRole {
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@@ -8,6 +8,7 @@ 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 string HighestRole {
|
public string HighestRole {
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@@ -7,33 +7,26 @@ using System.Security.Cryptography;
|
|||||||
using Authentication;
|
using Authentication;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
using gaseous_server.Controllers;
|
using gaseous_server.Controllers;
|
||||||
|
using gaseous_server.Controllers.v1_1;
|
||||||
using gaseous_server.Models;
|
using gaseous_server.Models;
|
||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using SharpCompress.Common;
|
using SharpCompress.Common;
|
||||||
|
using static gaseous_server.Classes.Metadata.Games;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
public class Collections
|
public class Collections
|
||||||
{
|
{
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
public static List<CollectionItem> GetCollections(string userid) {
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
|
||||||
|
|
||||||
public Collections(
|
|
||||||
UserManager<ApplicationUser> userManager,
|
|
||||||
SignInManager<ApplicationUser> signInManager)
|
|
||||||
{
|
|
||||||
_userManager = userManager;
|
|
||||||
_signInManager = signInManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<CollectionItem> GetCollections() {
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM RomCollections ORDER BY `Name`";
|
string sql = "SELECT * FROM RomCollections WHERE OwnedBy=@ownedby ORDER BY `Name`";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||||
DataTable data = db.ExecuteCMD(sql);
|
{ "ownedby", userid }
|
||||||
|
};
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
List<CollectionItem> collectionItems = new List<CollectionItem>();
|
List<CollectionItem> collectionItems = new List<CollectionItem>();
|
||||||
|
|
||||||
@@ -44,11 +37,24 @@ namespace gaseous_server.Classes
|
|||||||
return collectionItems;
|
return collectionItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CollectionItem GetCollection(long Id) {
|
public static CollectionItem GetCollection(long Id, string userid) {
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM RomCollections WHERE Id = @id ORDER BY `Name`";
|
string sql;
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
if (userid == "")
|
||||||
dbDict.Add("id", Id);
|
{
|
||||||
|
// reserved for internal operations
|
||||||
|
sql = "SELECT * FROM RomCollections WHERE Id = @id ORDER BY `Name`";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// instigated by a user
|
||||||
|
sql = "SELECT * FROM RomCollections WHERE Id = @id AND OwnedBy = @ownedby ORDER BY `Name`";
|
||||||
|
}
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "id", Id },
|
||||||
|
{ "ownedby", userid }
|
||||||
|
};
|
||||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
if (romDT.Rows.Count > 0)
|
if (romDT.Rows.Count > 0)
|
||||||
@@ -64,60 +70,66 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CollectionItem NewCollection(CollectionItem item)
|
public static CollectionItem NewCollection(CollectionItem item, string userid)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "INSERT INTO RomCollections (`Name`, Description, Platforms, Genres, Players, PlayerPerspectives, Themes, MinimumRating, MaximumRating, MaximumRomsPerPlatform, MaximumBytesPerPlatform, MaximumCollectionSizeInBytes, FolderStructure, IncludeBIOSFiles, ArchiveType, AlwaysInclude, BuiltStatus) VALUES (@name, @description, @platforms, @genres, @players, @playerperspectives, @themes, @minimumrating, @maximumrating, @maximumromsperplatform, @maximumbytesperplatform, @maximumcollectionsizeinbytes, @folderstructure, @includebiosfiles, @archivetype, @alwaysinclude, @builtstatus); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
string sql = "INSERT INTO RomCollections (`Name`, Description, Platforms, Genres, Players, PlayerPerspectives, Themes, MinimumRating, MaximumRating, MaximumRomsPerPlatform, MaximumBytesPerPlatform, MaximumCollectionSizeInBytes, FolderStructure, IncludeBIOSFiles, ArchiveType, AlwaysInclude, BuiltStatus, OwnedBy) VALUES (@name, @description, @platforms, @genres, @players, @playerperspectives, @themes, @minimumrating, @maximumrating, @maximumromsperplatform, @maximumbytesperplatform, @maximumcollectionsizeinbytes, @folderstructure, @includebiosfiles, @archivetype, @alwaysinclude, @builtstatus, @ownedby); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
dbDict.Add("name", item.Name);
|
{
|
||||||
dbDict.Add("description", item.Description);
|
{ "name", item.Name },
|
||||||
dbDict.Add("platforms", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Platforms, new List<long>())));
|
{ "description", item.Description },
|
||||||
dbDict.Add("genres", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Genres, new List<long>())));
|
{ "platforms", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Platforms, new List<long>())) },
|
||||||
dbDict.Add("players", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Players, new List<long>())));
|
{ "genres", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Genres, new List<long>())) },
|
||||||
dbDict.Add("playerperspectives", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.PlayerPerspectives, new List<long>())));
|
{ "players", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Players, new List<long>())) },
|
||||||
dbDict.Add("themes", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Themes, new List<long>())));
|
{ "playerperspectives", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.PlayerPerspectives, new List<long>())) },
|
||||||
dbDict.Add("minimumrating", Common.ReturnValueIfNull(item.MinimumRating, -1));
|
{ "themes", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Themes, new List<long>())) },
|
||||||
dbDict.Add("maximumrating", Common.ReturnValueIfNull(item.MaximumRating, -1));
|
{ "minimumrating", Common.ReturnValueIfNull(item.MinimumRating, -1) },
|
||||||
dbDict.Add("maximumromsperplatform", Common.ReturnValueIfNull(item.MaximumRomsPerPlatform, -1));
|
{ "maximumrating", Common.ReturnValueIfNull(item.MaximumRating, -1) },
|
||||||
dbDict.Add("maximumbytesperplatform", Common.ReturnValueIfNull(item.MaximumBytesPerPlatform, -1));
|
{ "maximumromsperplatform", Common.ReturnValueIfNull(item.MaximumRomsPerPlatform, -1) },
|
||||||
dbDict.Add("maximumcollectionsizeinbytes", Common.ReturnValueIfNull(item.MaximumCollectionSizeInBytes, -1));
|
{ "maximumbytesperplatform", Common.ReturnValueIfNull(item.MaximumBytesPerPlatform, -1) },
|
||||||
dbDict.Add("folderstructure", Common.ReturnValueIfNull(item.FolderStructure, CollectionItem.FolderStructures.Gaseous));
|
{ "maximumcollectionsizeinbytes", Common.ReturnValueIfNull(item.MaximumCollectionSizeInBytes, -1) },
|
||||||
dbDict.Add("includebiosfiles", Common.ReturnValueIfNull(item.IncludeBIOSFiles, 0));
|
{ "folderstructure", Common.ReturnValueIfNull(item.FolderStructure, CollectionItem.FolderStructures.Gaseous) },
|
||||||
dbDict.Add("archivetype", Common.ReturnValueIfNull(item.ArchiveType, CollectionItem.ArchiveTypes.Zip));
|
{ "includebiosfiles", Common.ReturnValueIfNull(item.IncludeBIOSFiles, 0) },
|
||||||
dbDict.Add("alwaysinclude", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.AlwaysInclude, new List<CollectionItem.AlwaysIncludeItem>())));
|
{ "archivetype", Common.ReturnValueIfNull(item.ArchiveType, CollectionItem.ArchiveTypes.Zip) },
|
||||||
dbDict.Add("builtstatus", CollectionItem.CollectionBuildStatus.WaitingForBuild);
|
{ "alwaysinclude", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.AlwaysInclude, new List<CollectionItem.AlwaysIncludeItem>())) },
|
||||||
|
{ "builtstatus", CollectionItem.CollectionBuildStatus.WaitingForBuild },
|
||||||
|
{ "ownedby", userid }
|
||||||
|
};
|
||||||
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
DataTable romDT = db.ExecuteCMD(sql, dbDict);
|
||||||
long CollectionId = (long)romDT.Rows[0][0];
|
long CollectionId = (long)romDT.Rows[0][0];
|
||||||
|
|
||||||
CollectionItem collectionItem = GetCollection(CollectionId);
|
CollectionItem collectionItem = GetCollection(CollectionId, userid);
|
||||||
|
|
||||||
StartCollectionItemBuild(CollectionId);
|
StartCollectionItemBuild(CollectionId, userid);
|
||||||
|
|
||||||
return collectionItem;
|
return collectionItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CollectionItem EditCollection(long Id, CollectionItem item, bool ForceRebuild = true)
|
public static CollectionItem EditCollection(long Id, CollectionItem item, string userid, bool ForceRebuild = true)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "UPDATE RomCollections SET `Name`=@name, Description=@description, Platforms=@platforms, Genres=@genres, Players=@players, PlayerPerspectives=@playerperspectives, Themes=@themes, MinimumRating=@minimumrating, MaximumRating=@maximumrating, MaximumRomsPerPlatform=@maximumromsperplatform, MaximumBytesPerPlatform=@maximumbytesperplatform, MaximumCollectionSizeInBytes=@maximumcollectionsizeinbytes, FolderStructure=@folderstructure, IncludeBIOSFiles=@includebiosfiles, ArchiveType=@archivetype, AlwaysInclude=@alwaysinclude, BuiltStatus=@builtstatus WHERE Id=@id";
|
string sql = "UPDATE RomCollections SET `Name`=@name, Description=@description, Platforms=@platforms, Genres=@genres, Players=@players, PlayerPerspectives=@playerperspectives, Themes=@themes, MinimumRating=@minimumrating, MaximumRating=@maximumrating, MaximumRomsPerPlatform=@maximumromsperplatform, MaximumBytesPerPlatform=@maximumbytesperplatform, MaximumCollectionSizeInBytes=@maximumcollectionsizeinbytes, FolderStructure=@folderstructure, IncludeBIOSFiles=@includebiosfiles, ArchiveType=@archivetype, AlwaysInclude=@alwaysinclude, BuiltStatus=@builtstatus WHERE Id=@id AND OwnedBy=@ownedby";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
dbDict.Add("id", Id);
|
{
|
||||||
dbDict.Add("name", item.Name);
|
{ "id", Id },
|
||||||
dbDict.Add("description", item.Description);
|
{ "name", item.Name },
|
||||||
dbDict.Add("platforms", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Platforms, new List<long>())));
|
{ "description", item.Description },
|
||||||
dbDict.Add("genres", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Genres, new List<long>())));
|
{ "platforms", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Platforms, new List<long>())) },
|
||||||
dbDict.Add("players", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Players, new List<long>())));
|
{ "genres", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Genres, new List<long>())) },
|
||||||
dbDict.Add("playerperspectives", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.PlayerPerspectives, new List<long>())));
|
{ "players", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Players, new List<long>())) },
|
||||||
dbDict.Add("themes", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Themes, new List<long>())));
|
{ "playerperspectives", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.PlayerPerspectives, new List<long>())) },
|
||||||
dbDict.Add("minimumrating", Common.ReturnValueIfNull(item.MinimumRating, -1));
|
{ "themes", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.Themes, new List<long>())) },
|
||||||
dbDict.Add("maximumrating", Common.ReturnValueIfNull(item.MaximumRating, -1));
|
{ "minimumrating", Common.ReturnValueIfNull(item.MinimumRating, -1) },
|
||||||
dbDict.Add("maximumromsperplatform", Common.ReturnValueIfNull(item.MaximumRomsPerPlatform, -1));
|
{ "maximumrating", Common.ReturnValueIfNull(item.MaximumRating, -1) },
|
||||||
dbDict.Add("maximumbytesperplatform", Common.ReturnValueIfNull(item.MaximumBytesPerPlatform, -1));
|
{ "maximumromsperplatform", Common.ReturnValueIfNull(item.MaximumRomsPerPlatform, -1) },
|
||||||
dbDict.Add("maximumcollectionsizeinbytes", Common.ReturnValueIfNull(item.MaximumCollectionSizeInBytes, -1));
|
{ "maximumbytesperplatform", Common.ReturnValueIfNull(item.MaximumBytesPerPlatform, -1) },
|
||||||
dbDict.Add("folderstructure", Common.ReturnValueIfNull(item.FolderStructure, CollectionItem.FolderStructures.Gaseous));
|
{ "maximumcollectionsizeinbytes", Common.ReturnValueIfNull(item.MaximumCollectionSizeInBytes, -1) },
|
||||||
dbDict.Add("includebiosfiles", Common.ReturnValueIfNull(item.IncludeBIOSFiles, 0));
|
{ "folderstructure", Common.ReturnValueIfNull(item.FolderStructure, CollectionItem.FolderStructures.Gaseous) },
|
||||||
dbDict.Add("alwaysinclude", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.AlwaysInclude, new List<CollectionItem.AlwaysIncludeItem>())));
|
{ "includebiosfiles", Common.ReturnValueIfNull(item.IncludeBIOSFiles, 0) },
|
||||||
dbDict.Add("archivetype", Common.ReturnValueIfNull(item.ArchiveType, CollectionItem.ArchiveTypes.Zip));
|
{ "alwaysinclude", Newtonsoft.Json.JsonConvert.SerializeObject(Common.ReturnValueIfNull(item.AlwaysInclude, new List<CollectionItem.AlwaysIncludeItem>())) },
|
||||||
|
{ "archivetype", Common.ReturnValueIfNull(item.ArchiveType, CollectionItem.ArchiveTypes.Zip) },
|
||||||
|
{ "ownedby", userid }
|
||||||
|
};
|
||||||
|
|
||||||
string CollectionZipFile = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + item.ArchiveExtension);
|
string CollectionZipFile = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + item.ArchiveExtension);
|
||||||
if (ForceRebuild == true)
|
if (ForceRebuild == true)
|
||||||
@@ -142,22 +154,25 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
CollectionItem collectionItem = GetCollection(Id);
|
CollectionItem collectionItem = GetCollection(Id, userid);
|
||||||
|
|
||||||
if (collectionItem.BuildStatus == CollectionItem.CollectionBuildStatus.WaitingForBuild)
|
if (collectionItem.BuildStatus == CollectionItem.CollectionBuildStatus.WaitingForBuild)
|
||||||
{
|
{
|
||||||
StartCollectionItemBuild(Id);
|
StartCollectionItemBuild(Id, userid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return collectionItem;
|
return collectionItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DeleteCollection(long Id)
|
public static void DeleteCollection(long Id, string userid)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "DELETE FROM RomCollections WHERE Id=@id";
|
string sql = "DELETE FROM RomCollections WHERE Id=@id AND OwnedBy=@ownedby";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
dbDict.Add("id", Id);
|
{
|
||||||
|
{ "id", Id },
|
||||||
|
{ "ownedby", userid }
|
||||||
|
};
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
string CollectionZipFile = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + ".zip");
|
string CollectionZipFile = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, Id + ".zip");
|
||||||
@@ -167,9 +182,10 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void StartCollectionItemBuild(long Id)
|
public static void StartCollectionItemBuild(long Id, string userid)
|
||||||
{
|
{
|
||||||
CollectionItem collectionItem = GetCollection(Id);
|
// send blank user id to getcollection as this is not a user initiated process
|
||||||
|
CollectionItem collectionItem = GetCollection(Id, userid);
|
||||||
|
|
||||||
if (collectionItem.BuildStatus != CollectionItem.CollectionBuildStatus.Building)
|
if (collectionItem.BuildStatus != CollectionItem.CollectionBuildStatus.Building)
|
||||||
{
|
{
|
||||||
@@ -183,13 +199,40 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// start background task
|
// start background task
|
||||||
ProcessQueue.QueueItem queueItem = new ProcessQueue.QueueItem(ProcessQueue.QueueItemType.CollectionCompiler, 1, false, true);
|
ProcessQueue.QueueItem queueItem = new ProcessQueue.QueueItem(ProcessQueue.QueueItemType.CollectionCompiler, 1, false, true);
|
||||||
queueItem.Options = Id;
|
queueItem.Options = new Dictionary<string, object>{
|
||||||
|
{ "Id", Id },
|
||||||
|
{ "UserId", userid }
|
||||||
|
};
|
||||||
queueItem.ForceExecute();
|
queueItem.ForceExecute();
|
||||||
ProcessQueue.QueueItems.Add(queueItem);
|
ProcessQueue.QueueItems.Add(queueItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CollectionContents GetCollectionContent(CollectionItem collectionItem) {
|
public static CollectionContents GetCollectionContent(CollectionItem collectionItem, string userid) {
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
|
||||||
|
// get age ratings for specified user
|
||||||
|
List<AgeGroups.AgeRestrictionGroupings> UserAgeGroupings = new List<AgeGroups.AgeRestrictionGroupings>();
|
||||||
|
bool UserAgeGroupIncludeUnrated = true;
|
||||||
|
if (userid != "")
|
||||||
|
{
|
||||||
|
Authentication.UserTable<Authentication.ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||||
|
var user = userTable.GetUserById(userid);
|
||||||
|
|
||||||
|
if (user.SecurityProfile.AgeRestrictionPolicy.IncludeUnrated == false)
|
||||||
|
{
|
||||||
|
UserAgeGroupIncludeUnrated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (AgeGroups.AgeRestrictionGroupings ageGrouping in Enum.GetValues(typeof(AgeGroups.AgeRestrictionGroupings)))
|
||||||
|
{
|
||||||
|
if (ageGrouping <= user.SecurityProfile.AgeRestrictionPolicy.MaximumAgeRestriction && ageGrouping != AgeGroups.AgeRestrictionGroupings.Unclassified)
|
||||||
|
{
|
||||||
|
UserAgeGroupings.Add(ageGrouping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<CollectionContents.CollectionPlatformItem> collectionPlatformItems = new List<CollectionContents.CollectionPlatformItem>();
|
List<CollectionContents.CollectionPlatformItem> collectionPlatformItems = new List<CollectionContents.CollectionPlatformItem>();
|
||||||
|
|
||||||
// get platforms
|
// get platforms
|
||||||
@@ -230,6 +273,10 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// age ratings
|
||||||
|
AgeGroups.AgeRestrictionGroupings AgeGrouping = AgeGroups.AgeRestrictionGroupings.Unclassified;
|
||||||
|
bool ContainsUnclassifiedAgeGroup = false;
|
||||||
|
|
||||||
// build collection
|
// build collection
|
||||||
List<CollectionContents.CollectionPlatformItem> platformItems = new List<CollectionContents.CollectionPlatformItem>();
|
List<CollectionContents.CollectionPlatformItem> platformItems = new List<CollectionContents.CollectionPlatformItem>();
|
||||||
|
|
||||||
@@ -247,18 +294,29 @@ namespace gaseous_server.Classes
|
|||||||
isDynamic = true;
|
isDynamic = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Game> games = new List<Game>();
|
Controllers.v1_1.GamesController.GameReturnPackage games = new Controllers.v1_1.GamesController.GameReturnPackage();
|
||||||
if (isDynamic == true)
|
if (isDynamic == true)
|
||||||
{
|
{
|
||||||
games = GamesController.GetGames("",
|
Controllers.v1_1.GamesController.GameSearchModel searchModel = new Controllers.v1_1.GamesController.GameSearchModel{
|
||||||
platform.Id.ToString(),
|
Name = "",
|
||||||
string.Join(",", collectionItem.Genres),
|
Platform = new List<string>{
|
||||||
string.Join(",", collectionItem.Players),
|
platform.Id.ToString()
|
||||||
string.Join(",", collectionItem.PlayerPerspectives),
|
},
|
||||||
string.Join(",", collectionItem.Themes),
|
Genre = collectionItem.Genres.ConvertAll(s => s.ToString()),
|
||||||
collectionItem.MinimumRating,
|
GameMode = collectionItem.Players.ConvertAll(s => s.ToString()),
|
||||||
collectionItem.MaximumRating
|
PlayerPerspective = collectionItem.PlayerPerspectives.ConvertAll(s => s.ToString()),
|
||||||
);
|
Theme = collectionItem.Themes.ConvertAll(s => s.ToString()),
|
||||||
|
GameRating = new Controllers.v1_1.GamesController.GameSearchModel.GameRatingItem{
|
||||||
|
MinimumRating = collectionItem.MinimumRating,
|
||||||
|
MaximumRating = collectionItem.MaximumRating
|
||||||
|
},
|
||||||
|
GameAgeRating = new Controllers.v1_1.GamesController.GameSearchModel.GameAgeRatingItem{
|
||||||
|
AgeGroupings = UserAgeGroupings,
|
||||||
|
IncludeUnrated = UserAgeGroupIncludeUnrated
|
||||||
|
}
|
||||||
|
};
|
||||||
|
games = Controllers.v1_1.GamesController.GetGames(searchModel, userid);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionContents.CollectionPlatformItem collectionPlatformItem = new CollectionContents.CollectionPlatformItem(platform);
|
CollectionContents.CollectionPlatformItem collectionPlatformItem = new CollectionContents.CollectionPlatformItem(platform);
|
||||||
@@ -274,7 +332,7 @@ namespace gaseous_server.Classes
|
|||||||
) && alwaysIncludeItem.PlatformId == platform.Id
|
) && alwaysIncludeItem.PlatformId == platform.Id
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Game AlwaysIncludeGame = Games.GetGame(alwaysIncludeItem.GameId, false, false, false);
|
MinimalGameItem AlwaysIncludeGame = new MinimalGameItem(Games.GetGame(alwaysIncludeItem.GameId, false, false, false));
|
||||||
CollectionContents.CollectionPlatformItem.CollectionGameItem gameItem = new CollectionContents.CollectionPlatformItem.CollectionGameItem(AlwaysIncludeGame);
|
CollectionContents.CollectionPlatformItem.CollectionGameItem gameItem = new CollectionContents.CollectionPlatformItem.CollectionGameItem(AlwaysIncludeGame);
|
||||||
gameItem.InclusionStatus = new CollectionItem.AlwaysIncludeItem();
|
gameItem.InclusionStatus = new CollectionItem.AlwaysIncludeItem();
|
||||||
gameItem.InclusionStatus.PlatformId = alwaysIncludeItem.PlatformId;
|
gameItem.InclusionStatus.PlatformId = alwaysIncludeItem.PlatformId;
|
||||||
@@ -286,7 +344,7 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Game game in games) {
|
foreach (MinimalGameItem game in games.Games) {
|
||||||
bool gameAlreadyInList = false;
|
bool gameAlreadyInList = false;
|
||||||
foreach (CollectionContents.CollectionPlatformItem.CollectionGameItem existingGame in collectionPlatformItem.Games)
|
foreach (CollectionContents.CollectionPlatformItem.CollectionGameItem existingGame in collectionPlatformItem.Games)
|
||||||
{
|
{
|
||||||
@@ -341,6 +399,17 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle age grouping
|
||||||
|
AgeGroups.AgeRestrictionGroupings CurrentAgeGroup = AgeGroups.GetAgeGroupFromAgeRatings(game.AgeRatings);
|
||||||
|
if (CurrentAgeGroup > AgeGrouping)
|
||||||
|
{
|
||||||
|
AgeGrouping = CurrentAgeGroup;
|
||||||
|
}
|
||||||
|
if (CurrentAgeGroup == AgeGroups.AgeRestrictionGroupings.Unclassified)
|
||||||
|
{
|
||||||
|
ContainsUnclassifiedAgeGroup = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
collectionPlatformItem.Games.Sort((x, y) => x.Name.CompareTo(y.Name));
|
collectionPlatformItem.Games.Sort((x, y) => x.Name.CompareTo(y.Name));
|
||||||
@@ -369,29 +438,39 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
collectionPlatformItems.Sort((x, y) => x.Name.CompareTo(y.Name));
|
collectionPlatformItems.Sort((x, y) => x.Name.CompareTo(y.Name));
|
||||||
|
|
||||||
CollectionContents collectionContents = new CollectionContents();
|
CollectionContents collectionContents = new CollectionContents
|
||||||
collectionContents.Collection = collectionPlatformItems;
|
{
|
||||||
|
Collection = collectionPlatformItems,
|
||||||
|
AgeGroup = AgeGrouping,
|
||||||
|
ContainsUnclassifiedAgeGroup = ContainsUnclassifiedAgeGroup
|
||||||
|
};
|
||||||
|
|
||||||
return collectionContents;
|
return collectionContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CompileCollections(long CollectionId)
|
public static void CompileCollections(long CollectionId, string userid)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
|
||||||
CollectionItem collectionItem = GetCollection(CollectionId);
|
CollectionItem collectionItem = GetCollection(CollectionId, userid);
|
||||||
if (collectionItem.BuildStatus == CollectionItem.CollectionBuildStatus.WaitingForBuild)
|
if (collectionItem.BuildStatus == CollectionItem.CollectionBuildStatus.WaitingForBuild)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Collections", "Beginning build of collection: " + collectionItem.Name);
|
Logging.Log(Logging.LogType.Information, "Collections", "Beginning build of collection: " + collectionItem.Name);
|
||||||
|
|
||||||
|
CollectionContents collectionContents = GetCollectionContent(collectionItem, userid);
|
||||||
|
|
||||||
// set starting
|
// set starting
|
||||||
string sql = "UPDATE RomCollections SET BuiltStatus=@bs WHERE Id=@id";
|
string sql = "UPDATE RomCollections SET BuiltStatus=@bs, AgeGroup=@ag, AgeGroupUnclassified=@agu WHERE Id=@id";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
dbDict.Add("id", collectionItem.Id);
|
{
|
||||||
dbDict.Add("bs", CollectionItem.CollectionBuildStatus.Building);
|
{ "id", collectionItem.Id },
|
||||||
|
{ "bs", CollectionItem.CollectionBuildStatus.Building },
|
||||||
|
{ "ag", collectionContents.AgeGroup },
|
||||||
|
{ "agu", collectionContents.ContainsUnclassifiedAgeGroup }
|
||||||
|
};
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
List<CollectionContents.CollectionPlatformItem> collectionPlatformItems = GetCollectionContent(collectionItem).Collection;
|
List<CollectionContents.CollectionPlatformItem> collectionPlatformItems = collectionContents.Collection;
|
||||||
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, collectionItem.Id + collectionItem.ArchiveExtension);
|
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, collectionItem.Id + collectionItem.ArchiveExtension);
|
||||||
string ZipFileTempPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, collectionItem.Id.ToString());
|
string ZipFileTempPath = Path.Combine(Config.LibraryConfiguration.LibraryTempDirectory, collectionItem.Id.ToString());
|
||||||
|
|
||||||
@@ -758,6 +837,9 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AgeGroups.AgeRestrictionGroupings AgeGroup { get; set; }
|
||||||
|
public bool ContainsUnclassifiedAgeGroup { get; set; }
|
||||||
|
|
||||||
public class CollectionPlatformItem {
|
public class CollectionPlatformItem {
|
||||||
public CollectionPlatformItem(IGDB.Models.Platform platform) {
|
public CollectionPlatformItem(IGDB.Models.Platform platform) {
|
||||||
string[] PropertyWhitelist = new string[] { "Id", "Name", "Slug" };
|
string[] PropertyWhitelist = new string[] { "Id", "Name", "Slug" };
|
||||||
@@ -808,49 +890,44 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CollectionGameItem {
|
public class CollectionGameItem : MinimalGameItem
|
||||||
public CollectionGameItem(IGDB.Models.Game game) {
|
|
||||||
string[] PropertyWhitelist = new string[] { "Id", "Name", "Slug", "Cover" };
|
|
||||||
PropertyInfo[] srcProperties = typeof(IGDB.Models.Game).GetProperties();
|
|
||||||
PropertyInfo[] dstProperties = typeof(CollectionPlatformItem.CollectionGameItem).GetProperties();
|
|
||||||
foreach (PropertyInfo srcProperty in srcProperties) {
|
|
||||||
if (PropertyWhitelist.Contains<string>(srcProperty.Name))
|
|
||||||
{
|
{
|
||||||
foreach (PropertyInfo dstProperty in dstProperties)
|
public CollectionGameItem(MinimalGameItem gameObject)
|
||||||
{
|
{
|
||||||
if (srcProperty.Name == dstProperty.Name)
|
this.Id = gameObject.Id;
|
||||||
{
|
this.Name = gameObject.Name;
|
||||||
if (srcProperty.GetValue(game) != null) {
|
this.Slug = gameObject.Slug;
|
||||||
string compareName = srcProperty.PropertyType.Name.ToLower().Split("`")[0];
|
this.TotalRating = gameObject.TotalRating;
|
||||||
switch(compareName) {
|
this.TotalRatingCount = gameObject.TotalRatingCount;
|
||||||
case "identityorvalue":
|
this.Cover = gameObject.Cover;
|
||||||
string newObjectValue = Newtonsoft.Json.JsonConvert.SerializeObject(srcProperty.GetValue(game));
|
this.Artworks = gameObject.Artworks;
|
||||||
Dictionary<string, object> newDict = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(newObjectValue);
|
this.FirstReleaseDate = gameObject.FirstReleaseDate;
|
||||||
dstProperty.SetValue(this, newDict["Id"]);
|
this.AgeRatings = gameObject.AgeRatings;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dstProperty.SetValue(this, srcProperty.GetValue(game));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long Id { get; set; }
|
public IGDB.Models.Cover? CoverItem
|
||||||
public string Name { get; set; }
|
|
||||||
public string Slug { get; set; }
|
|
||||||
public long Cover { get; set;}
|
|
||||||
public IGDB.Models.Cover CoverItem
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
IGDB.Models.Cover cover = Covers.GetCover(Cover, Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory, "Games", Slug), false);
|
if (Cover != null)
|
||||||
|
{
|
||||||
|
IGDB.Models.Cover cover = Covers.GetCover(Cover.Id, Path.Combine(Config.LibraryConfiguration.LibraryMetadataDirectory, "Games", Slug), false);
|
||||||
|
|
||||||
return cover;
|
return cover;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AgeGroups.AgeRestrictionGroupings AgeGrouping
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return AgeGroups.GetAgeGroupFromAgeRatings(this.AgeRatings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CollectionItem.AlwaysIncludeItem InclusionStatus { get; set; }
|
public CollectionItem.AlwaysIncludeItem InclusionStatus { get; set; }
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO.Compression;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
@@ -18,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;
|
||||||
}
|
}
|
||||||
@@ -42,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);
|
||||||
@@ -120,6 +125,40 @@ namespace gaseous_server.Classes
|
|||||||
.Single(x => x.GetValue(null).Equals(value)),
|
.Single(x => x.GetValue(null).Equals(value)),
|
||||||
typeof(DescriptionAttribute)))?.Description ?? value.ToString();
|
typeof(DescriptionAttribute)))?.Description ?? value.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compression
|
||||||
|
public static byte[] Compress(byte[] data)
|
||||||
|
{
|
||||||
|
MemoryStream output = new MemoryStream();
|
||||||
|
using (DeflateStream dstream = new DeflateStream(output, CompressionLevel.Optimal))
|
||||||
|
{
|
||||||
|
dstream.Write(data, 0, data.Length);
|
||||||
|
}
|
||||||
|
return output.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] Decompress(byte[] data)
|
||||||
|
{
|
||||||
|
MemoryStream input = new MemoryStream(data);
|
||||||
|
MemoryStream output = new MemoryStream();
|
||||||
|
using (DeflateStream dstream = new DeflateStream(input, CompressionMode.Decompress))
|
||||||
|
{
|
||||||
|
dstream.CopyTo(output);
|
||||||
|
}
|
||||||
|
return output.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object GetEnvVar(string envName, string defaultValue)
|
||||||
|
{
|
||||||
|
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable(envName)))
|
||||||
|
{
|
||||||
|
return Environment.GetEnvironmentVariable(envName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -3,6 +3,7 @@ using System.Data;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
|
using NuGet.Common;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
@@ -79,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;
|
||||||
@@ -117,11 +119,33 @@ namespace gaseous_server.Classes
|
|||||||
if (_tempConfig != null)
|
if (_tempConfig != null)
|
||||||
{
|
{
|
||||||
_config = _tempConfig;
|
_config = _tempConfig;
|
||||||
} else
|
|
||||||
|
// load environment variables if we're in a docker container
|
||||||
|
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("INDOCKER")))
|
||||||
|
{
|
||||||
|
if (Environment.GetEnvironmentVariable("INDOCKER") == "1")
|
||||||
|
{
|
||||||
|
Console.WriteLine("Running in Docker - setting configuration from variables");
|
||||||
|
_config.DatabaseConfiguration.HostName = (string)Common.GetEnvVar("dbhost", _config.DatabaseConfiguration.HostName);
|
||||||
|
_config.DatabaseConfiguration.UserName = (string)Common.GetEnvVar("dbuser", _config.DatabaseConfiguration.UserName);
|
||||||
|
_config.DatabaseConfiguration.Password = (string)Common.GetEnvVar("dbpass", _config.DatabaseConfiguration.Password);
|
||||||
|
_config.DatabaseConfiguration.DatabaseName = (string)Common.GetEnvVar("dbname", _config.DatabaseConfiguration.DatabaseName);
|
||||||
|
_config.DatabaseConfiguration.Port = int.Parse((string)Common.GetEnvVar("dbport", _config.DatabaseConfiguration.Port.ToString()));
|
||||||
|
_config.MetadataConfiguration.MetadataSource = (HasheousClient.Models.MetadataModel.MetadataSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.MetadataSources), (string)Common.GetEnvVar("metadatasource", _config.MetadataConfiguration.MetadataSource.ToString()));
|
||||||
|
_config.MetadataConfiguration.SignatureSource = (HasheousClient.Models.MetadataModel.SignatureSources)Enum.Parse(typeof(HasheousClient.Models.MetadataModel.SignatureSources), (string)Common.GetEnvVar("signaturesource", _config.MetadataConfiguration.SignatureSource.ToString())); ;
|
||||||
|
_config.MetadataConfiguration.MaxLibraryScanWorkers = int.Parse((string)Common.GetEnvVar("maxlibraryscanworkers", _config.MetadataConfiguration.MaxLibraryScanWorkers.ToString()));
|
||||||
|
_config.MetadataConfiguration.HasheousHost = (string)Common.GetEnvVar("hasheoushost", _config.MetadataConfiguration.HasheousHost);
|
||||||
|
_config.IGDBConfiguration.ClientId = (string)Common.GetEnvVar("igdbclientid", _config.IGDBConfiguration.ClientId);
|
||||||
|
_config.IGDBConfiguration.Secret = (string)Common.GetEnvVar("igdbclientsecret", _config.IGDBConfiguration.Secret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
throw new Exception("There was an error reading the config file: Json returned null");
|
throw new Exception("There was an error reading the config file: Json returned null");
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// no config file!
|
// no config file!
|
||||||
// use defaults and save
|
// use defaults and save
|
||||||
@@ -161,7 +185,7 @@ namespace gaseous_server.Classes
|
|||||||
File.WriteAllText(ConfigurationFilePath, configRaw);
|
File.WriteAllText(ConfigurationFilePath, configRaw);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<string, string> AppSettings = new Dictionary<string, string>();
|
private static Dictionary<string, object> AppSettings = new Dictionary<string, object>();
|
||||||
|
|
||||||
public static void InitSettings()
|
public static void InitSettings()
|
||||||
{
|
{
|
||||||
@@ -171,45 +195,127 @@ namespace gaseous_server.Classes
|
|||||||
DataTable dbResponse = db.ExecuteCMD(sql);
|
DataTable dbResponse = db.ExecuteCMD(sql);
|
||||||
foreach (DataRow dataRow in dbResponse.Rows)
|
foreach (DataRow dataRow in dbResponse.Rows)
|
||||||
{
|
{
|
||||||
if (AppSettings.ContainsKey((string)dataRow["Setting"]))
|
string SettingName = (string)dataRow["Setting"];
|
||||||
|
|
||||||
|
if (SettingName.StartsWith("LastRun_"))
|
||||||
{
|
{
|
||||||
AppSettings[(string)dataRow["Setting"]] = (string)dataRow["Value"];
|
Console.WriteLine("Break");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AppSettings.ContainsKey(SettingName))
|
||||||
|
{
|
||||||
|
AppSettings.Remove(SettingName);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Load Settings", "Loading setting " + SettingName + " from database");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Database.schema_version >= 1016)
|
||||||
|
{
|
||||||
|
switch ((int)dataRow["ValueType"])
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
// value is a string
|
||||||
|
AppSettings.Add(SettingName, dataRow["Value"]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// value is a datetime
|
||||||
|
AppSettings.Add(SettingName, dataRow["ValueDate"]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AppSettings.Add((string)dataRow["Setting"], (string)dataRow["Value"]);
|
AppSettings.Add(SettingName, dataRow["Value"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InvalidCastException castEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Settings", "Exception when reading server setting " + SettingName + ". Resetting to default.", castEx);
|
||||||
|
|
||||||
|
// delete broken setting and return the default
|
||||||
|
// this error is probably generated during an upgrade
|
||||||
|
sql = "DELETE FROM Settings WHERE Setting = @SettingName";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "SettingName", SettingName }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Critical, "Settings", "Exception when reading server setting " + SettingName + ".", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ReadSetting(string SettingName, string DefaultValue)
|
public static T ReadSetting<T>(string SettingName, T DefaultValue)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (AppSettings.ContainsKey(SettingName))
|
if (AppSettings.ContainsKey(SettingName))
|
||||||
{
|
{
|
||||||
return AppSettings[SettingName];
|
return (T)AppSettings[SettingName];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
string sql;
|
||||||
string sql = "SELECT Value FROM Settings WHERE Setting = @SettingName";
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
{
|
||||||
dbDict.Add("SettingName", SettingName);
|
{ "SettingName", SettingName }
|
||||||
dbDict.Add("Value", DefaultValue);
|
};
|
||||||
|
DataTable dbResponse;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Reading setting '" + SettingName + "'");
|
Logging.Log(Logging.LogType.Debug, "Database", "Reading setting '" + SettingName + "'");
|
||||||
DataTable dbResponse = db.ExecuteCMD(sql, dbDict);
|
|
||||||
|
if (Database.schema_version >= 1016)
|
||||||
|
{
|
||||||
|
sql = "SELECT Value, ValueDate FROM Settings WHERE Setting = @SettingName";
|
||||||
|
|
||||||
|
dbResponse = db.ExecuteCMD(sql, dbDict);
|
||||||
|
Type type = typeof(T);
|
||||||
if (dbResponse.Rows.Count == 0)
|
if (dbResponse.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
// no value with that name stored - respond with the default value
|
// no value with that name stored - respond with the default value
|
||||||
SetSetting(SettingName, DefaultValue);
|
SetSetting<T>(SettingName, DefaultValue);
|
||||||
return DefaultValue;
|
return DefaultValue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AppSettings.Add(SettingName, (string)dbResponse.Rows[0][0]);
|
if (type.ToString() == "System.DateTime")
|
||||||
return (string)dbResponse.Rows[0][0];
|
{
|
||||||
|
AppSettings.Add(SettingName, (T)dbResponse.Rows[0]["ValueDate"]);
|
||||||
|
return (T)dbResponse.Rows[0]["ValueDate"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AppSettings.Add(SettingName, (T)dbResponse.Rows[0]["Value"]);
|
||||||
|
return (T)dbResponse.Rows[0]["Value"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sql = "SELECT Value FROM Settings WHERE Setting = @SettingName";
|
||||||
|
|
||||||
|
dbResponse = db.ExecuteCMD(sql, dbDict);
|
||||||
|
Type type = typeof(T);
|
||||||
|
if (dbResponse.Rows.Count == 0)
|
||||||
|
{
|
||||||
|
// no value with that name stored - respond with the default value
|
||||||
|
SetSetting<T>(SettingName, DefaultValue);
|
||||||
|
return DefaultValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AppSettings.Add(SettingName, (T)dbResponse.Rows[0]["Value"]);
|
||||||
|
return (T)dbResponse.Rows[0]["Value"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -219,14 +325,85 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (InvalidCastException castEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Settings", "Exception when reading server setting " + SettingName + ". Resetting to default.", castEx);
|
||||||
|
|
||||||
public static void SetSetting(string SettingName, string Value)
|
// delete broken setting and return the default
|
||||||
|
// this error is probably generated during an upgrade
|
||||||
|
if (AppSettings.ContainsKey(SettingName))
|
||||||
|
{
|
||||||
|
AppSettings.Remove(SettingName);
|
||||||
|
}
|
||||||
|
|
||||||
|
string sql = "DELETE FROM Settings WHERE Setting = @SettingName";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "SettingName", SettingName }
|
||||||
|
};
|
||||||
|
|
||||||
|
return DefaultValue;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Critical, "Settings", "Exception when reading server setting " + SettingName + ".", ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetSetting<T>(string SettingName, T Value)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "REPLACE INTO Settings (Setting, Value) VALUES (@SettingName, @Value)";
|
string sql;
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict;
|
||||||
dbDict.Add("SettingName", SettingName);
|
|
||||||
dbDict.Add("Value", Value);
|
if (Database.schema_version >= 1016)
|
||||||
|
{
|
||||||
|
sql = "REPLACE INTO Settings (Setting, ValueType, Value, ValueDate) VALUES (@SettingName, @ValueType, @Value, @ValueDate)";
|
||||||
|
Type type = typeof(T);
|
||||||
|
|
||||||
|
switch (type.ToString())
|
||||||
|
{
|
||||||
|
case "System.DateTime":
|
||||||
|
dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "SettingName", SettingName },
|
||||||
|
{ "ValueType", 1 },
|
||||||
|
{ "Value", null },
|
||||||
|
{ "ValueDate", Value }
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "System.Collections.Generic.List`1[gaseous_server.Classes.Metadata.Games+SearchType]":
|
||||||
|
dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "SettingName", SettingName },
|
||||||
|
{ "ValueType", 2 },
|
||||||
|
{ "Value", JsonConvert.SerializeObject(Value) },
|
||||||
|
{ "ValueDate", null }
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "SettingName", SettingName },
|
||||||
|
{ "ValueType", 0 },
|
||||||
|
{ "Value", Value },
|
||||||
|
{ "ValueDate", null }
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sql = "REPLACE INTO Settings (Setting, Value) VALUES (@SettingName, @Value)";
|
||||||
|
dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "SettingName", SettingName },
|
||||||
|
{ "Value", Value }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Debug, "Database", "Storing setting '" + SettingName + "' to value: '" + Value + "'");
|
Logging.Log(Logging.LogType.Debug, "Database", "Storing setting '" + SettingName + "' to value: '" + Value + "'");
|
||||||
try
|
try
|
||||||
@@ -264,7 +441,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")))
|
||||||
@@ -308,11 +486,41 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string _DefaultDatabaseName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("dbname")))
|
||||||
|
{
|
||||||
|
return Environment.GetEnvironmentVariable("dbname");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "gaseous";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int _DefaultDatabasePort
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("dbport")))
|
||||||
|
{
|
||||||
|
return int.Parse(Environment.GetEnvironmentVariable("dbport"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 3306;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string HostName = _DefaultHostName;
|
public string HostName = _DefaultHostName;
|
||||||
public string UserName = _DefaultUserName;
|
public string UserName = _DefaultUserName;
|
||||||
public string Password = _DefaultPassword;
|
public string Password = _DefaultPassword;
|
||||||
public string DatabaseName = "gaseous";
|
public string DatabaseName = _DefaultDatabaseName;
|
||||||
public int Port = 3306;
|
public int Port = _DefaultDatabasePort;
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string ConnectionString
|
public string ConnectionString
|
||||||
@@ -341,11 +549,11 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return ReadSetting("LibraryRootDirectory", Path.Combine(Config.ConfigurationPath, "Data"));
|
return ReadSetting<string>("LibraryRootDirectory", Path.Combine(Config.ConfigurationPath, "Data"));
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SetSetting("LibraryRootDirectory", value);
|
SetSetting<string>("LibraryRootDirectory", value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,18 +714,25 @@ namespace gaseous_server.Classes
|
|||||||
private static int _MaxLibraryScanWorkers
|
private static int _MaxLibraryScanWorkers
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
{
|
||||||
|
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("maxlibraryscanworkers")))
|
||||||
|
{
|
||||||
|
return int.Parse(Environment.GetEnvironmentVariable("maxlibraryscanworkers"));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string _HasheousHost
|
private static string _HasheousHost
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("hasheoushoust")))
|
if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("hasheoushost")))
|
||||||
{
|
{
|
||||||
return Environment.GetEnvironmentVariable("hasheoushoust");
|
return Environment.GetEnvironmentVariable("hasheoushost");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -9,6 +9,21 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
public class Database
|
public class Database
|
||||||
{
|
{
|
||||||
|
private static int _schema_version { get; set; } = 0;
|
||||||
|
public static int schema_version
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
//Logging.Log(Logging.LogType.Information, "Database Schema", "Schema version is " + _schema_version);
|
||||||
|
return _schema_version;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
//Logging.Log(Logging.LogType.Information, "Database Schema", "Setting schema version " + _schema_version);
|
||||||
|
_schema_version = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Database()
|
public Database()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -78,7 +93,16 @@ namespace gaseous_server.Classes
|
|||||||
ExecuteCMD(sql, dbDict);
|
ExecuteCMD(sql, dbDict);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1000; i < 10000; i++)
|
sql = "SELECT schema_version FROM schema_version;";
|
||||||
|
dbDict = new Dictionary<string, object>();
|
||||||
|
DataTable SchemaVersion = ExecuteCMD(sql, dbDict);
|
||||||
|
int OuterSchemaVer = (int)SchemaVersion.Rows[0][0];
|
||||||
|
if (OuterSchemaVer == 0)
|
||||||
|
{
|
||||||
|
OuterSchemaVer = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = OuterSchemaVer; i < 10000; i++)
|
||||||
{
|
{
|
||||||
string resourceName = "gaseous_server.Support.Database.MySQL.gaseous-" + i + ".sql";
|
string resourceName = "gaseous_server.Support.Database.MySQL.gaseous-" + i + ".sql";
|
||||||
string dbScript = "";
|
string dbScript = "";
|
||||||
@@ -94,7 +118,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>();
|
||||||
DataTable SchemaVersion = ExecuteCMD(sql, dbDict);
|
SchemaVersion = ExecuteCMD(sql, dbDict);
|
||||||
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?
|
||||||
@@ -105,6 +129,8 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
int SchemaVer = (int)SchemaVersion.Rows[0][0];
|
int SchemaVer = (int)SchemaVersion.Rows[0][0];
|
||||||
Logging.Log(Logging.LogType.Information, "Database", "Schema version is " + SchemaVer);
|
Logging.Log(Logging.LogType.Information, "Database", "Schema version is " + SchemaVer);
|
||||||
|
// update schema version variable
|
||||||
|
Database.schema_version = SchemaVer;
|
||||||
if (SchemaVer < i)
|
if (SchemaVer < i)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -123,6 +149,9 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// run post-upgrade code
|
// run post-upgrade code
|
||||||
DatabaseMigration.PostUpgradeScript(i, _ConnectorType);
|
DatabaseMigration.PostUpgradeScript(i, _ConnectorType);
|
||||||
|
|
||||||
|
// update schema version variable
|
||||||
|
Database.schema_version = i;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
@@ -9,15 +10,66 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
public static void PreUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
public static void PreUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
||||||
{
|
{
|
||||||
|
// load resources
|
||||||
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
DataTable data;
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "Database", "Checking for pre-upgrade for schema version " + TargetSchemaVersion);
|
||||||
|
|
||||||
|
switch (DatabaseType)
|
||||||
|
{
|
||||||
|
case Database.databaseType.MySql:
|
||||||
|
switch (TargetSchemaVersion)
|
||||||
|
{
|
||||||
|
case 1005:
|
||||||
|
Logging.Log(Logging.LogType.Information, "Database", "Running pre-upgrade for schema version " + TargetSchemaVersion);
|
||||||
|
|
||||||
|
// there was a mistake at dbschema version 1004-1005
|
||||||
|
// the first preview release of v1.7 reused dbschema version 1004
|
||||||
|
// if table "Relation_Game_AgeRatings" exists - then we need to apply the gaseous-fix-1005.sql script before applying the standard 1005 script
|
||||||
|
sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = @dbname AND table_name = @tablename;";
|
||||||
|
dbDict.Add("dbname", Config.DatabaseConfiguration.DatabaseName);
|
||||||
|
dbDict.Add("tablename", "Relation_Game_AgeRatings");
|
||||||
|
data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
if (data.Rows.Count == 0)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Database", "Schema version " + TargetSchemaVersion + " requires a table which is missing.");
|
||||||
|
|
||||||
|
string resourceName = "gaseous_server.Support.Database.MySQL.gaseous-fix-1005.sql";
|
||||||
|
string dbScript = "";
|
||||||
|
|
||||||
|
string[] resources = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
||||||
|
if (resources.Contains(resourceName))
|
||||||
|
{
|
||||||
|
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
|
||||||
|
using (StreamReader reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
dbScript = reader.ReadToEnd();
|
||||||
|
|
||||||
|
// apply schema!
|
||||||
|
Logging.Log(Logging.LogType.Information, "Database", "Applying schema version fix prior to version 1005");
|
||||||
|
db.ExecuteCMD(dbScript, dbDict, 180);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PostUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
public static void PostUpgradeScript(int TargetSchemaVersion, Database.databaseType? DatabaseType)
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
DataTable data;
|
||||||
|
|
||||||
switch(DatabaseType)
|
switch (DatabaseType)
|
||||||
{
|
{
|
||||||
case Database.databaseType.MySql:
|
case Database.databaseType.MySql:
|
||||||
switch (TargetSchemaVersion)
|
switch (TargetSchemaVersion)
|
||||||
@@ -32,12 +84,12 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
// copy root path to new libraries format
|
// copy root path to new libraries format
|
||||||
string oldRoot = Path.Combine(Config.LibraryConfiguration.LibraryRootDirectory, "Library");
|
string oldRoot = Path.Combine(Config.LibraryConfiguration.LibraryRootDirectory, "Library");
|
||||||
string sql = "INSERT INTO GameLibraries (Name, Path, DefaultLibrary, DefaultPlatform) VALUES (@name, @path, @defaultlibrary, @defaultplatform); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
sql = "INSERT INTO GameLibraries (Name, Path, DefaultLibrary, DefaultPlatform) VALUES (@name, @path, @defaultlibrary, @defaultplatform); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||||
dbDict.Add("name", "Default");
|
dbDict.Add("name", "Default");
|
||||||
dbDict.Add("path", oldRoot);
|
dbDict.Add("path", oldRoot);
|
||||||
dbDict.Add("defaultlibrary", 1);
|
dbDict.Add("defaultlibrary", 1);
|
||||||
dbDict.Add("defaultplatform", 0);
|
dbDict.Add("defaultplatform", 0);
|
||||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
// apply the new library id to the existing roms
|
// apply the new library id to the existing roms
|
||||||
sql = "UPDATE Games_Roms SET LibraryId=@libraryid;";
|
sql = "UPDATE Games_Roms SET LibraryId=@libraryid;";
|
||||||
@@ -46,6 +98,11 @@ namespace gaseous_server.Classes
|
|||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 1016:
|
||||||
|
// delete old format LastRun_* settings from settings table
|
||||||
|
sql = "DELETE FROM Settings WHERE Setting LIKE 'LastRun_%';";
|
||||||
|
db.ExecuteNonQuery(sql);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -64,7 +121,8 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MySql_1002_MigrateMetadataVersion() {
|
public static void MySql_1002_MigrateMetadataVersion()
|
||||||
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
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>();
|
||||||
|
58
gaseous-server/Classes/Favourites.cs
Normal file
58
gaseous-server/Classes/Favourites.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using IGDB.Models;
|
||||||
|
|
||||||
|
namespace gaseous_server.Classes
|
||||||
|
{
|
||||||
|
public class Favourites
|
||||||
|
{
|
||||||
|
public bool GetFavourite(string userid, long GameId)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT * FROM Favourites WHERE UserId=@userid AND GameId=@gameid";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||||
|
{ "userid", userid },
|
||||||
|
{ "gameid", GameId}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (db.ExecuteCMD(sql, dbDict).Rows.Count > 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetFavourite(string userid, long GameId, bool Favourite)
|
||||||
|
{
|
||||||
|
bool CurrentFavourite = GetFavourite(userid, GameId);
|
||||||
|
if (CurrentFavourite == Favourite)
|
||||||
|
{
|
||||||
|
return Favourite;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql;
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||||
|
{ "userid", userid },
|
||||||
|
{ "gameid", GameId}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (CurrentFavourite == true)
|
||||||
|
{
|
||||||
|
// delete existing value
|
||||||
|
sql = "DELETE FROM Favourites WHERE UserId=@userid AND GameId=@gameid";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// insert new value
|
||||||
|
sql = "INSERT INTO Favourites (UserId, GameId) VALUES (@userid, @gameid)";
|
||||||
|
}
|
||||||
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
|
||||||
|
return Favourite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -31,7 +31,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");
|
||||||
@@ -121,7 +121,8 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
if (zfi != null)
|
if (zfi != null)
|
||||||
{
|
{
|
||||||
ArchiveData archiveData = new ArchiveData{
|
ArchiveData archiveData = new ArchiveData
|
||||||
|
{
|
||||||
FileName = Path.GetFileName(file),
|
FileName = Path.GetFileName(file),
|
||||||
FilePath = zfi.Directory.FullName.Replace(ExtractPath, ""),
|
FilePath = zfi.Directory.FullName.Replace(ExtractPath, ""),
|
||||||
Size = zfi.Length,
|
Size = zfi.Length,
|
||||||
@@ -264,7 +265,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{
|
SignatureLookupItem? HasheousResult = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HasheousResult = hasheous.RetrieveFromHasheousAsync(new HashLookupModel
|
||||||
|
{
|
||||||
MD5 = hash.md5hash,
|
MD5 = hash.md5hash,
|
||||||
SHA1 = hash.sha1hash
|
SHA1 = hash.sha1hash
|
||||||
});
|
});
|
||||||
@@ -296,6 +302,11 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Get Signature", "Error retrieving signature from Hasheous", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
@@ -180,7 +181,13 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Import Game", " Searching for title: " + SearchCandidate);
|
Logging.Log(Logging.LogType.Information, "Import Game", " Searching for title: " + SearchCandidate);
|
||||||
|
|
||||||
foreach (Metadata.Games.SearchType searchType in Enum.GetValues(typeof(Metadata.Games.SearchType)))
|
List<Metadata.Games.SearchType> allowedSearchTypes = Config.ReadSetting<List<Metadata.Games.SearchType>>("DefaultSearchMethods", new List<gaseous_server.Classes.Metadata.Games.SearchType>() {
|
||||||
|
Games.SearchType.where,
|
||||||
|
Games.SearchType.wherefuzzy,
|
||||||
|
Games.SearchType.search,
|
||||||
|
Games.SearchType.searchNoPlatform
|
||||||
|
});
|
||||||
|
foreach (Metadata.Games.SearchType searchType in allowedSearchTypes)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Import Game", " Search type: " + searchType.ToString());
|
Logging.Log(Logging.LogType.Information, "Import Game", " Search type: " + searchType.ToString());
|
||||||
IGDB.Models.Game[] games = Metadata.Games.SearchForGame(SearchCandidate, PlatformId, searchType);
|
IGDB.Models.Game[] games = Metadata.Games.SearchForGame(SearchCandidate, PlatformId, searchType);
|
||||||
@@ -197,8 +204,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!");
|
||||||
@@ -236,7 +245,13 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
foreach (string SearchCandidate in SearchCandidates)
|
foreach (string SearchCandidate in SearchCandidates)
|
||||||
{
|
{
|
||||||
foreach (Metadata.Games.SearchType searchType in Enum.GetValues(typeof(Metadata.Games.SearchType)))
|
List<Metadata.Games.SearchType> allowedSearchTypes = Config.ReadSetting<List<Metadata.Games.SearchType>>("DefaultSearchMethods", new List<gaseous_server.Classes.Metadata.Games.SearchType>() {
|
||||||
|
Games.SearchType.where,
|
||||||
|
Games.SearchType.wherefuzzy,
|
||||||
|
Games.SearchType.search,
|
||||||
|
Games.SearchType.searchNoPlatform
|
||||||
|
});
|
||||||
|
foreach (Metadata.Games.SearchType searchType in allowedSearchTypes)
|
||||||
{
|
{
|
||||||
if ((PlatformId == 0 && searchType == SearchType.searchNoPlatform) || (PlatformId != 0 && searchType != SearchType.searchNoPlatform))
|
if ((PlatformId == 0 && searchType == SearchType.searchNoPlatform) || (PlatformId != 0 && searchType != SearchType.searchNoPlatform))
|
||||||
{
|
{
|
||||||
@@ -273,7 +288,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +321,8 @@ 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) VALUES (@platformid, @gameid, @name, @size, @crc, @md5, @sha1, @developmentstatus, @Attributes, @romtype, @romtypemedia, @medialabel, @path, @metadatasource, @metadatagamename, @metadataversion, @libraryid); SELECT CAST(LAST_INSERT_ID() AS SIGNED);";
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
sql = "UPDATE Games_Roms SET PlatformId=@platformid, GameId=@gameid, Name=@name, Size=@size, DevelopmentStatus=@developmentstatus, Attributes=@Attributes, RomType=@romtype, RomTypeMedia=@romtypemedia, MediaLabel=@medialabel, MetadataSource=@metadatasource, MetadataGameName=@metadatagamename, MetadataVersion=@metadataversion WHERE Id=@id;";
|
sql = "UPDATE Games_Roms SET PlatformId=@platformid, GameId=@gameid, Name=@name, Size=@size, DevelopmentStatus=@developmentstatus, Attributes=@Attributes, RomType=@romtype, RomTypeMedia=@romtypemedia, MediaLabel=@medialabel, MetadataSource=@metadatasource, MetadataGameName=@metadatagamename, MetadataVersion=@metadataversion WHERE Id=@id;";
|
||||||
dbDict.Add("id", UpdateId);
|
dbDict.Add("id", UpdateId);
|
||||||
@@ -348,7 +365,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;
|
||||||
}
|
}
|
||||||
@@ -452,13 +470,15 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
if (romDT.Rows.Count > 0)
|
if (romDT.Rows.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (DataRow dr in romDT.Rows)
|
for (int i = 0; i < romDT.Rows.Count; i++)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Organise Library", "Processing ROM " + dr["name"]);
|
SetStatus(i, romDT.Rows.Count, "Processing file " + romDT.Rows[i]["name"]);
|
||||||
long RomId = (long)dr["id"];
|
Logging.Log(Logging.LogType.Information, "Organise Library", "(" + i + "/" + romDT.Rows.Count + ") Processing ROM " + romDT.Rows[i]["name"]);
|
||||||
|
long RomId = (long)romDT.Rows[i]["id"];
|
||||||
MoveGameFile(RomId);
|
MoveGameFile(RomId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ClearStatus();
|
||||||
|
|
||||||
// clean up empty directories
|
// clean up empty directories
|
||||||
DeleteOrphanedDirectories(GameLibrary.GetDefaultLibrary.Path);
|
DeleteOrphanedDirectories(GameLibrary.GetDefaultLibrary.Path);
|
||||||
@@ -643,7 +663,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;
|
||||||
@@ -769,7 +789,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;
|
||||||
|
@@ -9,13 +9,14 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
const int MaxFileAge = 30;
|
const int MaxFileAge = 30;
|
||||||
|
|
||||||
public void RunMaintenance()
|
public void RunDailyMaintenance()
|
||||||
{
|
{
|
||||||
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>();
|
||||||
|
|
||||||
// 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,27 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete old logs
|
// delete old logs
|
||||||
sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRententionDate;";
|
Logging.Log(Logging.LogType.Information, "Maintenance", "Removing logs older than " + Config.LoggingConfiguration.LogRetention + " days");
|
||||||
dbDict.Add("EventRententionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
|
long deletedCount = 1;
|
||||||
db.ExecuteCMD(sql, dbDict);
|
long deletedEventCount = 0;
|
||||||
|
long maxLoops = 1000;
|
||||||
|
sql = "DELETE FROM ServerLogs WHERE EventTime < @EventRetentionDate LIMIT 1000; SELECT ROW_COUNT() AS Count;";
|
||||||
|
dbDict.Add("EventRetentionDate", DateTime.UtcNow.AddDays(Config.LoggingConfiguration.LogRetention * -1));
|
||||||
|
while (deletedCount > 0)
|
||||||
|
{
|
||||||
|
DataTable deletedCountTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
deletedCount = (long)deletedCountTable.Rows[0][0];
|
||||||
|
deletedEventCount += deletedCount;
|
||||||
|
|
||||||
|
// 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>();
|
||||||
@@ -69,6 +88,13 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RunWeeklyMaintenance()
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Maintenance", "Optimising database tables");
|
Logging.Log(Logging.LogType.Information, "Maintenance", "Optimising database tables");
|
||||||
sql = "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE';";
|
sql = "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE';";
|
||||||
@@ -80,7 +106,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 = "";
|
||||||
|
@@ -72,32 +72,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compile the ratings values into the ratings groups
|
// compile the ratings values into the ratings groups
|
||||||
AgeRestrictionGroupings highestAgeGroup = AgeRestrictionGroupings.Unclassified;
|
AgeRestrictionGroupings highestAgeGroup = GetAgeGroupFromAgeRatings(ageRatings);
|
||||||
foreach (AgeRating ageRating in ageRatings)
|
|
||||||
{
|
|
||||||
foreach (KeyValuePair<AgeRestrictionGroupings, AgeGroupItem> ageGroupItem in AgeGroupingsFlat)
|
|
||||||
{
|
|
||||||
|
|
||||||
PropertyInfo[] groupProps = typeof(AgeGroupItem).GetProperties();
|
|
||||||
foreach (PropertyInfo property in groupProps)
|
|
||||||
{
|
|
||||||
if (RatingsBoards.Contains(property.Name))
|
|
||||||
{
|
|
||||||
List<AgeRatingTitle> ratingBoard = (List<AgeRatingTitle>)property.GetValue(ageGroupItem.Value);
|
|
||||||
foreach (AgeRatingTitle ratingTitle in ratingBoard)
|
|
||||||
{
|
|
||||||
if (ageRating.Rating == ratingTitle)
|
|
||||||
{
|
|
||||||
if (highestAgeGroup < ageGroupItem.Key)
|
|
||||||
{
|
|
||||||
highestAgeGroup = ageGroupItem.Key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the compiled ratings group
|
// return the compiled ratings group
|
||||||
AgeGroup ageGroup = new AgeGroup();
|
AgeGroup ageGroup = new AgeGroup();
|
||||||
@@ -138,6 +113,39 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AgeRestrictionGroupings GetAgeGroupFromAgeRatings(List<AgeRating> ageRatings)
|
||||||
|
{
|
||||||
|
// compile the ratings values into the ratings groups
|
||||||
|
AgeRestrictionGroupings highestAgeGroup = AgeRestrictionGroupings.Unclassified;
|
||||||
|
foreach (AgeRating ageRating in ageRatings)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<AgeRestrictionGroupings, AgeGroupItem> ageGroupItem in AgeGroupingsFlat)
|
||||||
|
{
|
||||||
|
|
||||||
|
PropertyInfo[] groupProps = typeof(AgeGroupItem).GetProperties();
|
||||||
|
foreach (PropertyInfo property in groupProps)
|
||||||
|
{
|
||||||
|
if (RatingsBoards.Contains(property.Name))
|
||||||
|
{
|
||||||
|
List<AgeRatingTitle> ratingBoard = (List<AgeRatingTitle>)property.GetValue(ageGroupItem.Value);
|
||||||
|
foreach (AgeRatingTitle ratingTitle in ratingBoard)
|
||||||
|
{
|
||||||
|
if (ageRating.Rating == ratingTitle)
|
||||||
|
{
|
||||||
|
if (highestAgeGroup < ageGroupItem.Key)
|
||||||
|
{
|
||||||
|
highestAgeGroup = ageGroupItem.Key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return highestAgeGroup;
|
||||||
|
}
|
||||||
|
|
||||||
public class AgeGroup
|
public class AgeGroup
|
||||||
{
|
{
|
||||||
public long? Id { get; set; }
|
public long? Id { get; set; }
|
||||||
|
@@ -7,7 +7,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
public class Collections
|
public class Collections
|
||||||
{
|
{
|
||||||
const string fieldList = "fields checksum,created_at,games,name,slug,updated_at,url;";
|
const string fieldList = "fields as_child_relations,as_parent_relations,checksum,created_at,games,name,slug,type,updated_at,url;";
|
||||||
|
|
||||||
public Collections()
|
public Collections()
|
||||||
{
|
{
|
||||||
|
@@ -224,6 +224,22 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
return await IGDBAPI<T>(Endpoint, Fields, Query);
|
return await IGDBAPI<T>(Endpoint, Fields, Query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case HttpStatusCode.Unauthorized:
|
||||||
|
Logging.Log(Logging.LogType.Information, "API Connection", "IGDB API unauthorised error while accessing endpoint " + Endpoint + ". Waiting " + RateLimitAvoidanceWait + " milliseconds and resetting IGDB client.", apiEx);
|
||||||
|
|
||||||
|
Thread.Sleep(RateLimitAvoidanceWait);
|
||||||
|
|
||||||
|
igdb = new IGDBClient(
|
||||||
|
// Found in Twitch Developer portal for your app
|
||||||
|
Config.IGDB.ClientId,
|
||||||
|
Config.IGDB.Secret
|
||||||
|
);
|
||||||
|
|
||||||
|
RetryAttempts += 1;
|
||||||
|
|
||||||
|
return await IGDBAPI<T>(Endpoint, Fields, Query);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Logging.Log(Logging.LogType.Warning, "API Connection", "Exception when accessing endpoint " + Endpoint, apiEx);
|
Logging.Log(Logging.LogType.Warning, "API Connection", "Exception when accessing endpoint " + Endpoint, apiEx);
|
||||||
throw;
|
throw;
|
||||||
|
@@ -9,7 +9,7 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
{
|
{
|
||||||
public class Covers
|
public class Covers
|
||||||
{
|
{
|
||||||
const string fieldList = "fields alpha_channel,animated,checksum,game,height,image_id,url,width;";
|
const string fieldList = "fields alpha_channel,animated,checksum,game,game_localization,height,image_id,url,width;";
|
||||||
|
|
||||||
public Covers()
|
public Covers()
|
||||||
{
|
{
|
||||||
|
@@ -7,7 +7,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,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 +17,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 +78,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 +112,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 +127,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 +441,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"], ""),
|
||||||
@@ -529,10 +532,16 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
|
|
||||||
public class MinimalGameItem
|
public class MinimalGameItem
|
||||||
{
|
{
|
||||||
|
public MinimalGameItem()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public MinimalGameItem(Game gameObject)
|
public MinimalGameItem(Game gameObject)
|
||||||
{
|
{
|
||||||
this.Id = gameObject.Id;
|
this.Id = gameObject.Id;
|
||||||
this.Name = gameObject.Name;
|
this.Name = gameObject.Name;
|
||||||
|
this.Slug = gameObject.Slug;
|
||||||
this.TotalRating = gameObject.TotalRating;
|
this.TotalRating = gameObject.TotalRating;
|
||||||
this.TotalRatingCount = gameObject.TotalRatingCount;
|
this.TotalRatingCount = gameObject.TotalRatingCount;
|
||||||
this.Cover = gameObject.Cover;
|
this.Cover = gameObject.Cover;
|
||||||
@@ -555,9 +564,13 @@ namespace gaseous_server.Classes.Metadata
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long? Id { get; set; }
|
public long? Id { get; set; }
|
||||||
|
public long Index { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
public string Slug { 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 IsFavourite { get; set; } = false;
|
||||||
public DateTimeOffset? FirstReleaseDate { get; set; }
|
public DateTimeOffset? FirstReleaseDate { get; set; }
|
||||||
public IGDB.IdentityOrValue<IGDB.Models.Cover> Cover { get; set; }
|
public IGDB.IdentityOrValue<IGDB.Models.Cover> Cover { get; set; }
|
||||||
public IGDB.IdentitiesOrValues<IGDB.Models.Artwork> Artworks { get; set; }
|
public IGDB.IdentitiesOrValues<IGDB.Models.Artwork> Artworks { get; set; }
|
||||||
|
@@ -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)
|
||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@@ -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; }
|
||||||
|
@@ -5,6 +5,9 @@ using Microsoft.VisualBasic;
|
|||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using SharpCompress.Archives;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
using gaseous_server.Models;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
{
|
{
|
||||||
@@ -55,12 +58,15 @@ namespace gaseous_server.Classes
|
|||||||
return GetMediaGroup(mgId);
|
return GetMediaGroup(mgId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameRomMediaGroupItem GetMediaGroup(long Id)
|
public static GameRomMediaGroupItem GetMediaGroup(long Id, string userid = "")
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM RomMediaGroup WHERE Id=@id;";
|
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.Id=@id;";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
dbDict.Add("id", Id);
|
{
|
||||||
|
{ "id", Id },
|
||||||
|
{ "userid", userid }
|
||||||
|
};
|
||||||
|
|
||||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
@@ -75,12 +81,15 @@ namespace gaseous_server.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<GameRomMediaGroupItem> GetMediaGroupsFromGameId(long GameId)
|
public static List<GameRomMediaGroupItem> GetMediaGroupsFromGameId(long GameId, string userid = "")
|
||||||
{
|
{
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
string sql = "SELECT * FROM RomMediaGroup WHERE GameId=@gameid;";
|
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;";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
dbDict.Add("gameid", GameId);
|
{
|
||||||
|
{ "gameid", GameId },
|
||||||
|
{ "userid", userid }
|
||||||
|
};
|
||||||
|
|
||||||
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
DataTable dataTable = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
@@ -156,7 +165,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;";
|
string sql = "DELETE FROM RomMediaGroup WHERE Id=@id; DELETE FROM GameState 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);
|
||||||
@@ -170,6 +179,15 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
internal static GameRomMediaGroupItem BuildMediaGroupFromRow(DataRow row)
|
internal static GameRomMediaGroupItem BuildMediaGroupFromRow(DataRow row)
|
||||||
{
|
{
|
||||||
|
bool hasSaveStates = false;
|
||||||
|
if (row.Table.Columns.Contains("GameStateRomId"))
|
||||||
|
{
|
||||||
|
if (row["GameStateRomId"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
hasSaveStates = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem();
|
GameRomMediaGroupItem mediaGroupItem = new GameRomMediaGroupItem();
|
||||||
mediaGroupItem.Id = (long)row["Id"];
|
mediaGroupItem.Id = (long)row["Id"];
|
||||||
mediaGroupItem.Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"];
|
mediaGroupItem.Status = (GameRomMediaGroupItem.GroupBuildStatus)row["Status"];
|
||||||
@@ -177,6 +195,7 @@ namespace gaseous_server.Classes
|
|||||||
mediaGroupItem.GameId = (long)row["GameId"];
|
mediaGroupItem.GameId = (long)row["GameId"];
|
||||||
mediaGroupItem.RomIds = new List<long>();
|
mediaGroupItem.RomIds = new List<long>();
|
||||||
mediaGroupItem.Roms = new List<Roms.GameRomItem>();
|
mediaGroupItem.Roms = new List<Roms.GameRomItem>();
|
||||||
|
mediaGroupItem.HasSaveStates = hasSaveStates;
|
||||||
|
|
||||||
// get members
|
// get members
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
@@ -243,6 +262,7 @@ namespace gaseous_server.Classes
|
|||||||
{
|
{
|
||||||
Game GameObject = Games.GetGame(mediaGroupItem.GameId, false, false, false);
|
Game GameObject = Games.GetGame(mediaGroupItem.GameId, false, false, false);
|
||||||
Platform PlatformObject = Platforms.GetPlatform(mediaGroupItem.PlatformId, false);
|
Platform PlatformObject = Platforms.GetPlatform(mediaGroupItem.PlatformId, false);
|
||||||
|
PlatformMapping.PlatformMapItem platformMapItem = PlatformMapping.GetPlatformMap(mediaGroupItem.PlatformId);
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "Media Group", "Beginning build of media group: " + GameObject.Name + " for platform " + PlatformObject.Name);
|
Logging.Log(Logging.LogType.Information, "Media Group", "Beginning build of media group: " + GameObject.Name + " for platform " + PlatformObject.Name);
|
||||||
|
|
||||||
@@ -277,10 +297,124 @@ namespace gaseous_server.Classes
|
|||||||
foreach (long RomId in mediaGroupItem.RomIds)
|
foreach (long RomId in mediaGroupItem.RomIds)
|
||||||
{
|
{
|
||||||
Roms.GameRomItem rom = Roms.GetRom(RomId);
|
Roms.GameRomItem rom = Roms.GetRom(RomId);
|
||||||
|
bool fileNameFound = false;
|
||||||
if (File.Exists(rom.Path))
|
if (File.Exists(rom.Path))
|
||||||
{
|
{
|
||||||
|
string romExt = Path.GetExtension(rom.Path);
|
||||||
|
if (new string[]{ ".zip", ".rar", ".7z" }.Contains(romExt))
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Media Group", "Decompressing ROM: " + rom.Name);
|
||||||
|
|
||||||
|
// is compressed
|
||||||
|
switch (romExt)
|
||||||
|
{
|
||||||
|
case ".zip":
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var archive = SharpCompress.Archives.Zip.ZipArchive.Open(rom.Path))
|
||||||
|
{
|
||||||
|
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key);
|
||||||
|
if (fileNameFound == false)
|
||||||
|
{
|
||||||
|
//check if extension is in valid extensions
|
||||||
|
if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
// update rom file name
|
||||||
|
rom.Name = entry.Key;
|
||||||
|
fileNameFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions()
|
||||||
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception zipEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Media Group", "Unzip error", zipEx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ".rar":
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var archive = SharpCompress.Archives.Rar.RarArchive.Open(rom.Path))
|
||||||
|
{
|
||||||
|
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key);
|
||||||
|
if (fileNameFound == false)
|
||||||
|
{
|
||||||
|
//check if extension is in valid extensions
|
||||||
|
if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
// update rom file name
|
||||||
|
rom.Name = entry.Key;
|
||||||
|
fileNameFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions()
|
||||||
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception zipEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Media Group", "Unrar error", zipEx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ".7z":
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var archive = SharpCompress.Archives.SevenZip.SevenZipArchive.Open(rom.Path))
|
||||||
|
{
|
||||||
|
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Media Group", "Extracting file: " + entry.Key);
|
||||||
|
if (fileNameFound == false)
|
||||||
|
{
|
||||||
|
//check if extension is in valid extensions
|
||||||
|
if (platformMapItem.Extensions.SupportedFileExtensions.Contains(Path.GetExtension(entry.Key), StringComparer.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
// update rom file name
|
||||||
|
rom.Name = entry.Key;
|
||||||
|
fileNameFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry.WriteToDirectory(ZipFileTempPath, new ExtractionOptions()
|
||||||
|
{
|
||||||
|
ExtractFullPath = true,
|
||||||
|
Overwrite = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception zipEx)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Media Group", "7z error", zipEx);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// is uncompressed
|
||||||
Logging.Log(Logging.LogType.Information, "Media Group", "Copying ROM: " + rom.Name);
|
Logging.Log(Logging.LogType.Information, "Media Group", "Copying ROM: " + rom.Name);
|
||||||
File.Copy(rom.Path, Path.Combine(ZipFileTempPath, Path.GetFileName(rom.Path)));
|
File.Copy(rom.Path, Path.Combine(ZipFileTempPath, Path.GetFileName(rom.Path)));
|
||||||
|
}
|
||||||
|
|
||||||
romItems.Add(rom);
|
romItems.Add(rom);
|
||||||
}
|
}
|
||||||
@@ -397,6 +531,7 @@ namespace gaseous_server.Classes
|
|||||||
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
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;
|
||||||
private GroupBuildStatus _Status { get; set; }
|
private GroupBuildStatus _Status { get; set; }
|
||||||
public GroupBuildStatus Status {
|
public GroupBuildStatus Status {
|
||||||
get
|
get
|
||||||
|
@@ -12,10 +12,16 @@ 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 static GameRomObject GetRoms(long GameId, long PlatformId = -1, string NameSearch = "", int pageNumber = 0, int pageSize = 0)
|
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 = "")
|
||||||
{
|
{
|
||||||
GameRomObject GameRoms = new GameRomObject();
|
GameRomObject GameRoms = new GameRomObject();
|
||||||
|
|
||||||
@@ -25,6 +31,7 @@ namespace gaseous_server.Classes
|
|||||||
string sqlPlatform = "";
|
string sqlPlatform = "";
|
||||||
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
dbDict.Add("id", GameId);
|
dbDict.Add("id", GameId);
|
||||||
|
dbDict.Add("userid", userid);
|
||||||
|
|
||||||
string NameSearchWhere = "";
|
string NameSearchWhere = "";
|
||||||
if (NameSearch.Length > 0)
|
if (NameSearch.Length > 0)
|
||||||
@@ -36,15 +43,18 @@ namespace gaseous_server.Classes
|
|||||||
// 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 Games_Roms.*, Platform.`Name` AS platformname FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id WHERE Games_Roms.GameId = @id" + NameSearchWhere + " ORDER BY Platform.`Name`, Games_Roms.`Name` LIMIT 1000;";
|
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;";
|
||||||
|
|
||||||
// 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 Games_Roms.*, Platform.`Name` AS platformname FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.Id 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, 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;";
|
||||||
|
|
||||||
// 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 + ";";
|
||||||
@@ -99,6 +109,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 FROM Games_Roms LEFT JOIN Platform ON Games_Roms.PlatformId = Platform.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
|
||||||
@@ -131,7 +161,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";
|
string sql = "DELETE FROM Games_Roms WHERE Id = @id; DELETE FROM GameState WHERE RomId = @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);
|
||||||
db.ExecuteCMD(sql, dbDict);
|
db.ExecuteCMD(sql, dbDict);
|
||||||
@@ -140,6 +170,15 @@ namespace gaseous_server.Classes
|
|||||||
|
|
||||||
private static GameRomItem BuildRom(DataRow romDR)
|
private static GameRomItem BuildRom(DataRow romDR)
|
||||||
{
|
{
|
||||||
|
bool hasSaveStates = false;
|
||||||
|
if (romDR.Table.Columns.Contains("SavedStateRomId"))
|
||||||
|
{
|
||||||
|
if (romDR["SavedStateRomId"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
hasSaveStates = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GameRomItem romItem = new GameRomItem
|
GameRomItem romItem = new GameRomItem
|
||||||
{
|
{
|
||||||
Id = (long)romDR["id"],
|
Id = (long)romDR["id"],
|
||||||
@@ -159,6 +198,7 @@ namespace gaseous_server.Classes
|
|||||||
Path = (string)romDR["path"],
|
Path = (string)romDR["path"],
|
||||||
SignatureSource = (gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType)(Int32)romDR["metadatasource"],
|
SignatureSource = (gaseous_server.Models.Signatures_Games.RomItem.SignatureSourceType)(Int32)romDR["metadatasource"],
|
||||||
SignatureSourceGameTitle = (string)Common.ReturnValueIfNull(romDR["MetadataGameName"], ""),
|
SignatureSourceGameTitle = (string)Common.ReturnValueIfNull(romDR["MetadataGameName"], ""),
|
||||||
|
HasSaveStates = hasSaveStates,
|
||||||
Library = GameLibrary.GetLibrary((int)romDR["LibraryId"])
|
Library = GameLibrary.GetLibrary((int)romDR["LibraryId"])
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -190,9 +230,9 @@ namespace gaseous_server.Classes
|
|||||||
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
public Models.PlatformMapping.PlatformMapItem.WebEmulatorItem? Emulator { get; set; }
|
||||||
public long GameId { get; set; }
|
public long GameId { 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 GameLibrary.LibraryItem Library { get; set; }
|
public GameLibrary.LibraryItem Library { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -194,7 +194,7 @@ namespace gaseous_server.SignatureIngestors.XML
|
|||||||
if (romObject.Md5 != null || romObject.Sha1 != null)
|
if (romObject.Md5 != null || romObject.Sha1 != null)
|
||||||
{
|
{
|
||||||
int romId = 0;
|
int romId = 0;
|
||||||
sql = "SELECT * FROM Signatures_Roms WHERE GameId=@gameid AND MD5=@md5";
|
sql = "SELECT * FROM Signatures_Roms WHERE `GameId`=@gameid AND (`MD5`=@md5 AND `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, ""));
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
|
using gaseous_server.Models;
|
||||||
using gaseous_signature_parser.models.RomSignatureObject;
|
using gaseous_signature_parser.models.RomSignatureObject;
|
||||||
|
|
||||||
namespace gaseous_server.Classes
|
namespace gaseous_server.Classes
|
||||||
@@ -10,7 +11,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 +23,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;
|
||||||
}
|
}
|
||||||
@@ -77,5 +80,46 @@ 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
99
gaseous-server/Classes/Statistics.cs
Normal file
99
gaseous-server/Classes/Statistics.cs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
using System.Data;
|
||||||
|
using gaseous_server.Models;
|
||||||
|
|
||||||
|
namespace gaseous_server.Classes
|
||||||
|
{
|
||||||
|
public class Statistics
|
||||||
|
{
|
||||||
|
public StatisticsModel RecordSession(Guid SessionId, long GameId, string UserId)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql;
|
||||||
|
Dictionary<string, object> dbDict;
|
||||||
|
|
||||||
|
if (SessionId == Guid.Empty)
|
||||||
|
{
|
||||||
|
// new session required
|
||||||
|
SessionId = Guid.NewGuid();
|
||||||
|
|
||||||
|
sql = "INSERT INTO UserTimeTracking (GameId, UserId, SessionId, SessionTime, SessionLength) VALUES (@gameid, @userid, @sessionid, @sessiontime, @sessionlength);";
|
||||||
|
dbDict = new Dictionary<string, object>{
|
||||||
|
{ "gameid", GameId },
|
||||||
|
{ "userid", UserId },
|
||||||
|
{ "sessionid", SessionId },
|
||||||
|
{ "sessiontime", DateTime.UtcNow },
|
||||||
|
{ "sessionlength", 1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
|
||||||
|
return new StatisticsModel{
|
||||||
|
GameId = GameId,
|
||||||
|
SessionId = SessionId,
|
||||||
|
SessionStart = (DateTime)dbDict["sessiontime"],
|
||||||
|
SessionLength = (int)dbDict["sessionlength"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// update existing session
|
||||||
|
sql = "UPDATE UserTimeTracking SET SessionLength = SessionLength + @sessionlength WHERE GameId = @gameid AND UserId = @userid AND SessionId = @sessionid;";
|
||||||
|
dbDict = new Dictionary<string, object>{
|
||||||
|
{ "gameid", GameId },
|
||||||
|
{ "userid", UserId },
|
||||||
|
{ "sessionid", SessionId },
|
||||||
|
{ "sessionlength", 1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
|
||||||
|
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid AND SessionId = @sessionid;";
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
return new StatisticsModel{
|
||||||
|
GameId = (long)data.Rows[0]["GameId"],
|
||||||
|
SessionId = Guid.Parse(data.Rows[0]["SessionId"].ToString()),
|
||||||
|
SessionStart = (DateTime)data.Rows[0]["SessionTime"],
|
||||||
|
SessionLength = (int)data.Rows[0]["SessionLength"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatisticsModel? GetSession(long GameId, string UserId)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT SUM(SessionLength) AS TotalLength FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||||
|
{ "gameid", GameId },
|
||||||
|
{ "userid", UserId }
|
||||||
|
};
|
||||||
|
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
if (data.Rows.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (data.Rows[0]["TotalLength"] == DBNull.Value)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int TotalTime = int.Parse(data.Rows[0]["TotalLength"].ToString());
|
||||||
|
|
||||||
|
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid ORDER BY SessionTime DESC LIMIT 1;";
|
||||||
|
data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
return new StatisticsModel{
|
||||||
|
GameId = GameId,
|
||||||
|
SessionLength = TotalTime,
|
||||||
|
SessionStart = (DateTime)data.Rows[0]["SessionTime"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -8,6 +8,8 @@ using Microsoft.AspNetCore.Identity;
|
|||||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
using Asp.Versioning;
|
||||||
|
using IGDB;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -97,6 +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.Roles.Sort();
|
profile.Roles.Sort();
|
||||||
|
|
||||||
return Ok(profile);
|
return Ok(profile);
|
||||||
@@ -185,6 +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;
|
||||||
|
|
||||||
// get roles
|
// get roles
|
||||||
ApplicationUser? aUser = await _userManager.FindByIdAsync(rawUser.Id);
|
ApplicationUser? aUser = await _userManager.FindByIdAsync(rawUser.Id);
|
||||||
@@ -413,5 +417,115 @@ namespace gaseous_server.Controllers
|
|||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[RequestSizeLimit(long.MaxValue)]
|
||||||
|
[Consumes("multipart/form-data")]
|
||||||
|
[DisableRequestSizeLimit, RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, ValueLengthLimit = int.MaxValue)]
|
||||||
|
[Route("Avatar")]
|
||||||
|
public async Task<IActionResult> UploadAvatar(IFormFile file)
|
||||||
|
{
|
||||||
|
ApplicationUser? user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Guid avatarId = Guid.Empty;
|
||||||
|
|
||||||
|
if (file.Length > 0)
|
||||||
|
{
|
||||||
|
using (var ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
file.CopyTo(ms);
|
||||||
|
byte[] fileBytes = ms.ToArray();
|
||||||
|
byte[] targetBytes;
|
||||||
|
|
||||||
|
using (var image = new ImageMagick.MagickImage(fileBytes))
|
||||||
|
{
|
||||||
|
ImageMagick.MagickGeometry size = new ImageMagick.MagickGeometry(256, 256);
|
||||||
|
|
||||||
|
// This will resize the image to a fixed size without maintaining the aspect ratio.
|
||||||
|
// Normally an image will be resized to fit inside the specified size.
|
||||||
|
size.IgnoreAspectRatio = true;
|
||||||
|
|
||||||
|
image.Resize(size);
|
||||||
|
var newMs = new MemoryStream();
|
||||||
|
image.Resize(size);
|
||||||
|
image.Strip();
|
||||||
|
image.Write(newMs, ImageMagick.MagickFormat.Jpg);
|
||||||
|
|
||||||
|
targetBytes = newMs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||||
|
avatarId = userTable.SetAvatar(user, targetBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(avatarId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("Avatar/{id}.jpg")]
|
||||||
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public ActionResult GetAvatar(Guid id)
|
||||||
|
{
|
||||||
|
if (id == Guid.Empty)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT * FROM UserAvatars WHERE Id = @id";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||||
|
{ "id", id }
|
||||||
|
};
|
||||||
|
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
if (data.Rows.Count > 0)
|
||||||
|
{
|
||||||
|
string filename = id.ToString() + ".jpg";
|
||||||
|
byte[] filedata = (byte[])data.Rows[0]["Avatar"];
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("Avatar/{id}.jpg")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public async Task<ActionResult> DeleteAvatarAsync()
|
||||||
|
{
|
||||||
|
ApplicationUser? user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
UserTable<ApplicationUser> userTable = new UserTable<ApplicationUser>(db);
|
||||||
|
userTable.SetAvatar(user, new byte[0]);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
|
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||||||
using gaseous_server.Classes;
|
using gaseous_server.Classes;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
|
@@ -3,9 +3,12 @@ using System.Collections.Generic;
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Authentication;
|
||||||
using gaseous_server.Classes;
|
using gaseous_server.Classes;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -16,6 +19,17 @@ namespace gaseous_server.Controllers
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public class CollectionsController : Controller
|
public class CollectionsController : Controller
|
||||||
{
|
{
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
|
|
||||||
|
public CollectionsController(
|
||||||
|
UserManager<ApplicationUser> userManager,
|
||||||
|
SignInManager<ApplicationUser> signInManager)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all ROM collections
|
/// Gets all ROM collections
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -24,9 +38,16 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public List<Classes.Collections.CollectionItem> GetCollections()
|
public async Task<ActionResult> GetCollectionsAsync()
|
||||||
{
|
{
|
||||||
return Classes.Collections.GetCollections();
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
return Ok(Classes.Collections.GetCollections(user.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -41,22 +62,31 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{CollectionId}")]
|
[Route("{CollectionId}")]
|
||||||
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GetCollection(long CollectionId, bool Build = false)
|
public async Task<ActionResult> GetCollection(long CollectionId, bool Build = false)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Build == true)
|
if (Build == true)
|
||||||
{
|
{
|
||||||
Classes.Collections.StartCollectionItemBuild(CollectionId);
|
Classes.Collections.StartCollectionItemBuild(CollectionId, user.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(Classes.Collections.GetCollection(CollectionId));
|
return Ok(Classes.Collections.GetCollection(CollectionId, user.Id));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the contents of the specified ROM collection
|
/// Gets the contents of the specified ROM collection
|
||||||
@@ -69,18 +99,27 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{CollectionId}/Roms")]
|
[Route("{CollectionId}/Roms")]
|
||||||
[ProducesResponseType(typeof(List<Classes.Collections.CollectionContents.CollectionPlatformItem>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<Classes.Collections.CollectionContents.CollectionPlatformItem>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GetCollectionRoms(long CollectionId)
|
public async Task<ActionResult> GetCollectionRoms(long CollectionId)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Classes.Collections.CollectionItem collectionItem = Classes.Collections.GetCollection(CollectionId);
|
Classes.Collections.CollectionItem collectionItem = Classes.Collections.GetCollection(CollectionId, user.Id);
|
||||||
return Ok(Classes.Collections.GetCollectionContent(collectionItem));
|
return Ok(Classes.Collections.GetCollectionContent(collectionItem, user.Id));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a preview of the provided collection item
|
/// Gets a preview of the provided collection item
|
||||||
@@ -94,17 +133,26 @@ namespace gaseous_server.Controllers
|
|||||||
[Authorize(Roles = "Admin,Gamer")]
|
[Authorize(Roles = "Admin,Gamer")]
|
||||||
[ProducesResponseType(typeof(List<Classes.Collections.CollectionContents.CollectionPlatformItem>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<Classes.Collections.CollectionContents.CollectionPlatformItem>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GetCollectionRomsPreview(Classes.Collections.CollectionItem Item)
|
public async Task<ActionResult> GetCollectionRomsPreview(Classes.Collections.CollectionItem Item)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Ok(Classes.Collections.GetCollectionContent(Item));
|
return Ok(Classes.Collections.GetCollectionContent(Item, user.Id));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return NotFound(ex);
|
return NotFound(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets ROM collection in zip format
|
/// Gets ROM collection in zip format
|
||||||
@@ -117,11 +165,15 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{CollectionId}/Roms/Zip")]
|
[Route("{CollectionId}/Roms/Zip")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GetCollectionRomsZip(long CollectionId)
|
public async Task<ActionResult> GetCollectionRomsZip(long CollectionId)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Classes.Collections.CollectionItem collectionItem = Classes.Collections.GetCollection(CollectionId);
|
Classes.Collections.CollectionItem collectionItem = Classes.Collections.GetCollection(CollectionId, user.Id);
|
||||||
|
|
||||||
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, CollectionId + ".zip");
|
string ZipFilePath = Path.Combine(Config.LibraryConfiguration.LibraryCollectionsDirectory, CollectionId + ".zip");
|
||||||
|
|
||||||
@@ -140,6 +192,11 @@ namespace gaseous_server.Controllers
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new ROM collection
|
/// Creates a new ROM collection
|
||||||
@@ -152,17 +209,26 @@ namespace gaseous_server.Controllers
|
|||||||
[Authorize(Roles = "Admin,Gamer")]
|
[Authorize(Roles = "Admin,Gamer")]
|
||||||
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
public ActionResult NewCollection(Classes.Collections.CollectionItem Item)
|
public async Task<ActionResult> NewCollectionAsync(Classes.Collections.CollectionItem Item)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Ok(Classes.Collections.NewCollection(Item));
|
return Ok(Classes.Collections.NewCollection(Item, user.Id));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return BadRequest(ex);
|
return BadRequest(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Edits an existing collection
|
/// Edits an existing collection
|
||||||
@@ -177,17 +243,26 @@ namespace gaseous_server.Controllers
|
|||||||
[Authorize(Roles = "Admin,Gamer")]
|
[Authorize(Roles = "Admin,Gamer")]
|
||||||
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult EditCollection(long CollectionId, Classes.Collections.CollectionItem Item)
|
public async Task<ActionResult> EditCollection(long CollectionId, Classes.Collections.CollectionItem Item)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Ok(Classes.Collections.EditCollection(CollectionId, Item, true));
|
return Ok(Classes.Collections.EditCollection(CollectionId, Item, user.Id, true));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Edits an existing collection
|
/// Edits an existing collection
|
||||||
@@ -202,11 +277,15 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{CollectionId}/AlwaysInclude")]
|
[Route("{CollectionId}/AlwaysInclude")]
|
||||||
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.Collections.CollectionItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult EditCollectionAlwaysInclude(long CollectionId, [FromQuery]bool Rebuild, [FromBody]Collections.CollectionItem.AlwaysIncludeItem Inclusion)
|
public async Task<ActionResult> EditCollectionAlwaysInclude(long CollectionId, [FromQuery]bool Rebuild, [FromBody]Collections.CollectionItem.AlwaysIncludeItem Inclusion)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Collections.CollectionItem collectionItem = Classes.Collections.GetCollection(CollectionId);
|
Collections.CollectionItem collectionItem = Classes.Collections.GetCollection(CollectionId, user.Id);
|
||||||
bool ItemFound = false;
|
bool ItemFound = false;
|
||||||
foreach (Collections.CollectionItem.AlwaysIncludeItem includeItem in collectionItem.AlwaysInclude)
|
foreach (Collections.CollectionItem.AlwaysIncludeItem includeItem in collectionItem.AlwaysInclude)
|
||||||
{
|
{
|
||||||
@@ -220,13 +299,18 @@ namespace gaseous_server.Controllers
|
|||||||
collectionItem.AlwaysInclude.Add(Inclusion);
|
collectionItem.AlwaysInclude.Add(Inclusion);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(Classes.Collections.EditCollection(CollectionId, collectionItem, Rebuild));
|
return Ok(Classes.Collections.EditCollection(CollectionId, collectionItem, user.Id, Rebuild));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deletes the specified ROM collection
|
/// Deletes the specified ROM collection
|
||||||
@@ -239,11 +323,15 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{CollectionId}")]
|
[Route("{CollectionId}")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult DeleteCollection(long CollectionId)
|
public async Task<ActionResult> DeleteCollection(long CollectionId)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Classes.Collections.DeleteCollection(CollectionId);
|
Classes.Collections.DeleteCollection(CollectionId, user.Id);
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -251,5 +339,10 @@ namespace gaseous_server.Controllers
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
|
@@ -6,15 +6,18 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Authentication;
|
||||||
using gaseous_server.Classes;
|
using gaseous_server.Classes;
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
using gaseous_server.Models;
|
using gaseous_server.Models;
|
||||||
using IGDB.Models;
|
using IGDB.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
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;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -25,10 +28,22 @@ namespace gaseous_server.Controllers
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class GamesController : Controller
|
public class GamesController : Controller
|
||||||
{
|
{
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
|
|
||||||
|
public GamesController(
|
||||||
|
UserManager<ApplicationUser> userManager,
|
||||||
|
SignInManager<ApplicationUser> signInManager
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
||||||
public ActionResult Game(
|
public async Task<ActionResult> Game(
|
||||||
string name = "",
|
string name = "",
|
||||||
string platform = "",
|
string platform = "",
|
||||||
string genre = "",
|
string genre = "",
|
||||||
@@ -288,7 +303,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(Game), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Game), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "5Minute")]
|
[ResponseCache(CacheProfileName = "5Minute")]
|
||||||
public ActionResult Game(long GameId)
|
public async Task<ActionResult> Game(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -316,7 +331,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(List<AlternativeName>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<AlternativeName>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameAlternativeNames(long GameId)
|
public async Task<ActionResult> GameAlternativeNames(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -349,7 +364,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(List<AgeRatings.GameAgeRating>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<AgeRatings.GameAgeRating>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameAgeClassification(long GameId)
|
public async Task<ActionResult> GameAgeClassification(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -382,7 +397,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(List<Artwork>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<Artwork>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameArtwork(long GameId)
|
public async Task<ActionResult> GameArtwork(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -413,7 +428,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(Artwork), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Artwork), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameArtwork(long GameId, long ArtworkId)
|
public async Task<ActionResult> GameArtwork(long GameId, long ArtworkId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -449,7 +464,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/artwork/{ArtworkId}/image/{size}/{ImageName}")]
|
[Route("{GameId}/artwork/{ArtworkId}/image/{size}/{ImageName}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameCoverImage(long GameId, long ArtworkId, Communications.IGDBAPI_ImageSize size, string ImageName)
|
public async Task<ActionResult> GameCoverImage(long GameId, long ArtworkId, Communications.IGDBAPI_ImageSize size, string ImageName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -516,7 +531,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(Cover), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Cover), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameCover(long GameId)
|
public async Task<ActionResult> GameCover(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -551,7 +566,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/cover/image/{size}/{imagename}")]
|
[Route("{GameId}/cover/image/{size}/{imagename}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameCoverImage(long GameId, Communications.IGDBAPI_ImageSize size, string imagename = "")
|
public async Task<ActionResult> GameCoverImage(long GameId, Communications.IGDBAPI_ImageSize size, string imagename = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -596,6 +611,81 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("{GameId}/favourite")]
|
||||||
|
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> GameGetFavouriteAsync(long GameId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
|
if (gameObject != null)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
Favourites favourites = new Favourites();
|
||||||
|
return Ok(favourites.GetFavourite(user.Id, GameId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpPost]
|
||||||
|
[Route("{GameId}/favourite")]
|
||||||
|
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> GameSetFavouriteAsync(long GameId, bool favourite)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IGDB.Models.Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
|
if (gameObject != null)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
Favourites favourites = new Favourites();
|
||||||
|
return Ok(favourites.SetFavourite(user.Id, GameId, favourite));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -603,7 +693,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(List<Genre>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<Genre>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameGenre(long GameId)
|
public async Task<ActionResult> GameGenre(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -641,7 +731,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(List<Dictionary<string, object>>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<Dictionary<string, object>>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameInvolvedCompanies(long GameId)
|
public async Task<ActionResult> GameInvolvedCompanies(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -686,7 +776,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(Dictionary<string, object>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Dictionary<string, object>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameInvolvedCompanies(long GameId, long CompanyId)
|
public async Task<ActionResult> GameInvolvedCompanies(long GameId, long CompanyId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -728,7 +818,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/companies/{CompanyId}/image")]
|
[Route("{GameId}/companies/{CompanyId}/image")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameCompanyImage(long GameId, long CompanyId)
|
public async Task<ActionResult> GameCompanyImage(long GameId, long CompanyId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -773,7 +863,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/platforms")]
|
[Route("{GameId}/platforms")]
|
||||||
[ProducesResponseType(typeof(List<KeyValuePair<long, string>>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<KeyValuePair<long, string>>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GamePlatforms(long GameId)
|
public async Task<ActionResult> GamePlatforms(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -792,7 +882,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(List<ReleaseDate>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<ReleaseDate>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameReleaseDates(long GameId)
|
public async Task<ActionResult> GameReleaseDates(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -830,13 +920,15 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(Classes.Roms.GameRomObject), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.Roms.GameRomObject), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
//[ResponseCache(CacheProfileName = "5Minute")]
|
//[ResponseCache(CacheProfileName = "5Minute")]
|
||||||
public ActionResult GameRom(long GameId, int pageNumber = 0, int pageSize = 0, long PlatformId = -1, string NameSearch = "")
|
public async Task<ActionResult> GameRomAsync(long GameId, int pageNumber = 0, int pageSize = 0, long PlatformId = -1, string NameSearch = "")
|
||||||
{
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
return Ok(Classes.Roms.GetRoms(GameId, PlatformId, NameSearch, pageNumber, pageSize));
|
return Ok(Classes.Roms.GetRoms(GameId, PlatformId, NameSearch, pageNumber, pageSize, user.Id));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -851,7 +943,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
//[ResponseCache(CacheProfileName = "5Minute")]
|
//[ResponseCache(CacheProfileName = "5Minute")]
|
||||||
public ActionResult GameRom(long GameId, long RomId)
|
public async Task<ActionResult> GameRom(long GameId, long RomId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -880,7 +972,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/roms/{RomId}")]
|
[Route("{GameId}/roms/{RomId}")]
|
||||||
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameRomRename(long GameId, long RomId, long NewPlatformId, long NewGameId)
|
public async Task<ActionResult> GameRomRename(long GameId, long RomId, long NewPlatformId, long NewGameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -910,7 +1002,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/roms/{RomId}")]
|
[Route("{GameId}/roms/{RomId}")]
|
||||||
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.Roms.GameRomItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameRomDelete(long GameId, long RomId)
|
public async Task<ActionResult> GameRomDelete(long GameId, long RomId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -942,7 +1034,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/roms/{RomId}/file")]
|
[Route("{GameId}/roms/{RomId}/file")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameRomFile(long GameId, long RomId)
|
public async Task<ActionResult> GameRomFile(long GameId, long RomId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -981,7 +1073,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/roms/{RomId}/{FileName}")]
|
[Route("{GameId}/roms/{RomId}/{FileName}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameRomFile(long GameId, long RomId, string FileName)
|
public async Task<ActionResult> GameRomFile(long GameId, long RomId, string FileName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1018,13 +1110,15 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
//[ResponseCache(CacheProfileName = "5Minute")]
|
//[ResponseCache(CacheProfileName = "5Minute")]
|
||||||
public ActionResult GameRomGroup(long GameId, long RomGroupId)
|
public async Task<ActionResult> GameRomGroupAsync(long GameId, long RomGroupId)
|
||||||
{
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId);
|
Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId, user.Id);
|
||||||
if (rom.GameId == GameId)
|
if (rom.GameId == GameId)
|
||||||
{
|
{
|
||||||
return Ok(rom);
|
return Ok(rom);
|
||||||
@@ -1047,15 +1141,17 @@ namespace gaseous_server.Controllers
|
|||||||
[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 ActionResult GetGameRomGroup(long GameId)
|
public async Task<ActionResult> GetGameRomGroupAsync(long GameId)
|
||||||
{
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId));
|
return Ok(RomMediaGroup.GetMediaGroupsFromGameId(GameId, user.Id));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -1076,7 +1172,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/romgroup")]
|
[Route("{GameId}/romgroup")]
|
||||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult NewGameRomGroup(long GameId, long PlatformId, [FromBody] List<long> RomIds)
|
public async Task<ActionResult> NewGameRomGroup(long GameId, long PlatformId, [FromBody] List<long> RomIds)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1105,13 +1201,15 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/romgroup/{RomId}")]
|
[Route("{GameId}/romgroup/{RomId}")]
|
||||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameRomGroupMembers(long GameId, long RomGroupId, [FromBody] List<long> RomIds)
|
public async Task<ActionResult> GameRomGroupMembersAsync(long GameId, long RomGroupId, [FromBody] List<long> RomIds)
|
||||||
{
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
Game gameObject = Classes.Metadata.Games.GetGame(GameId, false, false, false);
|
||||||
|
|
||||||
Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId);
|
Classes.RomMediaGroup.GameRomMediaGroupItem rom = Classes.RomMediaGroup.GetMediaGroup(RomGroupId, user.Id);
|
||||||
if (rom.GameId == GameId)
|
if (rom.GameId == GameId)
|
||||||
{
|
{
|
||||||
rom = Classes.RomMediaGroup.EditMediaGroup(RomGroupId, RomIds);
|
rom = Classes.RomMediaGroup.EditMediaGroup(RomGroupId, RomIds);
|
||||||
@@ -1135,7 +1233,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/romgroup/{RomGroupId}")]
|
[Route("{GameId}/romgroup/{RomGroupId}")]
|
||||||
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Classes.RomMediaGroup.GameRomMediaGroupItem), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameRomGroupDelete(long GameId, long RomGroupId)
|
public async Task<ActionResult> GameRomGroupDelete(long GameId, long RomGroupId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1168,7 +1266,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("{GameId}/romgroup/{RomGroupId}/{filename}")]
|
[Route("{GameId}/romgroup/{RomGroupId}/{filename}")]
|
||||||
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameRomGroupFile(long GameId, long RomGroupId, string filename = "")
|
public async Task<ActionResult> GameRomGroupFile(long GameId, long RomGroupId, string filename = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1213,7 +1311,7 @@ namespace gaseous_server.Controllers
|
|||||||
[Route("search")]
|
[Route("search")]
|
||||||
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<Game>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public ActionResult GameSearch(long RomId = 0, string SearchString = "")
|
public async Task<ActionResult> GameSearch(long RomId = 0, string SearchString = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1254,7 +1352,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(List<Screenshot>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<Screenshot>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameScreenshot(long GameId)
|
public async Task<ActionResult> GameScreenshot(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1285,7 +1383,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(Screenshot), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Screenshot), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameScreenshot(long GameId, long ScreenshotId)
|
public async Task<ActionResult> GameScreenshot(long GameId, long ScreenshotId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1319,7 +1417,7 @@ namespace gaseous_server.Controllers
|
|||||||
[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 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
|
||||||
{
|
{
|
||||||
@@ -1370,7 +1468,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(typeof(List<GameVideo>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<GameVideo>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ResponseCache(CacheProfileName = "7Days")]
|
[ResponseCache(CacheProfileName = "7Days")]
|
||||||
public ActionResult GameVideo(long GameId)
|
public async Task<ActionResult> GameVideo(long GameId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
|
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
|||||||
using gaseous_server.Classes;
|
using gaseous_server.Classes;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
|
@@ -13,6 +13,8 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.CodeAnalysis.Scripting;
|
using Microsoft.CodeAnalysis.Scripting;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using System.Text;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -37,6 +39,32 @@ namespace gaseous_server.Controllers
|
|||||||
return Ok(PlatformMapping.PlatformMap);
|
return Ok(PlatformMapping.PlatformMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("PlatformMap.json")]
|
||||||
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public ActionResult DownloadPlatformMap()
|
||||||
|
{
|
||||||
|
string srcJson = Newtonsoft.Json.JsonConvert.SerializeObject(PlatformMapping.PlatformMap, Newtonsoft.Json.Formatting.Indented);
|
||||||
|
|
||||||
|
string filename = "PlatformMap.json";
|
||||||
|
byte[] bytes = Encoding.UTF8.GetBytes(srcJson);
|
||||||
|
string contentType = "application/json";
|
||||||
|
|
||||||
|
var cd = new System.Net.Mime.ContentDisposition
|
||||||
|
{
|
||||||
|
FileName = filename,
|
||||||
|
Inline = true,
|
||||||
|
DispositionType = "attachment"
|
||||||
|
};
|
||||||
|
|
||||||
|
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||||
|
|
||||||
|
return File(bytes, contentType);
|
||||||
|
}
|
||||||
|
|
||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
@@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.CodeAnalysis.Scripting;
|
using Microsoft.CodeAnalysis.Scripting;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
|
@@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
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;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
|
@@ -12,7 +12,7 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NuGet.Common;
|
using NuGet.Common;
|
||||||
using static gaseous_server.Classes.Metadata.Games;
|
using static gaseous_server.Classes.Metadata.Games;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -73,9 +73,11 @@ 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 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;";
|
||||||
|
|
||||||
List<GaseousGame>? searchCache = Communications.GetSearchCache<List<GaseousGame>>(searchFields, searchBody);
|
List<GaseousGame>? searchCache = Communications.GetSearchCache<List<GaseousGame>>(searchFields, searchBody);
|
||||||
|
|
||||||
@@ -90,7 +92,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);
|
||||||
|
@@ -8,6 +8,8 @@ using gaseous_server.Classes;
|
|||||||
using gaseous_signature_parser.models.RomSignatureObject;
|
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 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
|
||||||
|
|
||||||
@@ -53,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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,6 +12,8 @@ using gaseous_server.Classes.Metadata;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Razor.Hosting;
|
using Microsoft.AspNetCore.Razor.Hosting;
|
||||||
|
using RestEase;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -68,7 +70,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,34 +81,39 @@ 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("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 +
|
||||||
|
"var emulatorDebugMode = " + Config.ReadSetting<string>("emulatorDebugMode", false.ToString()).ToLower() + ";";
|
||||||
byte[] bytes = Encoding.UTF8.GetBytes(ver);
|
byte[] bytes = Encoding.UTF8.GetBytes(ver);
|
||||||
return File(bytes, "text/javascript");
|
return File(bytes, "text/javascript");
|
||||||
}
|
}
|
||||||
@@ -113,19 +121,23 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("Settings/BackgroundTasks/Intervals")]
|
[Route("Settings/BackgroundTasks/Configuration")]
|
||||||
[Authorize(Roles = "Admin")]
|
[Authorize(Roles = "Admin")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public ActionResult GetBackgroundTasks()
|
public ActionResult GetBackgroundTasks()
|
||||||
{
|
{
|
||||||
Dictionary<string, BackgroundTaskItem> Intervals = new Dictionary<string, BackgroundTaskItem>();
|
Dictionary<string, BackgroundTaskItem> Intervals = new Dictionary<string, BackgroundTaskItem>();
|
||||||
Intervals.Add(ProcessQueue.QueueItemType.SignatureIngestor.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.SignatureIngestor));
|
foreach (ProcessQueue.QueueItemType itemType in Enum.GetValues(typeof(ProcessQueue.QueueItemType)))
|
||||||
Intervals.Add(ProcessQueue.QueueItemType.TitleIngestor.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.TitleIngestor));
|
{
|
||||||
Intervals.Add(ProcessQueue.QueueItemType.MetadataRefresh.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.MetadataRefresh));
|
BackgroundTaskItem taskItem = new BackgroundTaskItem(itemType);
|
||||||
Intervals.Add(ProcessQueue.QueueItemType.OrganiseLibrary.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.OrganiseLibrary));
|
if (taskItem.UserManageable == true)
|
||||||
Intervals.Add(ProcessQueue.QueueItemType.LibraryScan.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.LibraryScan));
|
{
|
||||||
Intervals.Add(ProcessQueue.QueueItemType.Rematcher.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.Rematcher));
|
if (!Intervals.ContainsKey(itemType.ToString()))
|
||||||
Intervals.Add(ProcessQueue.QueueItemType.Maintainer.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.Maintainer));
|
{
|
||||||
|
Intervals.Add(itemType.ToString(), taskItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(Intervals);
|
return Ok(Intervals);
|
||||||
}
|
}
|
||||||
@@ -133,45 +145,102 @@ namespace gaseous_server.Controllers
|
|||||||
[MapToApiVersion("1.0")]
|
[MapToApiVersion("1.0")]
|
||||||
[MapToApiVersion("1.1")]
|
[MapToApiVersion("1.1")]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("Settings/BackgroundTasks/Intervals")]
|
[Route("Settings/BackgroundTasks/Configuration")]
|
||||||
[Authorize(Roles = "Admin")]
|
[Authorize(Roles = "Admin")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public ActionResult SetBackgroundTasks(Dictionary<string, int> Intervals)
|
public ActionResult SetBackgroundTasks([FromBody] List<BackgroundTaskSettingsItem> model)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<string, int> Interval in Intervals)
|
foreach (BackgroundTaskSettingsItem TaskConfiguration in model)
|
||||||
{
|
{
|
||||||
if (Enum.IsDefined(typeof(ProcessQueue.QueueItemType), Interval.Key))
|
if (Enum.IsDefined(typeof(ProcessQueue.QueueItemType), TaskConfiguration.Task))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
BackgroundTaskItem taskItem = new BackgroundTaskItem(
|
BackgroundTaskItem taskItem = new BackgroundTaskItem(
|
||||||
(ProcessQueue.QueueItemType)Enum.Parse(typeof(ProcessQueue.QueueItemType), Interval.Key)
|
(ProcessQueue.QueueItemType)Enum.Parse(typeof(ProcessQueue.QueueItemType), TaskConfiguration.Task)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (Interval.Value >= taskItem.MinimumAllowedValue)
|
if (taskItem.UserManageable == true)
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Information, "Update Background Task", "Updating task " + Interval.Key + " with new interval " + Interval.Value);
|
// update task enabled
|
||||||
|
Logging.Log(Logging.LogType.Information, "Update Background Task", "Updating task " + TaskConfiguration.Task + " with enabled value " + TaskConfiguration.Enabled.ToString());
|
||||||
|
|
||||||
Config.SetSetting("Interval_" + Interval.Key, Interval.Value.ToString());
|
Config.SetSetting<string>("Enabled_" + TaskConfiguration.Task, TaskConfiguration.Enabled.ToString());
|
||||||
|
|
||||||
// update existing process
|
// update existing process
|
||||||
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||||
{
|
{
|
||||||
if (item.ItemType.ToString().ToLower() == Interval.Key.ToLower())
|
if (item.ItemType.ToString().ToLower() == TaskConfiguration.Task.ToLower())
|
||||||
{
|
{
|
||||||
item.Interval = Interval.Value;
|
item.Enabled(Boolean.Parse(TaskConfiguration.Enabled.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update task interval
|
||||||
|
if (TaskConfiguration.Interval >= taskItem.MinimumAllowedInterval)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Update Background Task", "Updating task " + TaskConfiguration.Task + " with new interval " + TaskConfiguration.Interval);
|
||||||
|
|
||||||
|
Config.SetSetting<string>("Interval_" + TaskConfiguration.Task, TaskConfiguration.Interval.ToString());
|
||||||
|
|
||||||
|
// update existing process
|
||||||
|
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||||
|
{
|
||||||
|
if (item.ItemType.ToString().ToLower() == TaskConfiguration.Task.ToLower())
|
||||||
|
{
|
||||||
|
item.Interval = TaskConfiguration.Interval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Interval " + Interval.Value + " for task " + Interval.Key + " is below the minimum allowed value of " + taskItem.MinimumAllowedValue + ". Skipping.");
|
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Interval " + TaskConfiguration.Interval.ToString() + " for task " + TaskConfiguration.Task + " is below the minimum allowed value of " + taskItem.MinimumAllowedInterval + ". Skipping.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// update task weekdays
|
||||||
|
Logging.Log(Logging.LogType.Information, "Update Background Task", "Updating task " + TaskConfiguration.Task + " with new weekdays " + String.Join(", ", TaskConfiguration.AllowedDays));
|
||||||
|
|
||||||
|
Config.SetSetting<string>("AllowedDays_" + TaskConfiguration.Task, Newtonsoft.Json.JsonConvert.SerializeObject(TaskConfiguration.AllowedDays));
|
||||||
|
|
||||||
|
// update existing process
|
||||||
|
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||||
|
{
|
||||||
|
if (item.ItemType.ToString().ToLower() == TaskConfiguration.Task.ToLower())
|
||||||
|
{
|
||||||
|
item.AllowedDays = TaskConfiguration.AllowedDays;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update task hours
|
||||||
|
Logging.Log(Logging.LogType.Information, "Update Background Task", "Updating task " + TaskConfiguration.Task + " with new hours " + TaskConfiguration.AllowedStartHours + ":" + TaskConfiguration.AllowedStartMinutes.ToString("00") + " to " + TaskConfiguration.AllowedEndHours + ":" + TaskConfiguration.AllowedEndMinutes.ToString("00"));
|
||||||
|
|
||||||
|
Config.SetSetting<string>("AllowedStartHours_" + TaskConfiguration.Task, TaskConfiguration.AllowedStartHours.ToString());
|
||||||
|
Config.SetSetting<string>("AllowedStartMinutes_" + TaskConfiguration.Task, TaskConfiguration.AllowedStartMinutes.ToString());
|
||||||
|
Config.SetSetting<string>("AllowedEndHours_" + TaskConfiguration.Task, TaskConfiguration.AllowedEndHours.ToString());
|
||||||
|
Config.SetSetting<string>("AllowedEndMinutes_" + TaskConfiguration.Task, TaskConfiguration.AllowedEndMinutes.ToString());
|
||||||
|
|
||||||
|
// update existing process
|
||||||
|
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||||
|
{
|
||||||
|
if (item.ItemType.ToString().ToLower() == TaskConfiguration.Task.ToLower())
|
||||||
|
{
|
||||||
|
item.AllowedStartHours = TaskConfiguration.AllowedStartHours;
|
||||||
|
item.AllowedStartMinutes = TaskConfiguration.AllowedStartMinutes;
|
||||||
|
item.AllowedEndHours = TaskConfiguration.AllowedEndHours;
|
||||||
|
item.AllowedEndMinutes = TaskConfiguration.AllowedEndMinutes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Unable to update non-user manageable task " + TaskConfiguration.Task + ". Skipping.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// task name not defined
|
// task name not defined
|
||||||
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Task " + Interval.Key + " is not user definable. Skipping.");
|
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Task " + TaskConfiguration.Task + " is not user definable. Skipping.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,9 +256,17 @@ 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())),
|
||||||
|
SearchTypes = Config.ReadSetting<List<Classes.Metadata.Games.SearchType>>("DefaultSearchMethods", new List<gaseous_server.Classes.Metadata.Games.SearchType>() {
|
||||||
|
Games.SearchType.where,
|
||||||
|
Games.SearchType.wherefuzzy,
|
||||||
|
Games.SearchType.search,
|
||||||
|
Games.SearchType.searchNoPlatform
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(systemSettingsModel);
|
return Ok(systemSettingsModel);
|
||||||
@@ -207,6 +284,8 @@ 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<List<Classes.Metadata.Games.SearchType>>("DefaultSearchMethods", model.SearchTypes);
|
||||||
Config.UpdateConfig();
|
Config.UpdateConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +294,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,
|
||||||
@@ -227,7 +307,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;
|
||||||
@@ -256,66 +337,395 @@ namespace gaseous_server.Controllers
|
|||||||
|
|
||||||
public class BackgroundTaskItem
|
public class BackgroundTaskItem
|
||||||
{
|
{
|
||||||
|
public BackgroundTaskItem()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public BackgroundTaskItem(ProcessQueue.QueueItemType TaskName)
|
public BackgroundTaskItem(ProcessQueue.QueueItemType TaskName)
|
||||||
{
|
{
|
||||||
this.Task = TaskName.ToString();
|
this.Task = TaskName.ToString();
|
||||||
|
this.TaskEnum = TaskName;
|
||||||
|
|
||||||
switch (TaskName)
|
switch (TaskName)
|
||||||
{
|
{
|
||||||
case ProcessQueue.QueueItemType.SignatureIngestor:
|
case ProcessQueue.QueueItemType.SignatureIngestor:
|
||||||
|
this._UserManageable = true;
|
||||||
this.DefaultInterval = 60;
|
this.DefaultInterval = 60;
|
||||||
this.MinimumAllowedValue = 20;
|
this.MinimumAllowedInterval = 20;
|
||||||
|
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
|
this.DefaultAllowedStartHours = 0;
|
||||||
|
this.DefaultAllowedStartMinutes = 0;
|
||||||
|
this.DefaultAllowedEndHours = 23;
|
||||||
|
this.DefaultAllowedEndMinutes = 59;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ProcessQueue.QueueItemType.TitleIngestor:
|
case ProcessQueue.QueueItemType.TitleIngestor:
|
||||||
|
this._UserManageable = true;
|
||||||
this.DefaultInterval = 1;
|
this.DefaultInterval = 1;
|
||||||
this.MinimumAllowedValue = 1;
|
this.MinimumAllowedInterval = 1;
|
||||||
|
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
|
this.DefaultAllowedStartHours = 0;
|
||||||
|
this.DefaultAllowedStartMinutes = 0;
|
||||||
|
this.DefaultAllowedEndHours = 23;
|
||||||
|
this.DefaultAllowedEndMinutes = 59;
|
||||||
|
this._Blocks = new List<ProcessQueue.QueueItemType>{
|
||||||
|
ProcessQueue.QueueItemType.OrganiseLibrary,
|
||||||
|
ProcessQueue.QueueItemType.LibraryScan,
|
||||||
|
ProcessQueue.QueueItemType.LibraryScanWorker
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ProcessQueue.QueueItemType.MetadataRefresh:
|
case ProcessQueue.QueueItemType.MetadataRefresh:
|
||||||
|
this._UserManageable = true;
|
||||||
this.DefaultInterval = 360;
|
this.DefaultInterval = 360;
|
||||||
this.MinimumAllowedValue = 360;
|
this.MinimumAllowedInterval = 360;
|
||||||
|
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
|
this.DefaultAllowedStartHours = 0;
|
||||||
|
this.DefaultAllowedStartMinutes = 0;
|
||||||
|
this.DefaultAllowedEndHours = 23;
|
||||||
|
this.DefaultAllowedEndMinutes = 59;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ProcessQueue.QueueItemType.OrganiseLibrary:
|
case ProcessQueue.QueueItemType.OrganiseLibrary:
|
||||||
|
this._UserManageable = true;
|
||||||
this.DefaultInterval = 1440;
|
this.DefaultInterval = 1440;
|
||||||
this.MinimumAllowedValue = 120;
|
this.MinimumAllowedInterval = 120;
|
||||||
|
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
|
this.DefaultAllowedStartHours = 0;
|
||||||
|
this.DefaultAllowedStartMinutes = 0;
|
||||||
|
this.DefaultAllowedEndHours = 23;
|
||||||
|
this.DefaultAllowedEndMinutes = 59;
|
||||||
|
this._Blocks = new List<ProcessQueue.QueueItemType>{
|
||||||
|
ProcessQueue.QueueItemType.LibraryScan,
|
||||||
|
ProcessQueue.QueueItemType.LibraryScanWorker,
|
||||||
|
ProcessQueue.QueueItemType.TitleIngestor,
|
||||||
|
ProcessQueue.QueueItemType.Rematcher
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ProcessQueue.QueueItemType.LibraryScan:
|
case ProcessQueue.QueueItemType.LibraryScan:
|
||||||
|
this._UserManageable = true;
|
||||||
this.DefaultInterval = 1440;
|
this.DefaultInterval = 1440;
|
||||||
this.MinimumAllowedValue = 120;
|
this.MinimumAllowedInterval = 120;
|
||||||
|
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
|
this.DefaultAllowedStartHours = 0;
|
||||||
|
this.DefaultAllowedStartMinutes = 0;
|
||||||
|
this.DefaultAllowedEndHours = 23;
|
||||||
|
this.DefaultAllowedEndMinutes = 59;
|
||||||
|
this._Blocks = new List<ProcessQueue.QueueItemType>{
|
||||||
|
ProcessQueue.QueueItemType.OrganiseLibrary,
|
||||||
|
ProcessQueue.QueueItemType.Rematcher
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ProcessQueue.QueueItemType.Rematcher:
|
case ProcessQueue.QueueItemType.Rematcher:
|
||||||
|
this._UserManageable = true;
|
||||||
this.DefaultInterval = 1440;
|
this.DefaultInterval = 1440;
|
||||||
this.MinimumAllowedValue = 360;
|
this.MinimumAllowedInterval = 360;
|
||||||
|
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
|
this.DefaultAllowedStartHours = 0;
|
||||||
|
this.DefaultAllowedStartMinutes = 0;
|
||||||
|
this.DefaultAllowedEndHours = 23;
|
||||||
|
this.DefaultAllowedEndMinutes = 59;
|
||||||
|
this._Blocks = new List<ProcessQueue.QueueItemType>{
|
||||||
|
ProcessQueue.QueueItemType.OrganiseLibrary,
|
||||||
|
ProcessQueue.QueueItemType.LibraryScan,
|
||||||
|
ProcessQueue.QueueItemType.LibraryScanWorker
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ProcessQueue.QueueItemType.Maintainer:
|
case ProcessQueue.QueueItemType.DailyMaintainer:
|
||||||
|
this._UserManageable = true;
|
||||||
|
this.DefaultInterval = 1440;
|
||||||
|
this.MinimumAllowedInterval = 1440;
|
||||||
|
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
|
this.DefaultAllowedStartHours = 1;
|
||||||
|
this.DefaultAllowedStartMinutes = 0;
|
||||||
|
this.DefaultAllowedEndHours = 5;
|
||||||
|
this.DefaultAllowedEndMinutes = 59;
|
||||||
|
this._Blocks = new List<ProcessQueue.QueueItemType>{
|
||||||
|
ProcessQueue.QueueItemType.All
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProcessQueue.QueueItemType.WeeklyMaintainer:
|
||||||
|
this._UserManageable = true;
|
||||||
this.DefaultInterval = 10080;
|
this.DefaultInterval = 10080;
|
||||||
this.MinimumAllowedValue = 10080;
|
this.MinimumAllowedInterval = 10080;
|
||||||
|
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||||
|
DayOfWeek.Monday
|
||||||
|
};
|
||||||
|
this.DefaultAllowedStartHours = 1;
|
||||||
|
this.DefaultAllowedStartMinutes = 0;
|
||||||
|
this.DefaultAllowedEndHours = 5;
|
||||||
|
this.DefaultAllowedEndMinutes = 59;
|
||||||
|
this._Blocks = new List<ProcessQueue.QueueItemType>{
|
||||||
|
ProcessQueue.QueueItemType.All
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProcessQueue.QueueItemType.BackgroundDatabaseUpgrade:
|
||||||
|
this._UserManageable = false;
|
||||||
|
this.DefaultInterval = 1;
|
||||||
|
this.MinimumAllowedInterval = 1;
|
||||||
|
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
|
this.DefaultAllowedStartHours = 0;
|
||||||
|
this.DefaultAllowedStartMinutes = 0;
|
||||||
|
this.DefaultAllowedEndHours = 23;
|
||||||
|
this.DefaultAllowedEndMinutes = 59;
|
||||||
|
this._Blocks.Add(ProcessQueue.QueueItemType.All);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProcessQueue.QueueItemType.TempCleanup:
|
||||||
|
this._UserManageable = true;
|
||||||
|
this.DefaultInterval = 1;
|
||||||
|
this.MinimumAllowedInterval = 1;
|
||||||
|
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
|
this.DefaultAllowedStartHours = 0;
|
||||||
|
this.DefaultAllowedStartMinutes = 0;
|
||||||
|
this.DefaultAllowedEndHours = 23;
|
||||||
|
this.DefaultAllowedEndMinutes = 59;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Exception("Invalid task");
|
this._UserManageable = false;
|
||||||
|
this.DefaultAllowedDays = new List<DayOfWeek>{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
|
this.DefaultAllowedStartHours = 0;
|
||||||
|
this.DefaultAllowedStartMinutes = 0;
|
||||||
|
this.DefaultAllowedEndHours = 23;
|
||||||
|
this.DefaultAllowedEndMinutes = 59;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Task { get; set; }
|
public string Task { get; set; }
|
||||||
public int Interval {
|
public ProcessQueue.QueueItemType TaskEnum { get; set; }
|
||||||
|
public bool Enabled
|
||||||
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return int.Parse(Config.ReadSetting("Interval_" + Task, DefaultInterval.ToString()));
|
if (_UserManageable == true)
|
||||||
|
{
|
||||||
|
return bool.Parse(Config.ReadSetting<string>("Enabled_" + Task, true.ToString()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_UserManageable == true)
|
||||||
|
{
|
||||||
|
Config.SetSetting<string>("Enabled_" + Task, value.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool _UserManageable;
|
||||||
|
public bool UserManageable => _UserManageable;
|
||||||
|
public int Interval
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return int.Parse(Config.ReadSetting<string>("Interval_" + Task, DefaultInterval.ToString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public int DefaultInterval { get; set; }
|
public int DefaultInterval { get; set; }
|
||||||
public int MinimumAllowedValue { get; set; }
|
public int MinimumAllowedInterval { get; set; }
|
||||||
|
public List<DayOfWeek> AllowedDays
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string jsonDefaultAllowedDays = Newtonsoft.Json.JsonConvert.SerializeObject(DefaultAllowedDays);
|
||||||
|
return Newtonsoft.Json.JsonConvert.DeserializeObject<List<DayOfWeek>>(Config.ReadSetting<string>("AllowedDays_" + Task, jsonDefaultAllowedDays));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int AllowedStartHours
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return int.Parse(Config.ReadSetting<string>("AllowedStartHours_" + Task, DefaultAllowedStartHours.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int AllowedStartMinutes
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return int.Parse(Config.ReadSetting<string>("AllowedStartMinutes_" + Task, DefaultAllowedStartMinutes.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int AllowedEndHours
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return int.Parse(Config.ReadSetting<string>("AllowedEndHours_" + Task, DefaultAllowedEndHours.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int AllowedEndMinutes
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return int.Parse(Config.ReadSetting<string>("AllowedEndMinutes_" + Task, DefaultAllowedEndMinutes.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<DayOfWeek> DefaultAllowedDays { get; set; }
|
||||||
|
public int DefaultAllowedStartHours { get; set; }
|
||||||
|
public int DefaultAllowedStartMinutes { get; set; }
|
||||||
|
public int DefaultAllowedEndHours { get; set; }
|
||||||
|
public int DefaultAllowedEndMinutes { get; set; }
|
||||||
|
private List<ProcessQueue.QueueItemType> _Blocks = new List<ProcessQueue.QueueItemType>();
|
||||||
|
public List<ProcessQueue.QueueItemType> Blocks
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_Blocks.Contains(ProcessQueue.QueueItemType.All))
|
||||||
|
{
|
||||||
|
List<ProcessQueue.QueueItemType> blockList = new List<ProcessQueue.QueueItemType>();
|
||||||
|
List<ProcessQueue.QueueItemType> skipBlockItems = new List<ProcessQueue.QueueItemType>{
|
||||||
|
ProcessQueue.QueueItemType.All,
|
||||||
|
ProcessQueue.QueueItemType.NotConfigured,
|
||||||
|
this.TaskEnum
|
||||||
|
};
|
||||||
|
foreach (ProcessQueue.QueueItemType blockType in Enum.GetValues(typeof(ProcessQueue.QueueItemType)))
|
||||||
|
{
|
||||||
|
if (!skipBlockItems.Contains(blockType))
|
||||||
|
{
|
||||||
|
blockList.Add(blockType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blockList;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _Blocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<ProcessQueue.QueueItemType> BlockedBy
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
List<ProcessQueue.QueueItemType> blockedBy = new List<ProcessQueue.QueueItemType>();
|
||||||
|
|
||||||
|
List<BackgroundTaskItem> backgroundTaskItems = new List<BackgroundTaskItem>();
|
||||||
|
foreach (ProcessQueue.QueueItemType blockType in Enum.GetValues(typeof(ProcessQueue.QueueItemType)))
|
||||||
|
{
|
||||||
|
if (blockType != this.TaskEnum)
|
||||||
|
{
|
||||||
|
BackgroundTaskItem taskItem = new BackgroundTaskItem(blockType);
|
||||||
|
if (taskItem.Blocks.Contains(this.TaskEnum))
|
||||||
|
{
|
||||||
|
if (!blockedBy.Contains(blockType))
|
||||||
|
{
|
||||||
|
blockedBy.Add(blockType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return blockedBy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BackgroundTaskSettingsItem
|
||||||
|
{
|
||||||
|
public string Task { get; set; }
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public int Interval { get; set; }
|
||||||
|
public List<DayOfWeek> AllowedDays { get; set; }
|
||||||
|
public int AllowedStartHours { get; set; }
|
||||||
|
public int AllowedStartMinutes { get; set; }
|
||||||
|
public int AllowedEndHours { get; set; }
|
||||||
|
public int AllowedEndMinutes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SystemSettingsModel
|
public class SystemSettingsModel
|
||||||
{
|
{
|
||||||
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 List<Classes.Metadata.Games.SearchType> SearchTypes { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -12,6 +12,7 @@ using gaseous_server.Classes.Metadata;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -40,7 +41,7 @@ namespace gaseous_server.Controllers
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult> CreateAdminAccount(Authentication.RegisterViewModel model)
|
public async Task<ActionResult> CreateAdminAccount(Authentication.RegisterViewModel model)
|
||||||
{
|
{
|
||||||
if (Config.ReadSetting("FirstRunStatus", "0") == "0")
|
if (Config.ReadSetting<string>("FirstRunStatus", "0") == "0")
|
||||||
{
|
{
|
||||||
if (ModelState.IsValid)
|
if (ModelState.IsValid)
|
||||||
{
|
{
|
||||||
@@ -68,7 +69,16 @@ namespace gaseous_server.Controllers
|
|||||||
await _signInManager.SignInAsync(user, isPersistent: true);
|
await _signInManager.SignInAsync(user, isPersistent: true);
|
||||||
|
|
||||||
Logging.Log(Logging.LogType.Information, "First Run", "Setting first run state to 1");
|
Logging.Log(Logging.LogType.Information, "First Run", "Setting first run state to 1");
|
||||||
Config.SetSetting("FirstRunStatus", "1");
|
Config.SetSetting<string>("FirstRunStatus", "1");
|
||||||
|
|
||||||
|
Logging.Log(Logging.LogType.Information, "First Run", "Migrating existing collections to newly created user (for upgrades from v1.6.1 and earlier)");
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "UPDATE RomCollections SET OwnedBy=@userid WHERE OwnedBy IS NULL;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "userid", user.Id }
|
||||||
|
};
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,8 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
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 Humanizer;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers.v1_1
|
namespace gaseous_server.Controllers.v1_1
|
||||||
{
|
{
|
||||||
@@ -85,7 +87,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
model.GameAgeRating.IncludeUnrated = false;
|
model.GameAgeRating.IncludeUnrated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(GetGames(model, pageNumber, pageSize));
|
return Ok(GetGames(model, user.Id, pageNumber, pageSize));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -141,9 +143,13 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
public List<string> GameMode { get; set; }
|
public List<string> GameMode { get; set; }
|
||||||
public List<string> PlayerPerspective { get; set; }
|
public List<string> PlayerPerspective { get; set; }
|
||||||
public List<string> Theme { get; set; }
|
public List<string> Theme { get; set; }
|
||||||
|
public int MinimumReleaseYear { get; set; } = -1;
|
||||||
|
public int MaximumReleaseYear { get; set; } = -1;
|
||||||
public GameRatingItem GameRating { get; set; } = new GameRatingItem();
|
public GameRatingItem GameRating { get; set; } = new GameRatingItem();
|
||||||
public GameAgeRatingItem GameAgeRating { get; set; } = new GameAgeRatingItem();
|
public GameAgeRatingItem GameAgeRating { get; set; } = new GameAgeRatingItem();
|
||||||
public GameSortingItem Sorting { get; set; } = new GameSortingItem();
|
public GameSortingItem Sorting { get; set; } = new GameSortingItem();
|
||||||
|
public bool HasSavedGame { get; set; }
|
||||||
|
public bool IsFavourite { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public class GameRatingItem
|
public class GameRatingItem
|
||||||
@@ -181,11 +187,12 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameReturnPackage GetGames(GameSearchModel model, int pageNumber = 0, int pageSize = 0)
|
public static GameReturnPackage GetGames(GameSearchModel model, string userid, int pageNumber = 0, int pageSize = 0)
|
||||||
{
|
{
|
||||||
string whereClause = "";
|
string whereClause = "";
|
||||||
string havingClause = "";
|
string havingClause = "";
|
||||||
Dictionary<string, object> whereParams = new Dictionary<string, object>();
|
Dictionary<string, object> whereParams = new Dictionary<string, object>();
|
||||||
|
whereParams.Add("userid", userid);
|
||||||
|
|
||||||
List<string> whereClauses = new List<string>();
|
List<string> whereClauses = new List<string>();
|
||||||
List<string> havingClauses = new List<string>();
|
List<string> havingClauses = new List<string>();
|
||||||
@@ -202,6 +209,32 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
whereParams.Add("@Name", "(*" + model.Name + "*) (" + model.Name + ") ");
|
whereParams.Add("@Name", "(*" + model.Name + "*) (" + model.Name + ") ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (model.HasSavedGame == true)
|
||||||
|
{
|
||||||
|
string hasSavesTemp = "(RomSavedStates.RomSaveCount IS NOT NULL OR RomGroupSavedStates.MediaGroupSaveCount IS NOT NULL)";
|
||||||
|
whereClauses.Add(hasSavesTemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model.IsFavourite == true)
|
||||||
|
{
|
||||||
|
string isFavTemp = "Favourite = 1";
|
||||||
|
havingClauses.Add(isFavTemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model.MinimumReleaseYear != -1)
|
||||||
|
{
|
||||||
|
string releaseTempMinVal = "FirstReleaseDate >= @minreleasedate";
|
||||||
|
whereParams.Add("minreleasedate", new DateTime(model.MinimumReleaseYear, 1, 1));
|
||||||
|
havingClauses.Add(releaseTempMinVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model.MaximumReleaseYear != -1)
|
||||||
|
{
|
||||||
|
string releaseTempMaxVal = "FirstReleaseDate <= @maxreleasedate";
|
||||||
|
whereParams.Add("maxreleasedate", new DateTime(model.MaximumReleaseYear, 12, 31, 23, 59, 59));
|
||||||
|
havingClauses.Add(releaseTempMaxVal);
|
||||||
|
}
|
||||||
|
|
||||||
if (model.GameRating != null)
|
if (model.GameRating != null)
|
||||||
{
|
{
|
||||||
List<string> ratingClauses = new List<string>();
|
List<string> ratingClauses = new List<string>();
|
||||||
@@ -444,11 +477,79 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
string orderByClause = "ORDER BY `" + orderByField + "` " + orderByOrder;
|
string orderByClause = "ORDER BY `" + orderByField + "` " + orderByOrder;
|
||||||
|
|
||||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
//string sql = "SELECT DISTINCT view_Games.* FROM view_Games LEFT JOIN Relation_Game_Platforms ON view_Games.Id = Relation_Game_Platforms.GameId AND (Relation_Game_Platforms.PlatformsId IN (SELECT DISTINCT PlatformId FROM Games_Roms WHERE Games_Roms.GameId = view_Games.Id)) LEFT JOIN Relation_Game_Genres ON view_Games.Id = Relation_Game_Genres.GameId LEFT JOIN Relation_Game_GameModes ON view_Games.Id = Relation_Game_GameModes.GameId LEFT JOIN Relation_Game_PlayerPerspectives ON view_Games.Id = Relation_Game_PlayerPerspectives.GameId LEFT JOIN Relation_Game_Themes ON view_Games.Id = Relation_Game_Themes.GameId " + whereClause + " " + havingClause + " " + orderByClause;
|
|
||||||
|
|
||||||
string sql = "SELECT DISTINCT Game.Id, Game.`Name`, Game.NameThe, Game.PlatformId, Game.TotalRating, Game.TotalRatingCount, Game.Cover, Game.Artworks, Game.FirstReleaseDate, Game.Category, Game.ParentGame, Game.AgeRatings, Game.AgeGroupId, Game.RomCount FROM (SELECT DISTINCT Game.*, CASE WHEN Game.`Name` LIKE 'The %' THEN CONCAT(TRIM(SUBSTR(Game.`Name` FROM 4)), ', The') ELSE Game.`Name` END AS NameThe, Games_Roms.PlatformId, 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" + platformWhereClause + " LEFT JOIN AlternativeName ON Game.Id = AlternativeName.Game " + nameWhereClause + " GROUP BY Game.Id HAVING RomCount > 0) Game LEFT JOIN Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId LEFT JOIN Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId LEFT JOIN Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId LEFT JOIN Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId " + whereClause + " " + havingClause + " " + orderByClause;
|
string sql = @"
|
||||||
|
SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
|
||||||
List<IGDB.Models.Game> RetVal = new List<IGDB.Models.Game>();
|
SELECT DISTINCT
|
||||||
|
Game.Id,
|
||||||
|
Game.`Name`,
|
||||||
|
Game.NameThe,
|
||||||
|
Game.Slug,
|
||||||
|
Game.PlatformId,
|
||||||
|
Game.TotalRating,
|
||||||
|
Game.TotalRatingCount,
|
||||||
|
Game.Cover,
|
||||||
|
Game.Artworks,
|
||||||
|
Game.FirstReleaseDate,
|
||||||
|
Game.Category,
|
||||||
|
Game.ParentGame,
|
||||||
|
Game.AgeRatings,
|
||||||
|
Game.AgeGroupId,
|
||||||
|
Game.RomCount,
|
||||||
|
RomSavedStates.RomSaveCount,
|
||||||
|
RomGroupSavedStates.MediaGroupSaveCount,
|
||||||
|
CASE
|
||||||
|
WHEN Favourites.UserId IS NULL THEN 0
|
||||||
|
ELSE 1
|
||||||
|
END AS Favourite
|
||||||
|
FROM
|
||||||
|
(SELECT DISTINCT
|
||||||
|
Game.*,
|
||||||
|
CASE
|
||||||
|
WHEN Game.`Name` LIKE 'The %' THEN CONCAT(TRIM(SUBSTR(Game.`Name` FROM 4)), ', The')
|
||||||
|
ELSE Game.`Name`
|
||||||
|
END AS NameThe,
|
||||||
|
Games_Roms.PlatformId,
|
||||||
|
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" + platformWhereClause + @"
|
||||||
|
LEFT JOIN AlternativeName ON Game.Id = AlternativeName.Game " + nameWhereClause + @"
|
||||||
|
GROUP BY Game.Id
|
||||||
|
HAVING RomCount > 0) Game
|
||||||
|
LEFT JOIN
|
||||||
|
(SELECT
|
||||||
|
Games_Roms.GameId, COUNT(GameState.Id) AS RomSaveCount
|
||||||
|
FROM
|
||||||
|
GameState
|
||||||
|
JOIN Games_Roms ON GameState.RomId = Games_Roms.Id
|
||||||
|
WHERE
|
||||||
|
GameState.IsMediaGroup = 0
|
||||||
|
AND GameState.UserId = @userid
|
||||||
|
GROUP BY Games_Roms.GameId) RomSavedStates ON Game.Id = RomSavedStates.GameId
|
||||||
|
LEFT JOIN
|
||||||
|
(SELECT
|
||||||
|
RomMediaGroup.GameId,
|
||||||
|
COUNT(RomMediaGroup.GameId) AS MediaGroupSaveCount
|
||||||
|
FROM
|
||||||
|
RomMediaGroup
|
||||||
|
JOIN GameState ON RomMediaGroup.Id = GameState.RomId
|
||||||
|
AND GameState.IsMediaGroup = 1
|
||||||
|
AND GameState.UserId = @userid
|
||||||
|
GROUP BY RomMediaGroup.GameId) RomGroupSavedStates ON Game.Id = RomGroupSavedStates.GameId
|
||||||
|
LEFT JOIN
|
||||||
|
Relation_Game_Genres ON Game.Id = Relation_Game_Genres.GameId
|
||||||
|
LEFT JOIN
|
||||||
|
Relation_Game_GameModes ON Game.Id = Relation_Game_GameModes.GameId
|
||||||
|
LEFT JOIN
|
||||||
|
Relation_Game_PlayerPerspectives ON Game.Id = Relation_Game_PlayerPerspectives.GameId
|
||||||
|
LEFT JOIN
|
||||||
|
Relation_Game_Themes ON Game.Id = Relation_Game_Themes.GameId
|
||||||
|
LEFT JOIN
|
||||||
|
Favourites ON Game.Id = Favourites.GameId AND Favourites.UserId = @userid " + whereClause + " " + havingClause + " " + orderByClause;
|
||||||
|
List<Games.MinimalGameItem> RetVal = new List<Games.MinimalGameItem>();
|
||||||
|
|
||||||
DataTable dbResponse = db.ExecuteCMD(sql, whereParams);
|
DataTable dbResponse = db.ExecuteCMD(sql, whereParams);
|
||||||
|
|
||||||
@@ -458,17 +559,72 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
// compile data for return
|
// compile data for return
|
||||||
int pageOffset = pageSize * (pageNumber - 1);
|
int pageOffset = pageSize * (pageNumber - 1);
|
||||||
for (int i = pageOffset; i < dbResponse.Rows.Count; i++)
|
for (int i = pageOffset; i < dbResponse.Rows.Count; i++)
|
||||||
|
{
|
||||||
|
if (pageNumber != 0 && pageSize != 0)
|
||||||
{
|
{
|
||||||
if (i >= (pageOffset + pageSize))
|
if (i >= (pageOffset + pageSize))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game retGame = Storage.BuildCacheObject<Game>(new Game() , dbResponse.Rows[i]);
|
|
||||||
RetVal.Add(retGame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GameReturnPackage gameReturn = new GameReturnPackage(RecordCount, RetVal);
|
Game retGame = Storage.BuildCacheObject<Game>(new Game() , dbResponse.Rows[i]);
|
||||||
|
Games.MinimalGameItem retMinGame = new Games.MinimalGameItem(retGame);
|
||||||
|
retMinGame.Index = i;
|
||||||
|
if (dbResponse.Rows[i]["RomSaveCount"] != DBNull.Value || dbResponse.Rows[i]["MediaGroupSaveCount"] != DBNull.Value)
|
||||||
|
{
|
||||||
|
retMinGame.HasSavedGame = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retMinGame.HasSavedGame = false;
|
||||||
|
}
|
||||||
|
if ((int)dbResponse.Rows[i]["Favourite"] == 0)
|
||||||
|
{
|
||||||
|
retMinGame.IsFavourite = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retMinGame.IsFavourite = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RetVal.Add(retMinGame);
|
||||||
|
}
|
||||||
|
|
||||||
|
// build alpha list
|
||||||
|
Dictionary<string, int> AlphaList = new Dictionary<string, int>();
|
||||||
|
int CurrentPage = 1;
|
||||||
|
int NextPageIndex = pageSize;
|
||||||
|
for (int i = 0; i < dbResponse.Rows.Count; i++)
|
||||||
|
{
|
||||||
|
string firstChar = dbResponse.Rows[i]["NameThe"].ToString().Substring(0, 1).ToUpperInvariant();
|
||||||
|
if (!"ABCDEFGHIJKLMNOPQRSTUVWXYZ".Contains(firstChar))
|
||||||
|
{
|
||||||
|
if (!AlphaList.ContainsKey("#"))
|
||||||
|
{
|
||||||
|
AlphaList.Add("#", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!AlphaList.ContainsKey(firstChar))
|
||||||
|
{
|
||||||
|
AlphaList.Add(firstChar, CurrentPage);
|
||||||
|
}
|
||||||
|
if (NextPageIndex == i + 1)
|
||||||
|
{
|
||||||
|
NextPageIndex += pageSize;
|
||||||
|
CurrentPage += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameReturnPackage gameReturn = new GameReturnPackage
|
||||||
|
{
|
||||||
|
Count = RecordCount,
|
||||||
|
Games = RetVal,
|
||||||
|
AlphaList = AlphaList
|
||||||
|
};
|
||||||
|
|
||||||
return gameReturn;
|
return gameReturn;
|
||||||
}
|
}
|
||||||
@@ -495,6 +651,7 @@ namespace gaseous_server.Controllers.v1_1
|
|||||||
|
|
||||||
public int Count { get; set; }
|
public int Count { get; set; }
|
||||||
public List<Games.MinimalGameItem> Games { get; set; } = new List<Games.MinimalGameItem>();
|
public List<Games.MinimalGameItem> Games { get; set; } = new List<Games.MinimalGameItem>();
|
||||||
|
public Dictionary<string, int> AlphaList { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
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;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers.v1_1
|
namespace gaseous_server.Controllers.v1_1
|
||||||
{
|
{
|
||||||
|
532
gaseous-server/Controllers/V1.1/StateManagerController.cs
Normal file
532
gaseous-server/Controllers/V1.1/StateManagerController.cs
Normal file
@@ -0,0 +1,532 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using gaseous_server.Models;
|
||||||
|
using gaseous_server.Classes;
|
||||||
|
using Authentication;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using System.Data;
|
||||||
|
using Asp.Versioning;
|
||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
|
namespace gaseous_server.Controllers.v1_1
|
||||||
|
{
|
||||||
|
[Route("api/v{version:apiVersion}/[controller]")]
|
||||||
|
[ApiVersion("1.0")]
|
||||||
|
[ApiVersion("1.1")]
|
||||||
|
[ApiController]
|
||||||
|
public class StateManagerController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
|
|
||||||
|
public StateManagerController(
|
||||||
|
UserManager<ApplicationUser> userManager,
|
||||||
|
SignInManager<ApplicationUser> signInManager
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(Models.GameStateItem), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Route("{RomId}")]
|
||||||
|
public async Task<ActionResult> SaveStateAsync(long RomId, UploadStateModel uploadState, bool IsMediaGroup = false)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
byte[] CompressedState = Common.Compress(uploadState.StateByteArray);
|
||||||
|
|
||||||
|
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", uploadState.ScreenshotByteArray },
|
||||||
|
{ "state", CompressedState },
|
||||||
|
{ "zipped", true }
|
||||||
|
};
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
if (IsMediaGroup == false)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Save State", "Saved state for rom id " + RomId + ". State size: " + uploadState.StateByteArrayBase64.Length + " Compressed size: " + CompressedState.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Save State", "Saved state for media group id " + RomId + ". State size: " + uploadState.StateByteArrayBase64.Length + " Compressed size: " + CompressedState.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(await GetStateAsync(RomId, (long)(ulong)data.Rows[0][0], IsMediaGroup));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(List<Models.GameStateItem>), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Route("{RomId}")]
|
||||||
|
public async Task<ActionResult> GetAllStateAsync(long RomId, bool IsMediaGroup = false)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT Id, StateDateTime, `Name`, Screenshot FROM GameState WHERE RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid ORDER BY StateDateTime DESC;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "romid", RomId },
|
||||||
|
{ "userid", user.Id },
|
||||||
|
{ "ismediagroup", IsMediaGroup }
|
||||||
|
};
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
List<Models.GameStateItem> gameStates = new List<GameStateItem>();
|
||||||
|
foreach (DataRow row in data.Rows)
|
||||||
|
{
|
||||||
|
gameStates.Add(BuildGameStateItem(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(gameStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(Models.GameStateItem), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Route("{RomId}/{StateId}")]
|
||||||
|
public async Task<ActionResult> GetStateAsync(long RomId, long StateId, bool IsMediaGroup = false)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT Id, StateDateTime, `Name`, Screenshot FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "id", StateId },
|
||||||
|
{ "romid", RomId },
|
||||||
|
{ "userid", user.Id },
|
||||||
|
{ "ismediagroup", IsMediaGroup }
|
||||||
|
};
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
if (data.Rows.Count == 0)
|
||||||
|
{
|
||||||
|
// invalid match - return not found
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameStateItem stateItem = BuildGameStateItem(data.Rows[0]);
|
||||||
|
|
||||||
|
return Ok(stateItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpDelete]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Route("{RomId}/{StateId}")]
|
||||||
|
public async Task<ActionResult> DeleteStateAsync(long RomId, long StateId, bool IsMediaGroup = false)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "DELETE FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "id", StateId },
|
||||||
|
{ "romid", RomId },
|
||||||
|
{ "userid", user.Id },
|
||||||
|
{ "ismediagroup", IsMediaGroup }
|
||||||
|
};
|
||||||
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpPut]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Route("{RomId}/{StateId}")]
|
||||||
|
public async Task<ActionResult> EditStateAsync(long RomId, long StateId, GameStateItemUpdateModel model, bool IsMediaGroup = false)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "UPDATE GameState SET `Name` = @name WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "id", StateId },
|
||||||
|
{ "romid", RomId },
|
||||||
|
{ "userid", user.Id },
|
||||||
|
{ "ismediagroup", IsMediaGroup },
|
||||||
|
{ "name", model.Name }
|
||||||
|
};
|
||||||
|
db.ExecuteNonQuery(sql, dbDict);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Route("{RomId}/{StateId}/Screenshot/")]
|
||||||
|
[Route("{RomId}/{StateId}/Screenshot/image.png")]
|
||||||
|
public async Task<ActionResult> GetStateScreenshotAsync(long RomId, long StateId, bool IsMediaGroup = false)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "SELECT Screenshot FROM GameState WHERE Id = @id AND RomId = @romid AND IsMediaGroup = @ismediagroup AND UserId = @userid;";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "id", StateId },
|
||||||
|
{ "romid", RomId },
|
||||||
|
{ "userid", user.Id },
|
||||||
|
{ "ismediagroup", IsMediaGroup }
|
||||||
|
};
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
if (data.Rows.Count == 0)
|
||||||
|
{
|
||||||
|
// invalid match - return not found
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string filename = "image.jpg";
|
||||||
|
byte[] bytes = (byte[])data.Rows[0][0];
|
||||||
|
string contentType = "image/png";
|
||||||
|
|
||||||
|
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(bytes, contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Route("{RomId}/{StateId}/State/")]
|
||||||
|
[Route("{RomId}/{StateId}/State/savestate.state")]
|
||||||
|
public async Task<ActionResult> GetStateDataAsync(long RomId, long StateId, bool IsMediaGroup = false, bool StateOnly = false)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
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>
|
||||||
|
{
|
||||||
|
{ "id", StateId },
|
||||||
|
{ "romid", RomId },
|
||||||
|
{ "userid", user.Id },
|
||||||
|
{ "ismediagroup", IsMediaGroup }
|
||||||
|
};
|
||||||
|
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||||
|
|
||||||
|
if (data.Rows.Count == 0)
|
||||||
|
{
|
||||||
|
// invalid match - return not found
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get rom data
|
||||||
|
Roms.GameRomItem romItem = Roms.GetRom(RomId);
|
||||||
|
|
||||||
|
byte[] bytes;
|
||||||
|
if ((bool)data.Rows[0]["Zipped"] == false)
|
||||||
|
{
|
||||||
|
bytes = (byte[])data.Rows[0]["State"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bytes = Common.Decompress((byte[])data.Rows[0]["State"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
string contentType = "";
|
||||||
|
string filename = ((DateTime)data.Rows[0]["StateDateTime"]).ToString("yyyy-MM-ddTHH-mm-ss") + "-" + Path.GetFileNameWithoutExtension(romItem.Name);
|
||||||
|
|
||||||
|
|
||||||
|
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", romItem.Name },
|
||||||
|
{ "StateDateTime", data.Rows[0]["StateDateTime"] },
|
||||||
|
{ "StateName", data.Rows[0]["Name"] }
|
||||||
|
};
|
||||||
|
if ((int)data.Rows[0]["IsMediaGroup"] == 0)
|
||||||
|
{
|
||||||
|
RomInfo.Add("MD5", romItem.Md5);
|
||||||
|
RomInfo.Add("SHA1", romItem.Sha1);
|
||||||
|
RomInfo.Add("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
|
||||||
|
{
|
||||||
|
FileName = filename,
|
||||||
|
Inline = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Response.Headers.Add("Content-Disposition", cd.ToString());
|
||||||
|
Response.Headers.Add("Cache-Control", "public, max-age=604800");
|
||||||
|
|
||||||
|
return File(bytes, contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[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)
|
||||||
|
{
|
||||||
|
bool HasScreenshot = true;
|
||||||
|
if (dr["Screenshot"] == DBNull.Value)
|
||||||
|
{
|
||||||
|
HasScreenshot = false;
|
||||||
|
}
|
||||||
|
GameStateItem stateItem = new GameStateItem
|
||||||
|
{
|
||||||
|
Id = (long)dr["Id"],
|
||||||
|
Name = (string)dr["Name"],
|
||||||
|
SaveTime = DateTime.Parse(((DateTime)dr["StateDateTime"]).ToString("yyyy-MM-ddThh:mm:ss") + 'Z'),
|
||||||
|
HasScreenshot = HasScreenshot
|
||||||
|
};
|
||||||
|
|
||||||
|
return stateItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
gaseous-server/Controllers/V1.1/StatisticsController.cs
Normal file
104
gaseous-server/Controllers/V1.1/StatisticsController.cs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using gaseous_server.Models;
|
||||||
|
using gaseous_server.Classes;
|
||||||
|
using Authentication;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
|
namespace gaseous_server.Controllers.v1_1
|
||||||
|
{
|
||||||
|
[Route("api/v{version:apiVersion}/[controller]")]
|
||||||
|
[ApiVersion("1.0")]
|
||||||
|
[ApiVersion("1.1")]
|
||||||
|
[ApiController]
|
||||||
|
public class StatisticsController: ControllerBase
|
||||||
|
{
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
|
|
||||||
|
public StatisticsController(
|
||||||
|
UserManager<ApplicationUser> userManager,
|
||||||
|
SignInManager<ApplicationUser> signInManager
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Route("Games/{GameId}/")]
|
||||||
|
public async Task<ActionResult> NewRecordStatistics(long GameId)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
Statistics statistics = new Statistics();
|
||||||
|
return Ok(statistics.RecordSession(Guid.Empty, GameId, user.Id));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpPut]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Route("Games/{GameId}/{SessionId}")]
|
||||||
|
public async Task<ActionResult> SubsequentRecordStatistics(long GameId, Guid SessionId)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
Statistics statistics = new Statistics();
|
||||||
|
return Ok(statistics.RecordSession(SessionId, GameId, user.Id));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
[Route("Games/{GameId}")]
|
||||||
|
public async Task<ActionResult> GetStatistics(long GameId)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
Statistics statistics = new Statistics();
|
||||||
|
StatisticsModel? model = statistics.GetSession(GameId, user.Id);
|
||||||
|
if (model == null)
|
||||||
|
{
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Ok(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
gaseous-server/Models/GameState.cs
Normal file
35
gaseous-server/Models/GameState.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
namespace gaseous_server.Models
|
||||||
|
{
|
||||||
|
public class UploadStateModel
|
||||||
|
{
|
||||||
|
public string ScreenshotByteArrayBase64 { get; set; }
|
||||||
|
public string StateByteArrayBase64 { get; set; }
|
||||||
|
public byte[] ScreenshotByteArray
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Convert.FromBase64String(ScreenshotByteArrayBase64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public byte[] StateByteArray
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Convert.FromBase64String(StateByteArrayBase64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GameStateItem
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public DateTime SaveTime { get; set; }
|
||||||
|
public bool HasScreenshot { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GameStateItemUpdateModel
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
}
|
||||||
|
}
|
@@ -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);
|
||||||
@@ -29,6 +29,8 @@ namespace gaseous_server.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool HasSavedGame { get; set; } = false;
|
||||||
|
|
||||||
public IGDB.Models.Cover? CoverItem
|
public IGDB.Models.Cover? CoverItem
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -37,7 +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()
|
||||||
|
{
|
||||||
|
Id = this.Cover.Id
|
||||||
|
};
|
||||||
|
|
||||||
return cover;
|
return cover;
|
||||||
}
|
}
|
||||||
@@ -46,49 +52,5 @@ namespace gaseous_server.Models
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public List<IGDB.Models.Artwork>? ArtworksItem
|
|
||||||
// {
|
|
||||||
// get
|
|
||||||
// {
|
|
||||||
// if (this.Artworks != null)
|
|
||||||
// {
|
|
||||||
// if (this.Artworks.Ids != null)
|
|
||||||
// {
|
|
||||||
// List<IGDB.Models.Artwork> artworks = new List<IGDB.Models.Artwork>();
|
|
||||||
// foreach (long id in this.Artworks.Ids)
|
|
||||||
// {
|
|
||||||
// artworks.Add(gaseous_server.Classes.Metadata.Artworks.GetArtwork(id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(this), false));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return artworks;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public List<IGDB.Models.Screenshot>? ScreenshotsItem
|
|
||||||
// {
|
|
||||||
// get
|
|
||||||
// {
|
|
||||||
// if (this.Screenshots != null)
|
|
||||||
// {
|
|
||||||
// if (this.Screenshots.Ids != null)
|
|
||||||
// {
|
|
||||||
// List<IGDB.Models.Screenshot> screenshots = new List<IGDB.Models.Screenshot>();
|
|
||||||
// foreach (long id in this.Screenshots.Ids)
|
|
||||||
// {
|
|
||||||
// screenshots.Add(gaseous_server.Classes.Metadata.Screenshots.GetScreenshot(id, Config.LibraryConfiguration.LibraryMetadataDirectory_Game(this), false));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return screenshots;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -27,7 +27,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);
|
||||||
@@ -42,6 +43,7 @@ namespace gaseous_server.Models
|
|||||||
// exists
|
// exists
|
||||||
if (ResetToDefault == false)
|
if (ResetToDefault == false)
|
||||||
{
|
{
|
||||||
|
WriteAvailableEmulators(mapItem);
|
||||||
Logging.Log(Logging.LogType.Information, "Platform Map", "Skipping import of " + mapItem.IGDBName + " - already in database.");
|
Logging.Log(Logging.LogType.Information, "Platform Map", "Skipping import of " + mapItem.IGDBName + " - already in database.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -73,7 +75,7 @@ namespace gaseous_server.Models
|
|||||||
foreach (PlatformMapItem mapItem in platforms)
|
foreach (PlatformMapItem mapItem in platforms)
|
||||||
{
|
{
|
||||||
// get the IGDB platform data
|
// get the IGDB platform data
|
||||||
Platform platform = Platforms.GetPlatform(mapItem.IGDBId);
|
Platform platform = Platforms.GetPlatform(mapItem.IGDBId, false);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -253,6 +255,30 @@ namespace gaseous_server.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void WriteAvailableEmulators(PlatformMapItem item)
|
||||||
|
{
|
||||||
|
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||||
|
string sql = "";
|
||||||
|
Dictionary<string, object> dbDict = new Dictionary<string, object>();
|
||||||
|
sql = "UPDATE PlatformMap SET RetroPieDirectoryName=@RetroPieDirectoryName, WebEmulator_Type=@WebEmulator_Type, WebEmulator_Core=@WebEmulator_Core, AvailableWebEmulators=@AvailableWebEmulators WHERE Id = @Id; ";
|
||||||
|
|
||||||
|
dbDict.Add("Id", item.IGDBId);
|
||||||
|
dbDict.Add("RetroPieDirectoryName", item.RetroPieDirectoryName);
|
||||||
|
if (item.WebEmulator != null)
|
||||||
|
{
|
||||||
|
dbDict.Add("WebEmulator_Type", item.WebEmulator.Type);
|
||||||
|
dbDict.Add("WebEmulator_Core", item.WebEmulator.Core);
|
||||||
|
dbDict.Add("AvailableWebEmulators", Newtonsoft.Json.JsonConvert.SerializeObject(item.WebEmulator.AvailableWebEmulators));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dbDict.Add("WebEmulator_Type", "");
|
||||||
|
dbDict.Add("WebEmulator_Core", "");
|
||||||
|
dbDict.Add("AvailableWebEmulators", "");
|
||||||
|
}
|
||||||
|
db.ExecuteCMD(sql, dbDict);
|
||||||
|
}
|
||||||
|
|
||||||
static PlatformMapItem BuildPlatformMapItem(DataRow row)
|
static PlatformMapItem BuildPlatformMapItem(DataRow row)
|
||||||
{
|
{
|
||||||
long IGDBId = (long)row["Id"];
|
long IGDBId = (long)row["Id"];
|
||||||
@@ -261,7 +287,7 @@ 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);
|
||||||
|
|
||||||
if (platform != null)
|
if (platform != null)
|
||||||
{
|
{
|
||||||
@@ -344,12 +370,14 @@ 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"], "[]"))
|
||||||
|
@@ -20,4 +20,3 @@ namespace gaseous_server.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
gaseous-server/Models/Signatures_Sources.cs
Normal file
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/StatisticsModel.cs
Normal file
17
gaseous-server/Models/StatisticsModel.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
namespace gaseous_server.Models
|
||||||
|
{
|
||||||
|
public class StatisticsModel
|
||||||
|
{
|
||||||
|
public Guid SessionId { get; set; } = Guid.Empty;
|
||||||
|
public long GameId { get; set; }
|
||||||
|
public DateTime SessionStart { get; set; }
|
||||||
|
public int SessionLength { get; set; }
|
||||||
|
public DateTime SessionEnd
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return SessionStart.AddMinutes(SessionLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -2,6 +2,8 @@
|
|||||||
using System.ComponentModel.Design.Serialization;
|
using System.ComponentModel.Design.Serialization;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using gaseous_server.Classes;
|
using gaseous_server.Classes;
|
||||||
|
using gaseous_server.Controllers;
|
||||||
|
using Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Manage.Internal;
|
||||||
using NuGet.Common;
|
using NuGet.Common;
|
||||||
using NuGet.Packaging;
|
using NuGet.Packaging;
|
||||||
|
|
||||||
@@ -13,25 +15,63 @@ namespace gaseous_server
|
|||||||
|
|
||||||
public class QueueItem
|
public class QueueItem
|
||||||
{
|
{
|
||||||
|
public QueueItem(QueueItemType ItemType, bool AllowManualStart = true, bool RemoveWhenStopped = false)
|
||||||
|
{
|
||||||
|
_ItemType = ItemType;
|
||||||
|
_ItemState = QueueItemState.NeverStarted;
|
||||||
|
_LastRunTime = Config.ReadSetting<DateTime>("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.AddMinutes(-5));
|
||||||
|
_AllowManualStart = AllowManualStart;
|
||||||
|
_RemoveWhenStopped = RemoveWhenStopped;
|
||||||
|
|
||||||
|
// load queueitem configuration
|
||||||
|
BackgroundTaskItem defaultItem = new BackgroundTaskItem(ItemType);
|
||||||
|
Enabled(defaultItem.Enabled);
|
||||||
|
_Interval = defaultItem.Interval;
|
||||||
|
_AllowedDays = defaultItem.AllowedDays;
|
||||||
|
AllowedStartHours = defaultItem.AllowedStartHours;
|
||||||
|
AllowedStartMinutes = defaultItem.AllowedStartMinutes;
|
||||||
|
AllowedEndHours = defaultItem.AllowedEndHours;
|
||||||
|
AllowedEndMinutes = defaultItem.AllowedEndMinutes;
|
||||||
|
_Blocks = defaultItem.Blocks;
|
||||||
|
}
|
||||||
|
|
||||||
public QueueItem(QueueItemType ItemType, int ExecutionInterval, bool AllowManualStart = true, bool RemoveWhenStopped = false)
|
public QueueItem(QueueItemType ItemType, int ExecutionInterval, bool AllowManualStart = true, bool RemoveWhenStopped = false)
|
||||||
{
|
{
|
||||||
_ItemType = ItemType;
|
_ItemType = ItemType;
|
||||||
_ItemState = QueueItemState.NeverStarted;
|
_ItemState = QueueItemState.NeverStarted;
|
||||||
_LastRunTime = DateTime.Parse(Config.ReadSetting("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ"))).AddMinutes(-5);
|
_LastRunTime = Config.ReadSetting<DateTime>("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.AddMinutes(-5));
|
||||||
_Interval = ExecutionInterval;
|
_Interval = ExecutionInterval;
|
||||||
_AllowManualStart = AllowManualStart;
|
_AllowManualStart = AllowManualStart;
|
||||||
_RemoveWhenStopped = RemoveWhenStopped;
|
_RemoveWhenStopped = RemoveWhenStopped;
|
||||||
|
|
||||||
|
// load timing defaults
|
||||||
|
BackgroundTaskItem defaultItem = new BackgroundTaskItem(ItemType);
|
||||||
|
Enabled(defaultItem.Enabled);
|
||||||
|
_AllowedDays = defaultItem.AllowedDays;
|
||||||
|
AllowedStartHours = defaultItem.AllowedStartHours;
|
||||||
|
AllowedStartMinutes = defaultItem.AllowedStartMinutes;
|
||||||
|
AllowedEndHours = defaultItem.AllowedEndHours;
|
||||||
|
AllowedEndMinutes = defaultItem.AllowedEndMinutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueueItem(QueueItemType ItemType, int ExecutionInterval, List<QueueItemType> Blocks, bool AllowManualStart = true, bool RemoveWhenStopped = false)
|
public QueueItem(QueueItemType ItemType, int ExecutionInterval, List<QueueItemType> Blocks, bool AllowManualStart = true, bool RemoveWhenStopped = false)
|
||||||
{
|
{
|
||||||
_ItemType = ItemType;
|
_ItemType = ItemType;
|
||||||
_ItemState = QueueItemState.NeverStarted;
|
_ItemState = QueueItemState.NeverStarted;
|
||||||
_LastRunTime = DateTime.Parse(Config.ReadSetting("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ"))).AddMinutes(-5);
|
_LastRunTime = Config.ReadSetting<DateTime>("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.AddMinutes(-5));
|
||||||
_Interval = ExecutionInterval;
|
_Interval = ExecutionInterval;
|
||||||
_AllowManualStart = AllowManualStart;
|
_AllowManualStart = AllowManualStart;
|
||||||
_RemoveWhenStopped = RemoveWhenStopped;
|
_RemoveWhenStopped = RemoveWhenStopped;
|
||||||
_Blocks = Blocks;
|
_Blocks = Blocks;
|
||||||
|
|
||||||
|
// load timing defaults
|
||||||
|
BackgroundTaskItem defaultItem = new BackgroundTaskItem(ItemType);
|
||||||
|
Enabled(defaultItem.Enabled);
|
||||||
|
_AllowedDays = defaultItem.AllowedDays;
|
||||||
|
AllowedStartHours = defaultItem.AllowedStartHours;
|
||||||
|
AllowedStartMinutes = defaultItem.AllowedStartMinutes;
|
||||||
|
AllowedEndHours = defaultItem.AllowedEndHours;
|
||||||
|
AllowedEndMinutes = defaultItem.AllowedEndMinutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueueItemType _ItemType = QueueItemType.NotConfigured;
|
private QueueItemType _ItemType = QueueItemType.NotConfigured;
|
||||||
@@ -42,13 +82,15 @@ namespace gaseous_server
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return DateTime.Parse(Config.ReadSetting("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ")));
|
// return DateTime.Parse(Config.ReadSetting("LastRun_" + _ItemType.ToString(), DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ")));
|
||||||
|
return Config.ReadSetting<DateTime>("LastRun_" + _ItemType.ToString(), DateTime.UtcNow);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_SaveLastRunTime == true)
|
if (_SaveLastRunTime == true)
|
||||||
{
|
{
|
||||||
Config.SetSetting("LastRun_" + _ItemType.ToString(), value.ToString("yyyy-MM-ddThh:mm:ssZ"));
|
//Config.SetSetting("LastRun_" + _ItemType.ToString(), value.ToString("yyyy-MM-ddThh:mm:ssZ"));
|
||||||
|
Config.SetSetting<DateTime>("LastRun_" + _ItemType.ToString(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,8 +103,33 @@ namespace gaseous_server
|
|||||||
private bool _RemoveWhenStopped = false;
|
private bool _RemoveWhenStopped = false;
|
||||||
private bool _IsBlocked = false;
|
private bool _IsBlocked = false;
|
||||||
private string _CorrelationId = "";
|
private string _CorrelationId = "";
|
||||||
|
private List<DayOfWeek> _AllowedDays = new List<DayOfWeek>
|
||||||
|
{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
private List<QueueItemType> _Blocks = new List<QueueItemType>();
|
private List<QueueItemType> _Blocks = new List<QueueItemType>();
|
||||||
|
|
||||||
|
public List<DayOfWeek> AllowedDays
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _AllowedDays;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_AllowedDays = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int AllowedStartHours { get; set; } = 0;
|
||||||
|
public int AllowedStartMinutes { get; set; } = 0;
|
||||||
|
public int AllowedEndHours { get; set; } = 23;
|
||||||
|
public int AllowedEndMinutes { get; set; } = 59;
|
||||||
public QueueItemType ItemType => _ItemType;
|
public QueueItemType ItemType => _ItemType;
|
||||||
public QueueItemState ItemState => _ItemState;
|
public QueueItemState ItemState => _ItemState;
|
||||||
public DateTime LastRunTime => _LastRunTime;
|
public DateTime LastRunTime => _LastRunTime;
|
||||||
@@ -72,9 +139,56 @@ namespace gaseous_server
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return LastRunTime.AddMinutes(Interval);
|
// next run time
|
||||||
|
DateTime tempNextRun = LastRunTime.ToLocalTime().AddMinutes(Interval);
|
||||||
|
// if (tempNextRun < DateTime.Now)
|
||||||
|
// {
|
||||||
|
// tempNextRun = DateTime.Now;
|
||||||
|
// }
|
||||||
|
DayOfWeek nextWeekDay = tempNextRun.DayOfWeek;
|
||||||
|
|
||||||
|
// create local start and end times
|
||||||
|
DateTime tempStartTime = new DateTime(tempNextRun.Year, tempNextRun.Month, tempNextRun.Day, AllowedStartHours, AllowedStartMinutes, 0, DateTimeKind.Local);
|
||||||
|
DateTime tempEndTime = new DateTime(tempNextRun.Year, tempNextRun.Month, tempNextRun.Day, AllowedEndHours, AllowedEndMinutes, 0, DateTimeKind.Local);
|
||||||
|
|
||||||
|
// bump the next run time to the next allowed day and hour range
|
||||||
|
if (AllowedDays.Contains(nextWeekDay))
|
||||||
|
{
|
||||||
|
// next run day is allowed, nothing to do
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// keep bumping the day forward until the a weekday is found
|
||||||
|
do
|
||||||
|
{
|
||||||
|
tempNextRun = tempNextRun.AddDays(1);
|
||||||
|
nextWeekDay = tempNextRun.DayOfWeek;
|
||||||
|
}
|
||||||
|
while (!AllowedDays.Contains(nextWeekDay));
|
||||||
|
|
||||||
|
// update windows
|
||||||
|
tempStartTime = new DateTime(tempNextRun.Year, tempNextRun.Month, tempNextRun.Day, AllowedStartHours, AllowedStartMinutes, 0, DateTimeKind.Local);
|
||||||
|
tempEndTime = new DateTime(tempNextRun.Year, tempNextRun.Month, tempNextRun.Day, AllowedEndHours, AllowedEndMinutes, 0, DateTimeKind.Local);
|
||||||
|
}
|
||||||
|
|
||||||
|
// are the hours in the right range
|
||||||
|
TimeSpan spanNextRun = tempNextRun.TimeOfDay;
|
||||||
|
if (LastRunTime.ToLocalTime().AddMinutes(Interval) < tempStartTime)
|
||||||
|
{
|
||||||
|
return tempStartTime.ToUniversalTime();
|
||||||
|
}
|
||||||
|
else if (spanNextRun >= tempStartTime.TimeOfDay && spanNextRun <= tempEndTime.TimeOfDay)
|
||||||
|
{
|
||||||
|
// all good - return nextRun
|
||||||
|
return tempNextRun.ToUniversalTime();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return tempStartTime.ToUniversalTime();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int Interval
|
public int Interval
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -220,7 +334,8 @@ namespace gaseous_server
|
|||||||
|
|
||||||
case QueueItemType.CollectionCompiler:
|
case QueueItemType.CollectionCompiler:
|
||||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Collection Compiler");
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Collection Compiler");
|
||||||
Classes.Collections.CompileCollections((long)Options);
|
Dictionary<string, object> collectionOptions = (Dictionary<string, object>)Options;
|
||||||
|
Classes.Collections.CompileCollections((long)collectionOptions["Id"], (string)collectionOptions["UserId"]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QueueItemType.MediaGroupCompiler:
|
case QueueItemType.MediaGroupCompiler:
|
||||||
@@ -233,12 +348,27 @@ namespace gaseous_server
|
|||||||
DatabaseMigration.UpgradeScriptBackgroundTasks();
|
DatabaseMigration.UpgradeScriptBackgroundTasks();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QueueItemType.Maintainer:
|
case QueueItemType.DailyMaintainer:
|
||||||
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Maintenance");
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Daily Maintenance");
|
||||||
Classes.Maintenance maintenance = new Maintenance{
|
Classes.Maintenance maintenance = new Maintenance
|
||||||
|
{
|
||||||
CallingQueueItem = this
|
CallingQueueItem = this
|
||||||
};
|
};
|
||||||
maintenance.RunMaintenance();
|
maintenance.RunDailyMaintenance();
|
||||||
|
|
||||||
|
_SaveLastRunTime = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QueueItemType.WeeklyMaintainer:
|
||||||
|
Logging.Log(Logging.LogType.Debug, "Timered Event", "Starting Weekly Maintenance");
|
||||||
|
Classes.Maintenance weeklyMaintenance = new Maintenance
|
||||||
|
{
|
||||||
|
CallingQueueItem = this
|
||||||
|
};
|
||||||
|
weeklyMaintenance.RunWeeklyMaintenance();
|
||||||
|
|
||||||
|
_SaveLastRunTime = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QueueItemType.TempCleanup:
|
case QueueItemType.TempCleanup:
|
||||||
@@ -277,7 +407,14 @@ namespace gaseous_server
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ForceExecute = false;
|
_ForceExecute = false;
|
||||||
|
if (_DisableWhenComplete == false)
|
||||||
|
{
|
||||||
_ItemState = QueueItemState.Stopped;
|
_ItemState = QueueItemState.Stopped;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_ItemState = QueueItemState.Disabled;
|
||||||
|
}
|
||||||
_LastFinishTime = DateTime.UtcNow;
|
_LastFinishTime = DateTime.UtcNow;
|
||||||
_LastRunDuration = Math.Round((DateTime.UtcNow - _LastRunTime).TotalSeconds, 2);
|
_LastRunDuration = Math.Round((DateTime.UtcNow - _LastRunTime).TotalSeconds, 2);
|
||||||
|
|
||||||
@@ -296,6 +433,26 @@ namespace gaseous_server
|
|||||||
_IsBlocked = BlockState;
|
_IsBlocked = BlockState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _DisableWhenComplete = false;
|
||||||
|
public void Enabled(bool Enabled)
|
||||||
|
{
|
||||||
|
_DisableWhenComplete = !Enabled;
|
||||||
|
if (Enabled == true)
|
||||||
|
{
|
||||||
|
if (_ItemState == QueueItemState.Disabled)
|
||||||
|
{
|
||||||
|
_ItemState = QueueItemState.Stopped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_ItemState == QueueItemState.Stopped || _ItemState == QueueItemState.NeverStarted)
|
||||||
|
{
|
||||||
|
_ItemState = QueueItemState.Disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public HasErrorsItem HasErrors
|
public HasErrorsItem HasErrors
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -420,9 +577,14 @@ namespace gaseous_server
|
|||||||
BackgroundDatabaseUpgrade,
|
BackgroundDatabaseUpgrade,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a clean up of old files, and optimises the database
|
/// Performs a clean up of old files, and purge old logs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Maintainer,
|
DailyMaintainer,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs more intensive cleanups and optimises the database
|
||||||
|
/// </summary>
|
||||||
|
WeeklyMaintainer,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cleans up marked paths in the temporary directory
|
/// Cleans up marked paths in the temporary directory
|
||||||
|
@@ -3,18 +3,14 @@ using System.Text.Json.Serialization;
|
|||||||
using gaseous_server;
|
using gaseous_server;
|
||||||
using gaseous_server.Classes;
|
using gaseous_server.Classes;
|
||||||
using gaseous_server.Models;
|
using gaseous_server.Models;
|
||||||
using gaseous_server.SignatureIngestors.XML;
|
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Versioning;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Authentication;
|
using Authentication;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
|
||||||
using IGDB.Models;
|
|
||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
|
using Asp.Versioning;
|
||||||
|
|
||||||
Logging.WriteToDiskOnly = true;
|
Logging.WriteToDiskOnly = true;
|
||||||
Logging.Log(Logging.LogType.Information, "Startup", "Starting Gaseous Server " + Assembly.GetExecutingAssembly().GetName().Version);
|
Logging.Log(Logging.LogType.Information, "Startup", "Starting Gaseous Server " + Assembly.GetExecutingAssembly().GetName().Version);
|
||||||
@@ -40,12 +36,27 @@ 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();
|
||||||
|
|
||||||
// load app settings
|
// load app settings
|
||||||
Config.InitSettings();
|
Config.InitSettings();
|
||||||
|
|
||||||
|
// set default search settings
|
||||||
|
Config.SetSetting<List<gaseous_server.Classes.Metadata.Games.SearchType>>("DefaultSearchMethods", new List<gaseous_server.Classes.Metadata.Games.SearchType>() {
|
||||||
|
Games.SearchType.where,
|
||||||
|
Games.SearchType.wherefuzzy,
|
||||||
|
Games.SearchType.search,
|
||||||
|
Games.SearchType.searchNoPlatform
|
||||||
|
});
|
||||||
|
|
||||||
|
// disable hasheous
|
||||||
|
Config.MetadataConfiguration.SignatureSource = HasheousClient.Models.MetadataModel.SignatureSources.LocalOnly;
|
||||||
|
|
||||||
// write updated settings back to the config file
|
// write updated settings back to the config file
|
||||||
Config.UpdateConfig();
|
Config.UpdateConfig();
|
||||||
|
|
||||||
@@ -55,15 +66,6 @@ Communications.MetadataSource = Config.MetadataConfiguration.MetadataSource;
|
|||||||
// set up hasheous client
|
// set up hasheous client
|
||||||
HasheousClient.WebApp.HttpHelper.BaseUri = Config.MetadataConfiguration.HasheousHost;
|
HasheousClient.WebApp.HttpHelper.BaseUri = Config.MetadataConfiguration.HasheousHost;
|
||||||
|
|
||||||
// set initial values
|
|
||||||
Guid APIKey = Guid.NewGuid();
|
|
||||||
if (Config.ReadSetting("API Key", "Test API Key") == "Test API Key")
|
|
||||||
{
|
|
||||||
// it's a new api key save it
|
|
||||||
Logging.Log(Logging.LogType.Information, "Startup", "Setting initial API key");
|
|
||||||
Config.SetSetting("API Key", APIKey.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// clean up storage
|
// clean up storage
|
||||||
if (Directory.Exists(Config.LibraryConfiguration.LibraryTempDirectory))
|
if (Directory.Exists(Config.LibraryConfiguration.LibraryTempDirectory))
|
||||||
{
|
{
|
||||||
@@ -140,12 +142,7 @@ builder.Services.AddApiVersioning(config =>
|
|||||||
config.ApiVersionReader = ApiVersionReader.Combine(new UrlSegmentApiVersionReader(),
|
config.ApiVersionReader = ApiVersionReader.Combine(new UrlSegmentApiVersionReader(),
|
||||||
new HeaderApiVersionReader("x-api-version"),
|
new HeaderApiVersionReader("x-api-version"),
|
||||||
new MediaTypeApiVersionReader("x-api-version"));
|
new MediaTypeApiVersionReader("x-api-version"));
|
||||||
});
|
}).AddApiExplorer(setup =>
|
||||||
// builder.Services.AddApiVersioning(setup =>
|
|
||||||
// {
|
|
||||||
// setup.ApiVersionReader = new UrlSegmentApiVersionReader();
|
|
||||||
// });
|
|
||||||
builder.Services.AddVersionedApiExplorer(setup =>
|
|
||||||
{
|
{
|
||||||
setup.GroupNameFormat = "'v'VVV";
|
setup.GroupNameFormat = "'v'VVV";
|
||||||
setup.SubstituteApiVersionInUrl = true;
|
setup.SubstituteApiVersionInUrl = true;
|
||||||
@@ -242,15 +239,6 @@ builder.Services.ConfigureApplicationCookie(options =>
|
|||||||
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
|
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
|
||||||
options.Cookie.SameSite = SameSiteMode.Strict;
|
options.Cookie.SameSite = SameSiteMode.Strict;
|
||||||
});
|
});
|
||||||
// builder.Services.AddIdentityCore<ApplicationUser>(options => {
|
|
||||||
// options.SignIn.RequireConfirmedAccount = false;
|
|
||||||
// options.User.RequireUniqueEmail = true;
|
|
||||||
// options.Password.RequireDigit = false;
|
|
||||||
// options.Password.RequiredLength = 10;
|
|
||||||
// options.Password.RequireNonAlphanumeric = false;
|
|
||||||
// options.Password.RequireUppercase = false;
|
|
||||||
// options.Password.RequireLowercase = false;
|
|
||||||
// });
|
|
||||||
builder.Services.AddScoped<UserStore>();
|
builder.Services.AddScoped<UserStore>();
|
||||||
builder.Services.AddScoped<RoleStore>();
|
builder.Services.AddScoped<RoleStore>();
|
||||||
|
|
||||||
@@ -277,8 +265,16 @@ var app = builder.Build();
|
|||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI(options =>
|
app.UseSwaggerUI(options =>
|
||||||
{
|
{
|
||||||
options.SwaggerEndpoint($"/swagger/v1/swagger.json", "v1.0");
|
// options.SwaggerEndpoint($"/swagger/v1/swagger.json", "v1.0");
|
||||||
options.SwaggerEndpoint($"/swagger/v1.1/swagger.json", "v1.1");
|
// options.SwaggerEndpoint($"/swagger/v1.1/swagger.json", "v1.1");
|
||||||
|
|
||||||
|
var descriptions = app.DescribeApiVersions();
|
||||||
|
foreach (var description in descriptions)
|
||||||
|
{
|
||||||
|
var url = $"/swagger/{description.GroupName}/swagger.json";
|
||||||
|
var name = description.GroupName.ToUpperInvariant();
|
||||||
|
options.SwaggerEndpoint(url, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
//}
|
//}
|
||||||
@@ -326,7 +322,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
|
||||||
{
|
{
|
||||||
@@ -421,69 +417,38 @@ 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)
|
||||||
int.Parse(Config.ReadSetting("Interval_SignatureIngestor", "60"))
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
||||||
ProcessQueue.QueueItemType.TitleIngestor,
|
ProcessQueue.QueueItemType.TitleIngestor)
|
||||||
int.Parse(Config.ReadSetting("Interval_TitleIngestor", "1")),
|
|
||||||
new List<ProcessQueue.QueueItemType>
|
|
||||||
{
|
|
||||||
ProcessQueue.QueueItemType.OrganiseLibrary,
|
|
||||||
ProcessQueue.QueueItemType.LibraryScan
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
||||||
ProcessQueue.QueueItemType.MetadataRefresh,
|
ProcessQueue.QueueItemType.MetadataRefresh)
|
||||||
int.Parse(Config.ReadSetting("Interval_MetadataRefresh", "360"))
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
||||||
ProcessQueue.QueueItemType.OrganiseLibrary,
|
ProcessQueue.QueueItemType.OrganiseLibrary)
|
||||||
int.Parse(Config.ReadSetting("Interval_OrganiseLibrary", "1440")),
|
|
||||||
new List<ProcessQueue.QueueItemType>
|
|
||||||
{
|
|
||||||
ProcessQueue.QueueItemType.LibraryScan,
|
|
||||||
ProcessQueue.QueueItemType.TitleIngestor,
|
|
||||||
ProcessQueue.QueueItemType.Rematcher
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
||||||
ProcessQueue.QueueItemType.LibraryScan,
|
ProcessQueue.QueueItemType.LibraryScan)
|
||||||
int.Parse(Config.ReadSetting("Interval_LibraryScan", "1440")),
|
|
||||||
new List<ProcessQueue.QueueItemType>
|
|
||||||
{
|
|
||||||
ProcessQueue.QueueItemType.OrganiseLibrary,
|
|
||||||
ProcessQueue.QueueItemType.Rematcher
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
||||||
ProcessQueue.QueueItemType.Rematcher,
|
ProcessQueue.QueueItemType.Rematcher)
|
||||||
int.Parse(Config.ReadSetting("Interval_Rematcher", "1440")),
|
|
||||||
new List<ProcessQueue.QueueItemType>
|
|
||||||
{
|
|
||||||
ProcessQueue.QueueItemType.OrganiseLibrary,
|
|
||||||
ProcessQueue.QueueItemType.LibraryScan
|
|
||||||
})
|
|
||||||
);
|
|
||||||
ProcessQueue.QueueItems.Add(new ProcessQueue.QueueItem(
|
|
||||||
ProcessQueue.QueueItemType.Maintainer,
|
|
||||||
int.Parse(Config.ReadSetting("Interval_Maintainer", "10080")),
|
|
||||||
new List<ProcessQueue.QueueItemType>
|
|
||||||
{
|
|
||||||
ProcessQueue.QueueItemType.All
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ProcessQueue.QueueItem tempCleanup = new ProcessQueue.QueueItem(
|
// maintenance tasks
|
||||||
ProcessQueue.QueueItemType.TempCleanup,
|
ProcessQueue.QueueItem dailyMaintenance = new ProcessQueue.QueueItem(
|
||||||
1,
|
ProcessQueue.QueueItemType.DailyMaintainer
|
||||||
new List<ProcessQueue.QueueItemType>(),
|
);
|
||||||
false,
|
ProcessQueue.QueueItems.Add(dailyMaintenance);
|
||||||
false
|
|
||||||
|
ProcessQueue.QueueItem weeklyMaintenance = new ProcessQueue.QueueItem(
|
||||||
|
ProcessQueue.QueueItemType.WeeklyMaintainer
|
||||||
|
);
|
||||||
|
ProcessQueue.QueueItems.Add(weeklyMaintenance);
|
||||||
|
|
||||||
|
ProcessQueue.QueueItem tempCleanup = new ProcessQueue.QueueItem(
|
||||||
|
ProcessQueue.QueueItemType.TempCleanup
|
||||||
);
|
);
|
||||||
tempCleanup.ForceExecute();
|
|
||||||
ProcessQueue.QueueItems.Add(tempCleanup);
|
ProcessQueue.QueueItems.Add(tempCleanup);
|
||||||
|
|
||||||
Logging.WriteToDiskOnly = false;
|
Logging.WriteToDiskOnly = false;
|
||||||
|
@@ -1,41 +1,15 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||||
"iisSettings": {
|
|
||||||
"windowsAuthentication": false,
|
|
||||||
"anonymousAuthentication": true,
|
|
||||||
"iisExpress": {
|
|
||||||
"applicationUrl": "http://localhost:38715",
|
|
||||||
"sslPort": 44314
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"profiles": {
|
"profiles": {
|
||||||
"http": {
|
"http": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "/",
|
||||||
"applicationUrl": "http://localhost:5198",
|
"applicationUrl": "http://localhost:5198",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
},
|
},
|
||||||
"dotnetRunMessages": true
|
"dotnetRunMessages": true
|
||||||
},
|
|
||||||
"https": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "swagger",
|
|
||||||
"applicationUrl": "https://localhost:7282;http://localhost:5198",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
},
|
|
||||||
"dotnetRunMessages": true
|
|
||||||
},
|
|
||||||
"IIS Express": {
|
|
||||||
"commandName": "IISExpress",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "swagger",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -26,18 +26,17 @@ SELECT
|
|||||||
*
|
*
|
||||||
FROM
|
FROM
|
||||||
(SELECT DISTINCT
|
(SELECT DISTINCT
|
||||||
row_number() over (partition by Id order by AgeGroupId desc) as seqnum, view_GamesWithRoms.*,
|
row_number() over (partition by Id order by AgeGroup.AgeGroupId desc) as seqnum, view_GamesWithRoms.*,
|
||||||
(SELECT
|
AgeGroup.AgeGroupId AS AgeGroupId
|
||||||
AgeGroupId
|
|
||||||
FROM
|
|
||||||
ClassificationMap
|
|
||||||
WHERE
|
|
||||||
RatingId = AgeRating.Rating
|
|
||||||
ORDER BY AgeGroupId DESC) AgeGroupId
|
|
||||||
FROM
|
FROM
|
||||||
view_GamesWithRoms
|
view_GamesWithRoms
|
||||||
LEFT JOIN Relation_Game_AgeRatings ON view_GamesWithRoms.Id = Relation_Game_AgeRatings.GameId
|
LEFT JOIN Relation_Game_AgeRatings ON view_GamesWithRoms.Id = Relation_Game_AgeRatings.GameId
|
||||||
LEFT JOIN AgeRating ON Relation_Game_AgeRatings.AgeRatingsId = AgeRating.Id
|
LEFT JOIN AgeRating ON Relation_Game_AgeRatings.AgeRatingsId = AgeRating.Id
|
||||||
|
LEFT JOIN (SELECT
|
||||||
|
AgeGroupId, RatingId
|
||||||
|
FROM
|
||||||
|
ClassificationMap
|
||||||
|
ORDER BY AgeGroupId DESC) AgeGroup ON AgeRating.Rating = AgeGroup.RatingId
|
||||||
) g
|
) g
|
||||||
WHERE g.seqnum = 1;
|
WHERE g.seqnum = 1;
|
||||||
|
|
||||||
|
11
gaseous-server/Support/Database/MySQL/gaseous-1015.sql
Normal file
11
gaseous-server/Support/Database/MySQL/gaseous-1015.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
CREATE TABLE `GameState` (
|
||||||
|
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`UserId` VARCHAR(45) NULL,
|
||||||
|
`RomId` BIGINT NULL,
|
||||||
|
`IsMediaGroup` INT NULL,
|
||||||
|
`StateDateTime` DATETIME NULL,
|
||||||
|
`Name` VARCHAR(100) NULL,
|
||||||
|
`Screenshot` LONGBLOB NULL,
|
||||||
|
`State` LONGBLOB NULL,
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
INDEX `idx_UserId` (`UserId` ASC) VISIBLE);
|
6
gaseous-server/Support/Database/MySQL/gaseous-1016.sql
Normal file
6
gaseous-server/Support/Database/MySQL/gaseous-1016.sql
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
ALTER TABLE `Settings`
|
||||||
|
ADD COLUMN `ValueType` INT NULL DEFAULT 0 AFTER `Setting`,
|
||||||
|
ADD COLUMN `ValueDate` DATETIME NULL DEFAULT NULL AFTER `Value`;
|
||||||
|
|
||||||
|
ALTER TABLE `GameState`
|
||||||
|
ADD COLUMN `Zipped` BOOLEAN NOT NULL DEFAULT 0;
|
4
gaseous-server/Support/Database/MySQL/gaseous-1017.sql
Normal file
4
gaseous-server/Support/Database/MySQL/gaseous-1017.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE `RomCollections`
|
||||||
|
ADD COLUMN `OwnedBy` VARCHAR(45) NULL,
|
||||||
|
ADD COLUMN `AgeGroup` INT NULL,
|
||||||
|
ADD COLUMN `AgeGroupUnclassified` BOOLEAN NULL;
|
17
gaseous-server/Support/Database/MySQL/gaseous-1018.sql
Normal file
17
gaseous-server/Support/Database/MySQL/gaseous-1018.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
ALTER TABLE `Collection`
|
||||||
|
ADD COLUMN `AsParentRelations` LONGTEXT NULL AFTER `Id`,
|
||||||
|
ADD COLUMN `AsChildRelations` LONGTEXT NULL AFTER `AsParentRelations`,
|
||||||
|
ADD COLUMN `Type` INT NULL AFTER `UpdatedAt`;
|
||||||
|
|
||||||
|
ALTER TABLE `Cover`
|
||||||
|
ADD COLUMN `GameLocalization` BIGINT NULL AFTER `Game`;
|
||||||
|
|
||||||
|
ALTER TABLE `Game`
|
||||||
|
ADD COLUMN `Collections` LONGTEXT NULL AFTER `Collection`,
|
||||||
|
ADD COLUMN `ExpandedGames` LONGTEXT NULL AFTER `Dlcs`,
|
||||||
|
ADD COLUMN `Forks` LONGTEXT NULL AFTER `Follows`,
|
||||||
|
ADD COLUMN `GameLocalizations` LONGTEXT NULL AFTER `GameEngines`,
|
||||||
|
ADD COLUMN `LanguageSupports` LONGTEXT NULL AFTER `Keywords`,
|
||||||
|
ADD COLUMN `Ports` LONGTEXT NULL AFTER `PlayerPerspectives`,
|
||||||
|
ADD COLUMN `Remakes` LONGTEXT NULL AFTER `ReleaseDates`,
|
||||||
|
ADD COLUMN `Remasters` LONGTEXT NULL AFTER `Remakes`;
|
11
gaseous-server/Support/Database/MySQL/gaseous-1019.sql
Normal file
11
gaseous-server/Support/Database/MySQL/gaseous-1019.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
CREATE TABLE `UserAvatars` (
|
||||||
|
`UserId` VARCHAR(128) NOT NULL,
|
||||||
|
`Id` VARCHAR(45) NOT NULL,
|
||||||
|
`Avatar` LONGBLOB NULL,
|
||||||
|
PRIMARY KEY (`UserId`),
|
||||||
|
INDEX `idx_AvatarId` (`Id` ASC) VISIBLE,
|
||||||
|
CONSTRAINT `ApplicationUser_Avatar`
|
||||||
|
FOREIGN KEY (`UserId`)
|
||||||
|
REFERENCES `Users` (`Id`)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
ON UPDATE NO ACTION);
|
13
gaseous-server/Support/Database/MySQL/gaseous-1020.sql
Normal file
13
gaseous-server/Support/Database/MySQL/gaseous-1020.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
CREATE TABLE `UserTimeTracking` (
|
||||||
|
`GameId` BIGINT NULL,
|
||||||
|
`UserId` VARCHAR(45) NULL,
|
||||||
|
`SessionId` VARCHAR(45) NULL,
|
||||||
|
`SessionTime` DATETIME NULL,
|
||||||
|
`SessionLength` INT NULL,
|
||||||
|
INDEX `UserId_idx` (`UserId` ASC) VISIBLE,
|
||||||
|
INDEX `SessionId_idx` (`SessionId` ASC) VISIBLE,
|
||||||
|
CONSTRAINT `UserId`
|
||||||
|
FOREIGN KEY (`UserId`)
|
||||||
|
REFERENCES `Users` (`Id`)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
ON UPDATE NO ACTION);
|
8
gaseous-server/Support/Database/MySQL/gaseous-1021.sql
Normal file
8
gaseous-server/Support/Database/MySQL/gaseous-1021.sql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
CREATE TABLE `Favourites` (
|
||||||
|
`UserId` varchar(45) NOT NULL,
|
||||||
|
`GameId` bigint(20) NOT NULL,
|
||||||
|
PRIMARY KEY (`UserId`,`GameId`),
|
||||||
|
KEY `idx_GameId` (`GameId`),
|
||||||
|
KEY `idx_UserId` (`UserId`),
|
||||||
|
CONSTRAINT `ApplicationUser_Favourite` FOREIGN KEY (`UserId`) REFERENCES `Users` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
);
|
1
gaseous-server/Support/Database/MySQL/gaseous-1022.sql
Normal file
1
gaseous-server/Support/Database/MySQL/gaseous-1022.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE `Platform` CHANGE `Name` `Name` varchar(255);
|
49
gaseous-server/Support/Database/MySQL/gaseous-fix-1005.sql
Normal file
49
gaseous-server/Support/Database/MySQL/gaseous-fix-1005.sql
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
CREATE TABLE `Relation_Game_AgeRatings` (
|
||||||
|
`GameId` BIGINT NOT NULL,
|
||||||
|
`AgeRatingsId` BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (`GameId`, `AgeRatingsId`),
|
||||||
|
INDEX `idx_PrimaryColumn` (`GameId` ASC) VISIBLE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `Relation_Game_Genres` (
|
||||||
|
`GameId` BIGINT NOT NULL,
|
||||||
|
`GenresId` BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (`GameId`, `GenresId`),
|
||||||
|
INDEX `idx_PrimaryColumn` (`GameId` ASC) VISIBLE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `Relation_Game_GameModes` (
|
||||||
|
`GameId` BIGINT NOT NULL,
|
||||||
|
`GameModesId` BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (`GameId`, `GameModesId`),
|
||||||
|
INDEX `idx_PrimaryColumn` (`GameId` ASC) VISIBLE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `Relation_Game_PlayerPerspectives` (
|
||||||
|
`GameId` BIGINT NOT NULL,
|
||||||
|
`PlayerPerspectivesId` BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (`GameId`, `PlayerPerspectivesId`),
|
||||||
|
INDEX `idx_PrimaryColumn` (`GameId` ASC) VISIBLE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `Relation_Game_Themes` (
|
||||||
|
`GameId` BIGINT NOT NULL,
|
||||||
|
`ThemesId` BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (`GameId`, `ThemesId`),
|
||||||
|
INDEX `idx_PrimaryColumn` (`GameId` ASC) VISIBLE
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE `Games_Roms`
|
||||||
|
ADD COLUMN `LastMatchAttemptDate` DATETIME NULL AFTER `LibraryId`;
|
||||||
|
|
||||||
|
CREATE TABLE `RomMediaGroup` (
|
||||||
|
`Id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`Status` INT NULL,
|
||||||
|
`PlatformId` BIGINT NULL,
|
||||||
|
`GameId` BIGINT NULL,
|
||||||
|
PRIMARY KEY (`Id`));
|
||||||
|
|
||||||
|
CREATE TABLE `RomMediaGroup_Members` (
|
||||||
|
`GroupId` BIGINT NOT NULL,
|
||||||
|
`RomId` BIGINT NOT NULL,
|
||||||
|
PRIMARY KEY (`GroupId`, `RomId`));
|
File diff suppressed because it is too large
Load Diff
@@ -20,8 +20,8 @@ namespace gaseous_server
|
|||||||
//_logger.LogInformation("Timed Hosted Service running.");
|
//_logger.LogInformation("Timed Hosted Service running.");
|
||||||
Logging.Log(Logging.LogType.Debug, "Background", "Starting background task monitor");
|
Logging.Log(Logging.LogType.Debug, "Background", "Starting background task monitor");
|
||||||
|
|
||||||
_timer = new Timer(DoWork, null, TimeSpan.Zero,
|
_timer = new Timer(DoWork, null, TimeSpan.FromSeconds(10),
|
||||||
TimeSpan.FromSeconds(5));
|
TimeSpan.FromSeconds(30));
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,8 @@ namespace gaseous_server
|
|||||||
List<ProcessQueue.QueueItem> ActiveList = new List<ProcessQueue.QueueItem>();
|
List<ProcessQueue.QueueItem> ActiveList = new List<ProcessQueue.QueueItem>();
|
||||||
ActiveList.AddRange(ProcessQueue.QueueItems);
|
ActiveList.AddRange(ProcessQueue.QueueItems);
|
||||||
foreach (ProcessQueue.QueueItem qi in ActiveList) {
|
foreach (ProcessQueue.QueueItem qi in ActiveList) {
|
||||||
|
if (qi.ItemState != ProcessQueue.QueueItemState.Disabled)
|
||||||
|
{
|
||||||
if (CheckIfProcessIsBlockedByOthers(qi) == false) {
|
if (CheckIfProcessIsBlockedByOthers(qi) == false) {
|
||||||
qi.BlockedState(false);
|
qi.BlockedState(false);
|
||||||
if (DateTime.UtcNow > qi.NextRunTime || qi.Force == true)
|
if (DateTime.UtcNow > qi.NextRunTime || qi.Force == true)
|
||||||
@@ -53,6 +55,7 @@ namespace gaseous_server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken stoppingToken)
|
public Task StopAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
|
17
gaseous-server/appsettings.Production.json
Normal file
17
gaseous-server/appsettings.Production.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*",
|
||||||
|
"Kestrel": {
|
||||||
|
"Endpoints": {
|
||||||
|
"Production": {
|
||||||
|
"Url": "http://*:80"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -1,40 +1,37 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<RootNamespace>gaseous_server</RootNamespace>
|
<RootNamespace>gaseous_server</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(RunConfiguration)' == 'https' " />
|
<PropertyGroup Condition=" '$(RunConfiguration)' == 'https' " />
|
||||||
<PropertyGroup Condition=" '$(RunConfiguration)' == 'http' " />
|
<PropertyGroup Condition=" '$(RunConfiguration)' == 'http' " />
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<DocumentationFile>bin\Debug\net7.0\gaseous-server.xml</DocumentationFile>
|
<DocumentationFile>bin\Debug\net8.0\gaseous-server.xml</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<DocumentationFile>bin\Release\net7.0\gaseous-server.xml</DocumentationFile>
|
<DocumentationFile>bin\Release\net8.0\gaseous-server.xml</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="gaseous-signature-parser" Version="2.0.0" />
|
<PackageReference Include="Asp.Versioning.Mvc" Version="8.1.0" />
|
||||||
<PackageReference Include="gaseous.IGDB" Version="1.0.1" />
|
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
|
||||||
|
<PackageReference Include="gaseous-signature-parser" Version="2.1.0" />
|
||||||
|
<PackageReference Include="gaseous.IGDB" Version="1.0.2" />
|
||||||
<PackageReference Include="hasheous-client" Version="0.1.0" />
|
<PackageReference Include="hasheous-client" Version="0.1.0" />
|
||||||
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="13.5.0" />
|
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="13.5.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.13" />
|
<PackageReference Include="sharpcompress" Version="0.38.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
|
<PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.2.24" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.1.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.12" />
|
<PackageReference Include="MySqlConnector" Version="2.3.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.10" />
|
||||||
<PackageReference Include="sharpcompress" Version="0.35.0" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
|
||||||
<PackageReference Include="Squid-Box.SevenZipSharp" Version="1.6.1.23" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.6" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.10" />
|
|
||||||
<PackageReference Include="MySqlConnector" Version="2.3.1" />
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="Controllers\" />
|
<None Remove="Controllers\" />
|
||||||
<None Remove="Models\" />
|
<None Remove="Models\" />
|
||||||
@@ -49,6 +46,7 @@
|
|||||||
<None Remove="Support\Database\MySQL\gaseous-1002.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1002.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1003.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1003.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1004.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1004.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-fix-1005.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1005.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1005.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1006.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1006.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1007.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1007.sql" />
|
||||||
@@ -59,6 +57,14 @@
|
|||||||
<None Remove="Support\Database\MySQL\gaseous-1012.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1012.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1013.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1013.sql" />
|
||||||
<None Remove="Support\Database\MySQL\gaseous-1014.sql" />
|
<None Remove="Support\Database\MySQL\gaseous-1014.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1015.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1016.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1017.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1018.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1019.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1020.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1021.sql" />
|
||||||
|
<None Remove="Support\Database\MySQL\gaseous-1022.sql" />
|
||||||
<None Remove="Classes\Metadata\" />
|
<None Remove="Classes\Metadata\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -85,6 +91,7 @@
|
|||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1002.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1002.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1003.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1003.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1004.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1004.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-fix-1005.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1005.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1005.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1006.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1006.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1007.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1007.sql" />
|
||||||
@@ -95,5 +102,13 @@
|
|||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1012.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1012.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1013.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1013.sql" />
|
||||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1014.sql" />
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1014.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1015.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1016.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1017.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1018.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1019.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1020.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1021.sql" />
|
||||||
|
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1022.sql" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
BIN
gaseous-server/wwwroot/.DS_Store
vendored
BIN
gaseous-server/wwwroot/.DS_Store
vendored
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 19 KiB |
Binary file not shown.
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 22 KiB |
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user