[+] Complete transfer logic

pull/131/head
Azalea 2025-03-20 06:06:35 -04:00
parent c6af5b7d87
commit c93f47744b
2 changed files with 166 additions and 27 deletions

View File

@ -1,8 +1,9 @@
<script lang="ts">
import { slide } from "svelte/transition";
import { ts } from "../../libs/i18n";
import { t, ts } from "../../libs/i18n";
import TransferServer from "./TransferServer.svelte";
import { DATA_HOST } from "../../libs/config";
import type { ConfirmProps } from "../../libs/generalTypes";
let tabs = ['chu3', 'mai2', 'ongeki']
@ -13,16 +14,15 @@
}
let tab = 0
let src = JSON.parse(localStorage.getItem('src') ?? JSON.stringify({
dns: "",
card: "",
keychip: ""
}))
let dst = JSON.parse(localStorage.getItem('dst') ?? `{ card: "", server: "", keychip: "" }`)
let gameInfo = JSON.parse(localStorage.getItem('gameInfo') ?? JSON.stringify({
game: "",
version: "",
}))
let src = JSON.parse(localStorage.getItem('src') ?? `{"dns": "", "card": "", "keychip": ""}`)
let dst = JSON.parse(localStorage.getItem('dst') ?? `{"dns": "", "card": "", "keychip": ""}`)
let [srcTested, dstTested] = [false, false]
let gameInfo = JSON.parse(localStorage.getItem('gameInfo') ?? `{"game": "", "version": ""}`)
let srcEl: TransferServer, dstEl: TransferServer
let srcExportedData: string
let loading: boolean = false
let confirm: ConfirmProps | null = null
function defaultGame() {
gameInfo.game = game[tabs[tab]].game
@ -35,6 +35,27 @@
localStorage.setItem('gameInfo', JSON.stringify(gameInfo))
}
function startTransfer() {
if (!(srcTested && dstTested)) return alert("Please test both servers first!")
if (loading) return alert("Transfer already in progress!")
console.log("Starting transfer...")
loading = true
if (!dstEl.exportedData) {
// Ask user to make sure to backup their data
if (!confirm("It seems like you haven't backed up your destination data. Are you sure you want to proceed? (This will overwrite your destination server's data)")) {
loading = false
return
}
}
srcEl.pull()
.then(() => dstEl.push(srcExportedData))
.then(() => alert("Transfer successful!"))
.catch(e => alert(`Transfer failed: ${e}`))
.finally(() => loading = false)
}
defaultGame()
</script>
@ -56,15 +77,21 @@
<p>👋 Welcome to the AquaTrans™ server data transfer tool!</p>
<p>You can use this to export data from any server, and input data into any server using the connection credentials (card number, server address, and keychip id).</p>
<p>This tool will simulate a game client and pull your data from the source server, and push your data to the destination server.</p>
<p>Please fill out the form below to get started!</p>
<p>Please fill out the info below to get started!</p>
</div>
<TransferServer bind:src={src} bind:gameInfo={gameInfo} on:change={onChange}
bind:tested={srcTested} bind:this={srcEl} bind:exportedData={srcExportedData} />
<div class="arrow" class:disabled={!(srcTested && dstTested)}>
<img src="{DATA_HOST}/d/DownArrow.png" alt="arrow" on:click={startTransfer}>
</div>
<TransferServer bind:src={src} bind:gameInfo={gameInfo} on:change={onChange} />
<div class="arrow"><img src="{DATA_HOST}/d/DownArrow.png" alt="arrow"></div>
<TransferServer bind:src={dst} bind:gameInfo={gameInfo} on:change={onChange}
isSrc={false} />
bind:tested={dstTested} bind:this={dstEl} isSrc={false} />
</main>
<style lang="sass">
.arrow
width: 100%
@ -72,10 +99,13 @@
justify-content: center
margin-top: -40px
margin-bottom: -40px
z-index: 0
z-index: 1
&.disabled
filter: grayscale(1)
// CSS animation to let the image opacity breathe
.arrow img
img
animation: breathe 1s infinite alternate
@keyframes breathe

View File

