show uptime

Changed files
+62 -7
src
+6 -6
src/App.svelte
··· 1 <script lang="ts"> 2 import { onMount } from 'svelte'; 3 - import { formatDistanceToNow, addSeconds, formatDate, formatISO9075 } from 'date-fns'; 4 import { Progress, Switch } from '@skeletonlabs/skeleton-svelte'; 5 import orderBy from "lodash/orderBy"; 6 import instancesData from './instances.json'; 7 - import numeral from 'numeral'; 8 9 const APP_TITLE = 'plcbundle instances' 10 const PLC_DIRECTORY = 'plc.directory' ··· 34 let instances = $state(instancesData.sort(() => Math.random() - 0.5)) 35 36 const instanceOrderBy = [['_head', 'status.latency'], ['desc', 'asc']] 37 - 38 - function formatNumber(n: number) { 39 - return numeral(n).format() 40 - } 41 42 async function getStatus(instance: Instance) { 43 let statusResp: object | undefined; ··· 206 <th>head</th> 207 <th>root</th> 208 <th>version</th> 209 <th>latency</th> 210 </tr> 211 </thead> ··· 219 <td><span class="font-mono text-xs {instance._head ? (isConflict ? 'text-error-600' : 'text-success-600') : 'opacity-50'}">{#if instance.status?.bundles?.head_hash}{instance.status?.bundles?.head_hash.slice(0, 7)}{/if}</span></td> 220 <td><span class="font-mono text-xs {instance.status ? (instance.status?.bundles?.root_hash === ROOT ? 'text-success-600' : 'text-error-600') : ''}">{#if instance.status?.bundles?.root_hash}{instance.status?.bundles?.root_hash.slice(0, 7)}{/if}</span></td> 221 <td>{#if instance.status?.server?.version}{instance.status?.server?.version}{/if}</td> 222 <td class="opacity-50">{#if instance.status?.latency}{Math.round(instance.status?.latency)}ms{/if}</td> 223 </tr> 224 {/each}
··· 1 <script lang="ts"> 2 import { onMount } from 'svelte'; 3 + import { formatDistanceToNow, addSeconds, subSeconds, formatDate, formatISO9075 } from 'date-fns'; 4 import { Progress, Switch } from '@skeletonlabs/skeleton-svelte'; 5 import orderBy from "lodash/orderBy"; 6 + import { formatNumber, formatUptime } from './lib/utils'; 7 import instancesData from './instances.json'; 8 9 const APP_TITLE = 'plcbundle instances' 10 const PLC_DIRECTORY = 'plc.directory' ··· 34 let instances = $state(instancesData.sort(() => Math.random() - 0.5)) 35 36 const instanceOrderBy = [['_head', 'status.latency'], ['desc', 'asc']] 37 38 async function getStatus(instance: Instance) { 39 let statusResp: object | undefined; ··· 202 <th>head</th> 203 <th>root</th> 204 <th>version</th> 205 + <th>ws?</th> 206 + <th>uptime</th> 207 <th>latency</th> 208 </tr> 209 </thead> ··· 217 <td><span class="font-mono text-xs {instance._head ? (isConflict ? 'text-error-600' : 'text-success-600') : 'opacity-50'}">{#if instance.status?.bundles?.head_hash}{instance.status?.bundles?.head_hash.slice(0, 7)}{/if}</span></td> 218 <td><span class="font-mono text-xs {instance.status ? (instance.status?.bundles?.root_hash === ROOT ? 'text-success-600' : 'text-error-600') : ''}">{#if instance.status?.bundles?.root_hash}{instance.status?.bundles?.root_hash.slice(0, 7)}{/if}</span></td> 219 <td>{#if instance.status?.server?.version}{instance.status?.server?.version}{/if}</td> 220 + <td>{#if instance.status?.server?.websocket_enabled}✔︎{:else if instance.status}<span class="opacity-25">-</span>{/if}</td> 221 + <td class="text-xs">{#if instance.status?.server?.uptime_seconds}{formatUptime(instance.status?.server?.uptime_seconds)}{/if}</td> 222 <td class="opacity-50">{#if instance.status?.latency}{Math.round(instance.status?.latency)}ms{/if}</td> 223 </tr> 224 {/each}
+3 -1
src/instances.json
··· 1 [ 2 { 3 - "url": "https://plcbundle.atscan.net" 4 }, 5 { 6 "url": "https://plc.j4ck.xyz"
··· 1 [ 2 { 3 + "url": "https://plcbundle.atscan.net", 4 + "country": "AT", 5 + "maintainer": "@tree.fail" 6 }, 7 { 8 "url": "https://plc.j4ck.xyz"
+53
src/lib/utils.ts
···
··· 1 + import numeral from 'numeral'; 2 + 3 + export function formatNumber(n: number) { 4 + return numeral(n).format() 5 + } 6 + 7 + export function formatUptime(totalSeconds: number): string { 8 + if (totalSeconds < 0) { 9 + return "Invalid input: seconds cannot be negative"; 10 + } 11 + if (totalSeconds === 0) { 12 + return "0s"; 13 + } 14 + 15 + let parts: string[] = []; 16 + let displayUnits: [string, number][]; 17 + 18 + const SECONDS_IN_MINUTE = 60; 19 + const SECONDS_IN_HOUR = 3600; // 60 minutes * 60 seconds/minute 20 + const SECONDS_IN_DAY = 24 * SECONDS_IN_HOUR; 21 + 22 + if (totalSeconds > SECONDS_IN_DAY) { // If uptime is bigger than 1 day 23 + displayUnits = [ 24 + ['d', SECONDS_IN_DAY], 25 + ['h', SECONDS_IN_HOUR], 26 + ]; 27 + } else if (totalSeconds > SECONDS_IN_MINUTE) { // If uptime is bigger than 60 seconds but not bigger than 60 minutes 28 + displayUnits = [ 29 + ['d', SECONDS_IN_DAY], 30 + ['h', SECONDS_IN_HOUR], 31 + ['m', SECONDS_IN_MINUTE], 32 + ]; 33 + } else { // If uptime is 60 seconds or less 34 + displayUnits = [ 35 + ['d', SECONDS_IN_DAY], 36 + ['h', SECONDS_IN_HOUR], 37 + ['m', SECONDS_IN_MINUTE], 38 + ['s', 1], 39 + ]; 40 + } 41 + 42 + let remainingSeconds = totalSeconds; 43 + 44 + for (const [unitChar, unitSeconds] of displayUnits) { 45 + if (remainingSeconds >= unitSeconds) { 46 + const value = Math.floor(remainingSeconds / unitSeconds); 47 + parts.push(`${value}${unitChar}`); 48 + remainingSeconds %= unitSeconds; 49 + } 50 + } 51 + 52 + return parts.join(""); 53 + }