blob: 4754c70f494d3aced08d8e6098d82de62972e536 [file] [log] [blame]
<script lang="ts">
import Button from '../Button.svelte';
import Select from '../Select.svelte';
import { decoderRegistry } from './decoders/utils/decoderRegistry';
import { decodeBase64 } from '$lib/utils/base64Utils';
interface Props {
payload?: string | undefined;
codec?: string | undefined | null;
}
let { payload = undefined, codec = undefined }: Props = $props();
type ErrorState = { title: string; message: string };
type DecodedState =
| { status: 'idle'; forceChangeDecoder: boolean }
| { status: 'error'; error: ErrorState }
| { status: 'success'; content: string };
let decodeState = $state<DecodedState>({ status: 'idle', forceChangeDecoder: false });
let showRaw = $state(false);
let selectedDecoder = $state(codec || 'string');
function getError(type: 'no_payload' | 'unsupported_codec' | 'invalid_format'): ErrorState {
switch (type) {
case 'no_payload':
return {
title: 'No payload',
message: 'This message has no payload to decode'
};
case 'unsupported_codec':
return {
title: 'Unsupported codec',
message: `The specified codec ${codec} is not supported. Select another decoder from the dropdown below.`
};
case 'invalid_format':
return {
title: 'Invalid format',
message: `The payload is not valid ${selectedDecoder.toUpperCase()}`
};
}
}
function decode() {
if (!payload) {
decodeState = { status: 'error', error: getError('no_payload') };
return;
}
const decodedPayload = decodeBase64(payload);
if (!decodedPayload) {
decodeState = { status: 'error', error: getError('invalid_format') };
return;
}
const decoder = decoderRegistry.get(selectedDecoder);
if (!decoder) {
decodeState = { status: 'error', error: getError('unsupported_codec') };
return;
}
const content = decoder.decode(decodedPayload);
if (!content) {
decodeState = { status: 'error', error: getError('invalid_format') };
return;
}
decodeState = { status: 'success', content };
}
</script>
{#if decodeState.status === 'idle'}
{#if !codec || !decoderRegistry.get(codec) || decodeState.forceChangeDecoder}
<div class="mb-4">
<Select
label="Select decoder"
name="decoder"
options={decoderRegistry.getNames()}
bind:value={selectedDecoder}
/>
</div>
{/if}
<Button variant="contained" onclick={decode}>Decode</Button>
{:else}
{#if decodeState.status === 'error'}
<div class="bg-red-100 dark:bg-red-900 p-4 rounded-md w-full">
<p class="font-bold">{decodeState.error.title}</p>
<p>{decodeState.error.message}</p>
</div>
{/if}
{#if decodeState.status === 'success'}
<div class="flex items-center gap-3">
<p class="font-bold">Codec: {selectedDecoder}</p>
<Button variant="text" onclick={() => (decodeState = { status: 'idle', forceChangeDecoder: true })}>Change decoder</Button>
</div>
<div class="w-full mt-2">
<pre class="bg-gray-100 dark:bg-gray-800 p-1 rounded-md overflow-auto"><code
>{decodeState.content}</code
></pre>
</div>
{/if}
<div class="mt-4 mb-2">
<Button variant="text" onclick={() => (showRaw = !showRaw)}>
{showRaw ? 'Hide' : 'Show'} raw payload (base64)
</Button>
</div>
{#if showRaw && payload}
<div class="w-full">
<pre
class="bg-gray-100 dark:bg-gray-800 p-4 rounded-md overflow-auto whitespace-pre-wrap break-all"><code
>{payload}</code
></pre>
</div>
{/if}
{/if}