core functionalities

This commit is contained in:
2024-02-07 15:03:12 +01:00
parent 6785ead452
commit 49152aa641
5 changed files with 131 additions and 14 deletions

View File

@@ -1,13 +1,53 @@
<script lang="ts">
import * as O from 'fp-ts/Option';
import { pipe } from 'fp-ts/lib/function';
import {
downloads,
httpPostRpcEndpoint,
rpcClient,
serverApiEndpoint,
websocketRpcEndpoint,
} from './lib/store';
import { datetimeCompareFunc, isRPCResponse } from './lib/utils';
rpcClient.subscribe(($client) => {
setInterval(() => $client.running(), 750);
$client.socket.onmessage = (ev: any) => {
const event = JSON.parse(ev.data);
// guards
if (!isRPCResponse(event)) {
return;
}
if (!Array.isArray(event.result)) {
return;
}
if (event.result) {
return downloads.set(
O.of(
event.result
.filter((f) => !!f.info.url)
.sort((a, b) =>
datetimeCompareFunc(b.info.created_at, a.info.created_at),
),
),
);
}
downloads.set(O.none);
};
});
</script>
<main>
{$serverApiEndpoint}
{$httpPostRpcEndpoint}
{$websocketRpcEndpoint}
<div class="flex flex-col gap-2 p-8">
{#each pipe( $downloads, O.getOrElseW(() => []), ) as download}
<div class="bg-neutral-100 p-4 rounded-lg shadow-lg">
<div>{download.id}</div>
<div>{JSON.stringify(download.info)}</div>
<div>{JSON.stringify(download.progress)}</div>
</div>
{/each}
</div>
</main>

View File

@@ -1,7 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
}
@tailwind utilities;

View File

@@ -1,6 +1,7 @@
import { derived, readable, writable } from 'svelte/store'
import { RPCClient } from './RPCClient'
import type { RPCResponse, RPCResult } from './types'
import * as O from 'fp-ts/lib/Option'
export const rpcHost = writable<string>(localStorage.getItem('rpcHost') ?? 'localhost')
export const rpcPort = writable<number>(Number(localStorage.getItem('rpcPort')) || 3033)
@@ -31,8 +32,4 @@ export const rpcClient = derived(
([$http, $ws, $token]) => new RPCClient($http, $ws, $token)
)
export const downloads = readable<RPCResponse<RPCResult[]>>({
id: '',
error: null,
result: [],
})
export const downloads = writable<O.Option<RPCResult[]>>(O.none)

84
ui/src/lib/utils.ts Normal file
View File

@@ -0,0 +1,84 @@
import { pipe } from 'fp-ts/lib/function'
import type { RPCResponse } from "./types"
/**
* Validate an ip v4 via regex
* @param {string} ipAddr
* @returns ip validity test
*/
export function validateIP(ipAddr: string): boolean {
let ipRegex = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/gm
return ipRegex.test(ipAddr)
}
export function validateDomain(url: string): boolean {
const urlRegex = /(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/
const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/
const [name, slug] = url.split('/')
return urlRegex.test(url) || name === 'localhost' && slugRegex.test(slug)
}
export function isValidURL(url: string): boolean {
let urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/
return urlRegex.test(url)
}
export function ellipsis(str: string, lim: number): string {
if (str) {
return str.length > lim ? `${str.substring(0, lim)}...` : str
}
return ''
}
export function toFormatArgs(codes: string[]): string {
if (codes.length > 1) {
return codes.reduce((v, a) => ` -f ${v}+${a}`)
}
if (codes.length === 1) {
return ` -f ${codes[0]}`
}
return ''
}
export const formatGiB = (bytes: number) =>
`${(bytes / 1_000_000_000).toFixed(0)}GiB`
export const roundMiB = (bytes: number) =>
`${(bytes / 1_000_000).toFixed(2)} MiB`
export const formatSpeedMiB = (val: number) =>
`${roundMiB(val)}/s`
export const datetimeCompareFunc = (a: string, b: string) =>
new Date(a).getTime() - new Date(b).getTime()
export function isRPCResponse(object: any): object is RPCResponse<any> {
return 'result' in object && 'id' in object
}
export function mapProcessStatus(status: number) {
switch (status) {
case 0:
return 'Pending'
case 1:
return 'Downloading'
case 2:
return 'Completed'
case 3:
return 'Error'
default:
return 'Pending'
}
}
export const prefersDarkMode = () =>
window.matchMedia('(prefers-color-scheme: dark)').matches
export const base64URLEncode = (s: string) => pipe(
s,
s => String.fromCodePoint(...new TextEncoder().encode(s)),
btoa,
encodeURIComponent
)

View File

@@ -2,7 +2,7 @@
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
"./src/**/*.{svelte,js,ts,jsx,tsx}",
],
theme: {
extend: {},