Files
OSIT-AE-App-Svelte/src/lib/element_websocket_v2.svelte

439 lines
14 KiB
Svelte

<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte';
export let log_lvl: number = 0;
export let ws_connect: boolean = false;
export let ws_connect_status: null|string = null;
export let ws_server = 'dev-api.oneskyit.com';
export let base_url = `wss://${ws_server}/ws`;
export let group_id = 'ae-grp-99';
export let client_id = Date.now();
export let cmd: null|string = null;
export let msg: null|string = null;
export let type: null|string = null; // msg, cmd, json, hello, bye
export let trigger_send: any = null;
export let classes: string = 'container p-1 bg-pink-100 text-xs mx-auto pb-16 mb-20 sm:mb-12 md:mb-8';
export let hide__ws_form: boolean = true;
export let hide__ws_messages: boolean = false;
export let hide__ws_commands: boolean = false;
// *** Set initial variables
const dispatch = createEventDispatcher();
// JSON formatted data
let ws_data = {
'client_id': null, // The device or browser ID if available.
// 'src': null, // Sending client
// 'account_id': null, // Essentially the person ID or user ID if available.
// 'dest': null, // Destination client
'target': 'echo', // echo, dm (direct), grp (group), all (broadcast)
'type': 'cmd', // msg, cmd, json, hello, bye
// 'grp': null, // Destination group
'msg': null, // Message string
'cmd': null, // Command string
// 'data': null,
// 'b64': null,
}
let ws_received_list_cmd: string[] = [];
let ws_received_list_other: any[] = [];
let ws_received_list_msg: string[] = [];
onMount(async () => {
console.log('** Component Mounted: ** Element Websocket v2');
});
function ws_connect_group_id({group_id, client_id}) {
console.log(`${base_url}/group/${group_id}/client/${client_id}`);
let ws_connection = new WebSocket(`${base_url}/group/${group_id}/client/${client_id}`);
ws_connection.onopen = function() {
console.log('WS: connected');
ws_connect_status = 'connected';
dispatch('ws_conn', {
'status': 'connected'
});
// ws_connection.send(JSON.stringify({
// client_id: client_id,
// target: 'echo',
// type: 'hello',
// group_id: group_id,
// msg: 'You are connected!'
// }));
ws_connection.send(JSON.stringify({
client_id: client_id,
target: 'all',
type: 'hello',
group_id: group_id,
msg: `Client ${client_id.toString().slice(-5)} connected!`
}));
};
ws_connection.onmessage = function(event) {
if (log_lvl) {
console.log('WS: message received', event);
}
let ws_recv_data = JSON.parse(event.data);
if (log_lvl) {
console.log('WS: Received data:', ws_recv_data);
}
if (client_id == ws_recv_data.client_id) {
if (log_lvl) {
console.log('WS: Message received was sent by self and is an echo that can be ignored.');
}
return false;
}
if (ws_recv_data.type == 'cmd') {
console.log(`WS: Type CMD: ${ws_recv_data.cmd}`);
ws_received_list_cmd.unshift(ws_recv_data); // Add to the beginning of the list
// ws_received_list_cmd.push(ws_recv_data); // Add to the end of the list
ws_received_list_cmd = ws_received_list_cmd; // trigger Svelte update -2024-10-04
} else {
console.log('WS: Type other');
ws_received_list_other.unshift(ws_recv_data); // Add to the beginning of the list
// ws_received_list_other.push(ws_recv_data); // Add to the end of the list
ws_received_list_other = ws_received_list_other; // trigger Svelte update -2024-10-04
}
dispatch('ws_recv', {
// 'client_id': ws_data.client_id, // The device or browser ID if available.
'src': ws_recv_data.client_id, // The device or browser ID if available.
// 'account_id': ws_recv_data.account_id, // Essentially the person ID or user ID if available.
'dest': group_id, // Destination client
'target': ws_recv_data.target, // echo, dm (direct), grp (group), all (broadcast)
'type': ws_recv_data.type, // Message type (msg, cmd, json, hello, bye)
// 'grp': ws_recv_data.grp, // Destination group
'msg': ws_recv_data.msg, // Message string
'cmd': ws_recv_data.cmd, // Command string
});
};
ws_connection.onclose = function(event) {
console.log('WS: connection closed');
ws_connection.send(JSON.stringify({
client_id: client_id,
target: 'all',
type: 'hello',
group_id: group_id,
msg: `Client ${client_id} is disconnecting!`
}));
ws_connect_status = 'disconnected';
let fake_ws_recv_data = {
'client_id': client_id,
'target': 'local',
'type': 'bye',
'group_id': group_id,
'msg': `LOCAL Client ${client_id} has disconnected!`
};
ws_received_list_other.unshift(fake_ws_recv_data);
ws_received_list_other = ws_received_list_other; // trigger Svelte update -2024-10-04
dispatch('ws_conn', {
'status': 'disconnected'
});
if (ws_connect) {
setTimeout(function() {
console.log('WS: Disconnected... Try again!');
ws_connect_group_id({group_id: group_id, client_id: client_id});
console.log('WS: Again done?');
}, 1000);
}
};
ws_connection.onerror = function(event) {
console.log('WS: connection error???');
ws_connection.send(JSON.stringify({
client_id: client_id,
target: 'all',
type: 'hello',
group_id: group_id,
msg: `Client ${client_id} is having trouble?!`
}));
};
// NOTE WARNING: Uncommenting this seems to break FastAPI somehow???
// NOTE: from FastAPI log: RuntimeError: Unexpected ASGI message 'websocket.send', after sending 'websocket.close'.
// ws_connection.onerror = function(err) {
// console.error('WS socket error: ', err.message, 'Closing socket');
// // ws_connection.close();
// };
return ws_connection;
}
// Start the WS function
let ws_group: any = null;
$: if (ws_connect && group_id) {
ws_group = ws_connect_group_id({group_id: group_id, client_id: client_id});
} else {
ws_group?.close();
}
$: if (trigger_send && cmd) {
trigger_send = null;
console.log('WS: Send triggered!');
console.log(cmd);
ws_data.target = 'group';
ws_data.type = 'cmd';
ws_data.cmd = cmd;
handle_send_ws_data();
cmd = '';
}
function handle_send_ws_data() {
console.log(ws_data);
if (!ws_data) {
return false;
}
if (!ws_group) {
console.log('WS: No connection!');
return false;
}
let ws_data_json_str = JSON.stringify(ws_data);
let resp = ws_group.send(ws_data_json_str);
console.log(resp);
dispatch('ws_sent', {
// 'client_id': ws_data.client_id, // The device or browser ID if available.
'src': ws_data.client_id, // The device or browser ID if available.
// 'account_id': ws_data.account_id, // Essentially the person ID or user ID if available.
'dest': group_id, // Destination client
'group_id': group_id,
'target': ws_data.target, // echo, dm (direct), grp (group), all (broadcast)
'type': ws_data.type, // Message type (msg, cmd, json, hello, bye)
// 'grp': ws_data.grp, // Destination group
'msg': ws_data.msg, // Message string
'cmd': ws_data.cmd, // Command string
});
cmd = '';
msg = '';
}
</script>
<section class="ae_element__websocket container p-1 bg-pink-100 text-xs mx-auto pb-16 mt-32 mb-32 relative">
<span class="absolute top-0 right-0 flex flex-col gap-1">
<button
type="button"
on:click={() => {
hide__ws_form = !hide__ws_form;
}}
class="btn btn-sm text-xs hover:variant-filled-tertiary"
class:variant-soft-tertiary={hide__ws_form}
class:variant-filled-tertiary={!hide__ws_form}
>
{#if hide__ws_form}
Show Form
{:else}
Hide Form?
{/if}
</button>
<button
type="button"
on:click={() => {
hide__ws_messages = !hide__ws_messages;
}}
class="btn btn-sm text-xs hover:variant-filled-tertiary"
class:variant-soft-tertiary={hide__ws_messages}
class:variant-filled-tertiary={!hide__ws_messages}
>
{#if hide__ws_messages}
Show Messages
{:else}
Hide Messages?
{/if}
</button>
<button
type="button"
on:click={() => {
hide__ws_commands = !hide__ws_commands;
}}
class="btn btn-sm text-xs hover:variant-filled-tertiary"
class:variant-soft-tertiary={hide__ws_commands}
class:variant-filled-tertiary={!hide__ws_commands}
>
{#if hide__ws_commands}
Show Commands
{:else}
Hide Commands?
{/if}
</button>
</span>
<header>
<h1 class="h6 text-center">Websocket Messages &amp; Commands</h1>
</header>
<!-- <form on:submit|preventDefault={handle_send_message}>
<select bind:value={type}>
<option value="">None</option>
<option value="echo">Echo</option>
<option value="dm">Direct Message</option>
<option value="group">Group Message</option>
<option value="all">Broadcast to All</option>
<option value="cmd">Command</option>
</select>
<select bind:value={group_id}>
<option value="">None</option>
<option value="test_grp_123">123</option>
<option value="test_grp_999">999</option>
<option value="test_grp_poster">A Poster Group</option>
</select>
<input type="text" bind:value={message_text} placeholder="Your message"/>
<button>Send</button>
</form> -->
{#if !hide__ws_form}
<form
on:submit|preventDefault={handle_send_ws_data}
>
<select
bind:value={ws_data.type}
class="input text-sm w-24"
>
<option value="">None</option>
<option value="echo">Echo</option>
<option value="dm">Direct Message</option>
<option value="group">Group Message</option>
<option value="all">Broadcast to All</option>
<option value="cmd">Command</option>
</select>
<input type="text" bind:value={group_id} placeholder="Group ID" class="input text-sm w-36" />
<!-- <select bind:value={group_id}>
<option value="">None</option>
<option value="test_grp_123">123</option>
<option value="test_grp_999">999</option>
<option value="test_grp_poster">A Poster Group</option>
</select> -->
<!-- <input type="text" bind:value={dm_client_id} placeholder="Direct message client ID"/> -->
<input type="text" bind:value={ws_data.cmd} placeholder="Your command" class="input text-sm w-36" />
<input type="text" bind:value={ws_data.msg} placeholder="Your message" class="input text-xs w-96" />
<button
type="submit"
class="btn btn-sm variant-soft-warning"
>Send Group</button>
</form>
{/if}
<!-- <pre>
ae_load:event_session=jEG9APQRUs8 (Poster Session #3: Work Never Ends - Pythagoras)
ae_open:event_file=CHqU5sW7xbc (jpg)
ae_open:event_file=Kljq0uiTlXt (video)
</pre> -->
<!-- <hr> -->
<section
class:hidden={hide__ws_messages}
>
<h2 class="text-center underline">Messages [grp, client, target, type]</h2>
<ol class="list-decimal list-outside max-h-24 overflow-y-auto messages">
{#each ws_received_list_other as msg_entry, index}
<li
class="ml-4"
>
<div
class="flex flex-row justify-between gap-1 w-full"
>
<span>
[{(msg_entry.group_id||'No Group ID')}]
{(msg_entry.client_id.toString().slice(-5)||'No Client ID')}
&ndash;
{(msg_entry.target||'No Target')}
|
<!-- &ndash; -->
{(msg_entry.type||'No Type')}:
</span>
<span class="justify-self-end">
"{msg_entry.msg}"
</span>
<!-- <br>{JSON.stringify(msg_entry)} -->
</div>
</li>
{/each}
</ol>
</section> <!-- End Messages -->
<hr>
<section
class:hidden={hide__ws_commands}
>
<h2 class="text-center underline">Commands</h2>
<ol class="list-decimal list-outside max-h-24 overflow-y-auto commands">
{#each ws_received_list_cmd as cmd_entry}
<li
class="ml-4"
>
<div
class="flex flex-row justify-between gap-1 w-full"
>
<span>
[{(cmd_entry.group_id||'No Group ID')}]
{(cmd_entry.client_id.toString().slice(-5)||'No Client ID')}
&mdash;
{(cmd_entry.target||'No Target')}
|
<!-- &mdash; -->
{(cmd_entry.type||'No Type')}:
</span>
<span class="justify-self-end">
"{cmd_entry.cmd}"
</span>
</div>
</li>
{/each}
</ol>
</section> <!-- End Commands -->
</section>
<style>
/* .websocket_element {
background-color: white;
border-top: dashed medium gray;
color: gray;
font-size: .7em;
}
.websocket_element header {
font-size: .7em;
}
.websocket_element h2 {
font-size: .9em;
} */
</style>