@ -1,18 +1,90 @@
<script lang="ts">
import StatusOverlays from "../../components/StatusOverlays.svelte";
import { TRANSFER } from "../../libs/sdk";
import { download, selectJsonFile } from "../../libs/ui";
import InputTextShort from "./InputTextShort.svelte";
export let src: AllNetSrc
export let gameInfo: AllNetGame
export let isSrc: boolean = true
let tested: boolean = false
export let tested: boolean = false
let [loading, error, expectedError] = [false, "", ""]
function testConnection() {
if (loading) return
// Preliminiary checks
if (!src.dns || !src.keychip || !src.card || !gameInfo.game || !gameInfo.version) {
error = "Please fill out all fields"
return
}
loading = true
console.log("Testing connection...")
TRANSFER.check({...src, ...gameInfo}).then(res => {
console.log("Connection test result:", res)
tested = true
}).catch(err => expectedError = err.message).finally(() => loading = false)
}
let messages: string[] = []
export let exportedData: string = ""
export function pull(): Promise<string> {
return new Promise<string>((resolve, reject) => {
if (loading || !tested) return reject("Please test connection first")
if (exportedData) return resolve(exportedData)
console.log("Exporting data...")
TRANSFER.pull({...src, ...gameInfo}, (msg: TrStreamMessage) => {
console.log("Export progress: ", JSON.stringify(msg))
if ('message' in msg) messages = [...messages, msg.message]
if ('error' in msg) {
expectedError = msg.error
reject(msg.error)
}
if ('data' in msg) {
// file name: Export YYYY-MM-DD {server host} {game} {card last 6}.json
let date = new Date().toISOString().split('T')[0]
let host = new URL(src.dns).hostname
download(msg.data, `Export ${date} ${host} ${gameInfo.game} ${src.card.slice(-6)}.json`)
exportedData = msg.data
resolve(msg.data)
}
}).catch(err => { expectedError = err; reject(err) })
})
}
function pushBtn() {
if (loading || !tested) return
selectJsonFile().then(obj => push(JSON.stringify(obj)))
}
export function push(data: string) {
if (loading || !tested) return
console.log("Import data...")
loading = true
TRANSFER.push({...src, ...gameInfo}, data).then(() => {
console.log("Data imported successfully")
messages = ["Data imported successfully"]
}).catch(err => expectedError = err.message).finally(() => loading = false)
}
</script>
<div class="server source" class:src={isSrc}>
<StatusOverlays {loading} {error} />
<div class="server source" class:src={isSrc} class:hasError={expectedError} class:tested={tested}>
<h3>{isSrc ? "Source" : "Target"} Server</h3>
{#if expectedError}
<blockquote class="error-msg">{expectedError}</blockquote>
{/if}
<!-- First input line -->
<div class="inputs">
<InputTextShort desc="Server Address" placeholder="e.g. http://aquadx.hydev.org"
@ -33,12 +105,22 @@
bind:value={src.card} on:change disabled={tested} />
</div>
<!-- Streaming messages -->
{#if messages.length > 0}
<div class="stream-messages">
{#each messages.slice(Math.max(messages.length - 5, 0), undefined) as msg}
<p>{msg}</p>
{/each}
</div>
{/if}
<!-- Buttons -->
<div class="inputs buttons">
{#if !tested}
<button class="flex-1" on:click={() => {}}>Test Connection</button>
<button class="flex-1" on:click={testConnection} disabled={loading}>Test Connection</button>
{:else}
<button class="flex-1" on:click={() => {}}>Export Data</button>
<button class="flex-1" on:click={pull}>Export Data</button>
<button class="flex-1" on:click={pushBtn}>Import Data</button>
{/if}
</div>
</div>
@ -47,14 +129,28 @@
@use "../../vars"
@use "sass:color"
.error-msg
white-space: pre-wrap
margin: 0
.server
display: flex
flex-direction: column
gap: 1rem
// --c-src: 202, 168, 252
--c-src: 179, 198, 255
// animation: hue-rotate 10s infinite linear
// &.src
// --c-src: 173, 192, 247
// animation: hue-rotate 10s infinite linear reverse
&.tested
--c-src: 169, 255, 186
&.hasError
--c-src: 255, 174, 174
&.src
--c-src: 173, 192, 247
animation: none
padding: 1rem
border-radius: vars.$border-radius
@ -71,6 +167,12 @@
text-align: center
// @keyframes hue-rotate
// 0%
// filter: hue-rotate(0deg)
// 100%
// filter: hue-rotate(360deg)
.inputs
display: flex
flex-wrap: wrap
@ -85,5 +187,12 @@
width: 100px
&.buttons
margin-top: 1rem
margin-top: 0.5rem
.stream-messages
font-size: 0.8rem
opacity: 0.8
margin-top: 0.5rem
padding: 0 0.5rem
</style>