Skip to content

Commit

Permalink
feat: add ftp sync throught ftpd service and device discovery with ti…
Browse files Browse the repository at this point in the history
…nfoil
  • Loading branch information
vinicioslc committed Aug 11, 2023
1 parent 742a45c commit 2f95984
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 93 deletions.
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ ROMS_DIR_FULLPATH=./games
AUTH_USERS=admin:123,other:421
UNAUTHORIZED_MSG='No tricks and treats for you!!'
WELCOME_MSG='The Server Works!!'
NX_PORTS=5000 # device ftp port
# NX_IPS=192.168.0.103 # device ip port / detected when tinfoil list games
SAVE_SYNC_INTERVAL=50000 # device sync cycle interval
# NX_USER=ftpd # device ftpd user
# NX_PASSWORD= # device ftpd password
55 changes: 55 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Multi-Arch Docker

on:
push:
branches: [main, master]
tags:
- "*.*.*"
workflow_call:

jobs:
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
steps:
# Get the repository's code
- name: Checkout
uses: actions/checkout@v3

# https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v2

# https://github.com/docker/setup-buildx-action
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2

- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: vinicioslc/tinfoil-hat
flavor: |
latest=auto
tags: |
type=ref,event=branch
type=ref,event=tag
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
48 changes: 25 additions & 23 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
name: Playwright Tests
on:
push:
branches: [ main, master ]
branches: [main, master]
pull_request:
branches: [ main, master ]
branches: [main, master]
workflow_call:

jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Copy environment files
working-directory: .
run: |
cp -f ./.env.example ./.env
cp -f ./.env.example ./test/project/.env
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Copy environment files
working-directory: .
run: |
cp -f ./.env.example ./.env
cp -f ./.env.example ./test/project/.env
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
39 changes: 30 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# 📂 Tinfoil-Hat Server

[![Playwright Tests](https://github.com/vinicioslc/tinfoil-hat/actions/workflows/playwright.yml/badge.svg)](https://github.com/vinicioslc/tinfoil-hat/actions/workflows/playwright.yml)
[![Docker Publish](https://github.com/vinicioslc/tinfoil-hat/actions/workflows/docker.yml/badge.svg)](https://github.com/vinicioslc/tinfoil-hat/actions/workflows/docker.yml)

> A Docker based Tinfoil Server - you could download code and `npm run dev` as well...
Expand All @@ -14,6 +15,7 @@ With this server Tinfoil users can serve all .NSP .XCI files in local network wi
- Multi user Authentication through user:pass,user2:pass2 ENV supplied as docker env
- Customize Hello message and not logged in message throught ENVs
- 96% less RAM consumption, compared to the NUT solution !!! (in some cases see below!)

<div align="center">
<br>

Expand Down Expand Up @@ -96,6 +98,33 @@ services:
- 9008:8080
```
## Automatic Saves Backup using FTP
> How it works :
1. First you need backup your saves using Tinfoil or JKSV the folders path supported are `/JKSV` and `/switch/tinfoil/saves`

> Both folders will be downloaded to `/<games_folder>/Saves/JKSV` and `/<games_folder>/Saves/Tinfoil` this will ensure these folders will be found by tinfoil app.

2. You need to serve your Switch files at network using ftpd

##### Setup sys-ftpd on the Switch

- Install sys-ftpd - available as sys ftpd light in the Homebrew Menu
- Install ovl-sysmodule from Homebrew Menu - optional but recommended

Follow the sys-ftpd configuration to set up the user, password and port used for the FTP connection. Note these for Ownfoil configuration, as well as the IP of your Switch. If you installed ovl-sysmodule you can toggle on/off the FTP server using the Tesla overlay.

It is recommended to test the FTP connection at least once with a regular FTP Client to make sure everything is working as expected on the switch.

3. To start sync saves inside Tinfoil app on switch connect and list the server homebrews to the server recongnize the switch IP and start sync

- This will allow the server "capture" the switch device IP and start to syncing it

4. After first sync the server will fetch periodically using sync interval.

![Save Sync Diagram](/.diagrams/save%20sync.drawio.png)

## We want

- [ ] Organize and rename app listing by GAMEID
Expand All @@ -104,7 +133,7 @@ services:

## Images with Tinfoil

#### setup connection
#### Setup Connection

![image](https://user-images.githubusercontent.com/10997022/214877049-8d369eb5-7440-4b22-9763-96da1c277f41.png)

Expand All @@ -117,11 +146,3 @@ services:
- `express` | Serve Dynamically shop(.json|.tfl) with updated content at every refresh and serve files statically
- `serve-index` | To serve a rich listing of files (in case only shop.json shop.tfl for tinfoil)
- `json5` | To parse custom shop_template.jsonc (you can define on it custom content like a welcome message !!!)

## Saves FTPD sync

The server will comunicate with the NSW that have connected throught tinfoil for list games in some time on past.

> How sync workflow works :

![Save Sync Diagram](/.diagrams/save%20sync.drawio.png)
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"local-devices": "^4.0.0",
"local-ip-address": "^1.0.0",
"lodash": "^4.17.21",
"mkdirp": "^3.0.1",
"public-ip": "^6.0.1",
"serve-index": "^1.9.1",
"supports-color": "^9.3.1",
Expand Down
6 changes: 4 additions & 2 deletions src/debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import debug from "debug";
var log = debug("tinfoil-hat");
var http = debug("tinfoil-hat:request");
var file = debug("tinfoil-hat:file");
var error = debug("tinfoil-hat:error");
var ftp = debug("tinfoil-hat:ftp");
var error = debug("tinfoil-hat:err");

export default {
http,
file,
log,
error: console.error,
ftp,
error,
};
13 changes: 8 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import shopFileBuilder from "./shop-file-builder.js";
import { romsDirPath, appPort, unauthorizedMessage } from "./helpers/envs.js";
import { afterStartFunction } from "./afterStartFunction.js";
import { getUsersFromEnv } from "./authUsersParser.js";
import FTPClient from "./modules/ftp-client.js";
import SaveSyncManager from "./modules/ftp-client.js";

const saveSyncManager = new SaveSyncManager();
const expressApp = express();
// Serve static files and interface
const BasicAuthUsers = getUsersFromEnv();
Expand All @@ -21,13 +22,14 @@ if (BasicAuthUsers) {
);
}

expressApp.use(shopFileBuilder);
expressApp.use(shopFileBuilder(saveSyncManager));

expressApp.use(express.static(path.join(romsDirPath)));
expressApp.use(
serveIndex(romsDirPath, {
icons: true,
hidden: true,
// will ignore . starting files like .hidden, .env ....
hidden: false,
// should ignore games folders only showing index files
// to avoid bug with not listing when have many games
filter: (filename, index, files) => {
Expand All @@ -36,6 +38,7 @@ expressApp.use(
})
);
const server = expressApp.listen(appPort, afterStartFunction(appPort));
const sync = new FTPClient();
await sync.start();

await saveSyncManager.start();

export default server;
Loading

0 comments on commit 2f95984

Please sign in to comment.