# JSIDPlay2 Server Setup and Maintenance

This guide explains how to set up and maintain the JSIDPlay2 server, ranging from an automated Docker-based setup to a
detailed manual configuration.

## Table of Contents

- [Easy Setup using Caddy and Docker](#easy-setup-using-caddy-and-docker)
    - [Component Details](#component-details)
- [Manual Setup](#manual-setup)
    - [Security](#security)
    - [SSL/TLS Configuration](#ssltls-configuration)
    - [Launching JSIDPlay2Server](#launching-jsidplay2server)
    - [Remote Access](#remote-access)
    - [Database Setup (WhatsSID)](#database-setup-whatssid)
    - [NGINX Configuration (Video Streaming)](#nginx-configuration-video-streaming)
    - [Voice Recognition Setup](#voice-recognition-setup)
    - [CI/CD with Jenkins](#cicd-with-jenkins)
    - [Maintenance and Updates](#maintenance-and-updates)
    - [WhatsSID and HVSC Update](#whatssid-and-hvsc-update)
    - [Server Folder Update](#server-folder-update)
    - [Fingerprinting Update](#fingerprinting-update)

---

## Easy Setup using Caddy and Docker

The easiest way to set up the JSIDPlay2 server is by using Caddy and Docker. This method automates much of the
configuration, including HTTPS support and dependency management.

- **Caddy Configuration:** See [src/main/caddy](../src/main/caddy) for the web server setup and reverse proxy
  configuration.
- **Docker Configuration:** See [src/main/docker](../src/main/docker) for Dockerfiles and Docker Compose configurations
  to run the server and its dependencies (MySQL, NGINX) in containers.
- **Jenkins Configuration:** See [src/main/jenkins](../src/main/jenkins) for Jenkins job configurations used for
  continuous integration and deployment, including beta releases, server updates, and online content deployment.

### Component Details

#### Caddy

[Caddy](https://caddyserver.com/) acts as a modern, high-performance web server and reverse proxy. In this setup, it:

- Automatically manages SSL/TLS certificates via Let's Encrypt.
- Redirects insecure HTTP traffic to HTTPS.
- Serves as a reverse proxy for the JSIDPlay2 backend services.
- Serves static files for the web interface and music collections.
- Handles port 8443 for backward compatibility.

#### Docker Compose Modules

The [src/main/docker](../src/main/docker) directory contains several Docker Compose files, each serving a specific
purpose. You can combine them as needed:

- **`docker-compose.server.linux.yml`**: The core component.
    - **`jsidplay2-server`**: Runs the main RESTful API server.
    - **`mysql`**: Provides the database for WhatsSID audio recognition.
    - **`nginx`**: Configured with the RTMP module to support C64 video streaming (RTMP/HLS).
- **`docker-compose.whatssid.linux.yml`**: A specialized configuration for maintenance.
    - Runs the `RecordingTool` to update the WhatsSID database when new music collections (like a new HVSC version) are
      released.
- **`docker-compose.ui.linux.yml`**: Runs the JSIDPlay2 JavaFX desktop UI inside a container.
- **`docker-compose.netsiddev.linux.yml`**: Runs the NetSID device emulator GUI in a container.

#### Jenkins CI/CD Jobs

Jenkins automates the lifecycle of the project. The [src/main/jenkins](../src/main/jenkins) directory contains:

- **Beta Releases (`config-linux.xml`, `config-win.xml`, `config-mac.xml`, etc.)**:
    - Automatically build and package the latest code for all supported platforms.
    - Ensure that every commit to the repository results in a functional, ready-to-test beta version.
- **Server Updates (`config-server-linux.xml`)**:
    - Monitors the master branch and automatically redeploys the live JSIDPlay2 server when changes are detected.
    - Ensures the online service is always running the latest stable version.
- **Extra Online Content (`config-online-content.xml`)**:
    - Automates the deployment of large music collections (HVSC, CGSC) and other static resources.
    - Handles the complex task of synchronizing the server's local storage with the latest online content releases.

---

## Manual Setup

Everything described below can be performed manually if you prefer not to use Docker or Caddy.

### Security

Basic authentication is used when calling the services with the following pre-configured credentials:

* **Username:** `jsidplay2`
* **Password:** `jsidplay2!`

You can change the password or add an administrative user (e.g., to grant access to private music collections) via an
external configuration file named `tomcat-users.xml` located in your home directory.

**Example `tomcat-users.xml`:**

```xml

<tomcat-users>
    <role rolename="admin"/>
    <role rolename="user"/>

    <user name="jsidplay2" password="jsidplay2!" roles="user"/>
    <user name="admin" password="admin" roles="admin"/>
</tomcat-users>
```

### SSL/TLS Configuration

If you want to use HTTPS, you need a certificate.

#### Self-signed Certificate (Testing only)

To create a self-signed certificate using Java's `keytool`:

```bash
keytool -genkey -alias jsidplay2 -keyalg RSA -keystore /etc/jsidplay2.ks -keysize 2048
```

*Note: This will trigger warnings in browsers and may be rejected by mobile devices.*

#### Trusted Certificate (Let's Encrypt)

This example uses Apache2 on Linux with Certbot.

1. **Secure Apache2:**
   ```bash
   sudo apt-get install software-properties-common
   sudo add-apt-repository ppa:certbot/certbot
   sudo apt-get update
   sudo apt-get install python-certbot-apache
   sudo certbot --apache
   ```

2. **Convert to Java Keystore:**
   Create a script `/usr/bin/jsidplay2cert`:
   ```bash
   #!/bin/bash
   # Combine PEM files
   cat /etc/letsencrypt/live/yourdomain.com/{cert.pem,chain.pem,fullchain.pem,privkey.pem} > /tmp/fullchain.pem

   # Convert to PKCS12
   openssl pkcs12 -export -out /tmp/fullchain.pkcs12 -in /tmp/fullchain.pem -password pass:jsidplay2
   rm /tmp/fullchain.pem

   # Create JKS keystore
   rm /etc/jsidplay2.ks
   keytool -genkey -keyalg RSA -alias jsidplay2 -keystore /etc/jsidplay2.ks -storepass jsidplay2 -keypass jsidplay2 -dname 'cn="JSIDPlay2", ou="JSIDPlay2", o="Open Source", l="Berlin", c=DE'
   keytool -delete -alias jsidplay2 -keystore /etc/jsidplay2.ks -storepass jsidplay2

   # Import certificate
   keytool -v -importkeystore -srckeystore /tmp/fullchain.pkcs12 -destkeystore /etc/jsidplay2.ks -deststoretype JKS -srcstorepass jsidplay2 -deststorepass jsidplay2
   rm /tmp/fullchain.pkcs12
   keytool -keystore /etc/jsidplay2.ks -changealias -alias 1 -destalias jsidplay2 -storepass jsidplay2
   ```

3. **Automate with Cron:**
   Add to `sudo crontab -e`:
   ```cron
   40 3 * * 0 certbot -q renew
   @weekly root /usr/bin/jsidplay2cert
   ```

### Launching JSIDPlay2Server

#### Standalone (HTTP)

```bash
java -classpath jsidplay2-{version}-ui.jar server.restful.JSIDPlay2Server
```

#### Standalone (HTTPS)

```bash
java -classpath {artifactId}-{version}-ui.jar server.restful.JSIDPlay2Server \
    --appServerKeystore /home/ken/jsidplay2.ks \
    --appServerKeystorePassword jsidplay2 \
    --appServerKeyAlias jsidplay2 \
    --appServerKeyPassword jsidplay2 \
    --appServerConnectors HTTPS
```

#### Systemd Service (Autostart)

Create `/etc/systemd/system/jsidplay2.service`:

```ini
[Unit]
Wants = network-online.target
After = network.target network-online.target

[Service]
ExecStart = java \
            -Dhibernate.dialect.storage_engine=innodb \
            -classpath /home/ken/Downloads/{artifactId}-{version}-linux/jsidplay2-{version}-ui.jar \
            server.restful.JSIDPlay2Server \
            --appServerKeystore /home/ken/jsidplay2.ks \
            --appServerKeystorePassword jsidplay2 \
            --appServerKeyAlias jsidplay2 \
            --appServerKeyPassword jsidplay2 \
            --appServerConnectors HTTP_HTTPS \
            --whatsSIDDatabaseDriver com.mysql.cj.jdbc.Driver \
            --whatsSIDDatabaseUrl "jdbc:mysql://127.0.0.1:3306/{hvsc_version}?createDatabaseIfNotExist=true&useUnicode=yes&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC" \
            --whatsSIDDatabaseUsername <username> \
            --whatsSIDDatabasePassword <password> \
            --whatsSIDDatabaseDialect org.hibernate.dialect.MySQL5InnoDBDialect
User = ken

[Install]
WantedBy = default.target
```

Enable and start:

```bash
sudo systemctl daemon-reload
sudo systemctl enable jsidplay2.service
sudo systemctl start jsidplay2.service
```

### Remote Access

To access the server from the internet:

1. **Dynamic DNS:** Set up a hostname (e.g., via No-IP) pointing to your public IP.
2. **Port Forwarding:** Forward ports `8080` (HTTP) and `8443` (HTTPS) to your server's internal IP.
   *Warning: Opening ports increases security risks.*

### Database Setup (WhatsSID)

JSIDPlay2Server uses MySQL for the WhatsSID audio recognition database.

1. **Install MySQL:**
   ```bash
   sudo apt-get install mysql-server
   sudo mysql_secure_installation
   ```

2. **Create User:**
   ```sql
   sudo mysql -u root -p
   CREATE USER 'newuser'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
   GRANT ALL PRIVILEGES ON *.* TO 'newuser'@'localhost' WITH GRANT OPTION;
   ```

3. **Performance Tuning:**
   Add these settings to `/etc/mysql/mysql.conf.d/mysqld.cnf`:
   ```ini
   [mysqld]
   innodb_buffer_pool_size = 32G
   innodb_buffer_pool_instances = 16
   innodb_log_file_size = 4G
   innodb_flush_log_at_trx_commit = 2
   innodb_flush_method = O_DIRECT
   max_connections = 200
   table_open_cache = 4000
   thread_cache_size = 50
   sql-mode = "ANSI_QUOTES"
   ```

4. **Monitoring & Management:**
    - Start/Restart: `sudo systemctl restart mysql`
    - Warm-up status: `SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';`

### NGINX Configuration (Video Streaming)

To support video streaming (RTMP/HLS), use NGINX with the RTMP module.

1. **Configuration:**
   ```bash
   cp src/main/deploy/jsidplay2/nginx.conf /usr/local/nginx/conf/nginx.conf
   ```

2. **Start NGINX:**
   ```bash
   sudo /usr/local/nginx/sbin/nginx
   ```

### Voice Recognition Setup

Install Vosk models for speech-to-text:

```bash
# English model
wget https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip
unzip vosk-model-small-en-us-0.15.zip -d ~/.cache/vosk/

# German model
wget https://alphacephei.com/vosk/models/vosk-model-small-de-0.15.zip
unzip vosk-model-small-de-0.15.zip -d ~/.cache/vosk/
```

### CI/CD with Jenkins

The project uses Jenkins for automated builds, testing, and deployment. Configuration files for these jobs are located
in [src/main/jenkins](../src/main/jenkins).

- **Beta Releases:** `config-linux.xml`, `config-win.xml`, `config-mac.xml`, etc., automate the creation and publication
  of beta versions for various platforms.
- **Server Updates:** `config-server-linux.xml` is used to update the JSIDPlay2 server automatically whenever changes
  are pushed to the master branch.
- **Extra Online Content:** `config-online-content.xml` manages the deployment of additional resources like HVSC, CGSC,
  and other music collections to the web server.

---

## Maintenance and Updates

### WhatsSID and HVSC Update

When a new HVSC version is released:

1. Update version references in `pom.xml`, `README.md`, and launch configurations.
2. Deploy online content by copying the new HVSC `.7z` file to the server and triggering the `config-online-content.xml`
   job.

### Server Folder Update

1. Deploy online content first.
2. Copy `src/main/deploy/jsidplay2/*.deploy` files to `~/.jsidplay2/deploy`.
3. Restart the server; it will fetch and publish deployment URLs automatically.

### Fingerprinting Update

To update the audio recognition database for a new HVSC:

1. **Manual Fingerprint Creation:**
   Use the `fingerprint-creator.sh` script:
   ```bash
   #!/bin/bash
   java -Dhibernate.dialect.storage_engine=innodb \
     -classpath jsidplay2-{version}-ui.jar ui.tools.RecordingTool \
     --whatsSIDDatabaseDriver com.mysql.cj.jdbc.Driver \
     --whatsSIDDatabaseUrl "jdbc:mysql://127.0.0.1:3306/{hvsc_version}?createDatabaseIfNotExist=true&..." \
     --whatsSIDDatabaseUsername <user> \
     --whatsSIDDatabasePassword <pass> \
     --fingerprinting true \
     --hvsc <pathToHVSC> \
     <pathToMusicCollection>
   ```
   *Tip: Use `--previousDirectory <oldWavPath>` to reuse existing recordings.*

2. **Database Cleanup:**
   ```sql
   DROP DATABASE hvsc_old_version;
   ```

3. **Verify Counts:**
   ```sql
   SELECT count(DISTINCT InfoDir) FROM MusicInfo;
   ```
