feat(ws): add connection status and last updated time
This commit is contained in:
@@ -1,62 +1,62 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"number": 43,
|
"number": 76,
|
||||||
"timestamp": 1751904678378
|
"timestamp": 1751906592502
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 44,
|
|
||||||
"timestamp": 1751904688400
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 50,
|
|
||||||
"timestamp": 1751904698413
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 55,
|
|
||||||
"timestamp": 1751904708422
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 52,
|
|
||||||
"timestamp": 1751904718446
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 45,
|
|
||||||
"timestamp": 1751904728342
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 73,
|
|
||||||
"timestamp": 1751904738349
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 45,
|
|
||||||
"timestamp": 1751904748375
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 45,
|
|
||||||
"timestamp": 1751904758402
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 49,
|
|
||||||
"timestamp": 1751904768420
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 71,
|
|
||||||
"timestamp": 1751904778446
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 62,
|
|
||||||
"timestamp": 1751904788455
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 46,
|
|
||||||
"timestamp": 1751904798494
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"number": 46,
|
|
||||||
"timestamp": 1751904808488
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"number": 63,
|
"number": 63,
|
||||||
"timestamp": 1751904818496
|
"timestamp": 1751906602503
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 87,
|
||||||
|
"timestamp": 1751906612523
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 68,
|
||||||
|
"timestamp": 1751906622542
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 55,
|
||||||
|
"timestamp": 1751906632552
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 57,
|
||||||
|
"timestamp": 1751906642555
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 69,
|
||||||
|
"timestamp": 1751906652569
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 78,
|
||||||
|
"timestamp": 1751906662576
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 78,
|
||||||
|
"timestamp": 1751906672595
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 58,
|
||||||
|
"timestamp": 1751906682619
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 91,
|
||||||
|
"timestamp": 1751906692626
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 76,
|
||||||
|
"timestamp": 1751906702646
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 64,
|
||||||
|
"timestamp": 1751906712664
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 70,
|
||||||
|
"timestamp": 1751906722670
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"number": 68,
|
||||||
|
"timestamp": 1751906732689
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1,19 +1,14 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import LineChart from './components/LineChart.vue';
|
|
||||||
import { ref, onMounted, onUnmounted } from 'vue';
|
import { ref, onMounted, onUnmounted } from 'vue';
|
||||||
import { tryCatchSync } from './utils/tryCatch.js';
|
import LineChart from './components/LineChart.vue';
|
||||||
|
import tryCatchSync from './utils/tryCatch';
|
||||||
|
import formatTimestamp from './utils/formatDate';
|
||||||
|
|
||||||
const data = ref([]); // Handles data
|
const data = ref([]); // Handles data
|
||||||
const connected = ref(false); // Stores connection state
|
const connected = ref(false); // Stores connection state
|
||||||
let socket = null;
|
let socket = null;
|
||||||
|
|
||||||
// Start WS connection
|
// Function for webhook connection handling
|
||||||
onMounted(connectWebSocket);
|
|
||||||
onUnmounted(() => {
|
|
||||||
// Close socket when component gets unmounted
|
|
||||||
if (socket) socket.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
function connectWebSocket() {
|
function connectWebSocket() {
|
||||||
// Connect to WebSocket server
|
// Connect to WebSocket server
|
||||||
socket = new WebSocket('/ws');
|
socket = new WebSocket('/ws');
|
||||||
@@ -21,7 +16,6 @@
|
|||||||
// Event on connection
|
// Event on connection
|
||||||
socket.onopen = () => {
|
socket.onopen = () => {
|
||||||
connected.value = true;
|
connected.value = true;
|
||||||
console.log('Connected to websocker');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Event on data received
|
// Event on data received
|
||||||
@@ -30,6 +24,7 @@
|
|||||||
const { data: message, error: parseErr } = tryCatchSync(() => JSON.parse(event.data));
|
const { data: message, error: parseErr } = tryCatchSync(() => JSON.parse(event.data));
|
||||||
if (parseErr) {
|
if (parseErr) {
|
||||||
console.error(`[WS] Error while parsing `, parseErr);
|
console.error(`[WS] Error while parsing `, parseErr);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load data initial data, or update it
|
// Load data initial data, or update it
|
||||||
@@ -47,27 +42,50 @@
|
|||||||
data.value = data.value.slice(-15);
|
data.value = data.value.slice(-15);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
// No default behaviour for now
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Event on socket close
|
// Event on socket close
|
||||||
socket.onclose = () => {
|
socket.onclose = () => {
|
||||||
|
// Mark as disconnected, and retry connection in 5 seconds
|
||||||
connected.value = false;
|
connected.value = false;
|
||||||
console.warn('[WS] Disconnected, trying to reconnect in 5 seconds ...');
|
|
||||||
setTimeout(connectWebSocket, 5000);
|
setTimeout(connectWebSocket, 5000);
|
||||||
};
|
};
|
||||||
|
|
||||||
// On socket error
|
// On socket error
|
||||||
socket.onerror = (err) => {
|
socket.onerror = (err) => {
|
||||||
|
// Close socket on error, and print to console
|
||||||
console.error('[WS] Error: ', err);
|
console.error('[WS] Error: ', err);
|
||||||
socket.close();
|
socket.close();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start WS connection
|
||||||
|
onMounted(connectWebSocket);
|
||||||
|
onUnmounted(() => {
|
||||||
|
// Close socket when component gets unmounted
|
||||||
|
if (socket) socket.close();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<main class="container">
|
<main class="container">
|
||||||
<h1 class="text-primary">Live data from WebSocket</h1>
|
<h1 class="text-primary">Live data from WebSocket</h1>
|
||||||
|
<div class="connection-container">
|
||||||
|
<div :class="{ connected: connected }" class="circle" />
|
||||||
|
<p class="text-secondary">{{ connected ? 'Connected' : 'Disconnected' }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="data.length > 0" class="update-container">
|
||||||
|
<p class="text-secondary">
|
||||||
|
Last update:
|
||||||
|
<span class="text-primary">{{ formatTimestamp(data[data.length - 1].timestamp) }}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<LineChart :data="data" />
|
<LineChart :data="data" />
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
@@ -76,4 +94,31 @@
|
|||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.update-container {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.circle {
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
|
||||||
|
background-color: red;
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connected {
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
5
frontend/src/utils/formatDate.js
Normal file
5
frontend/src/utils/formatDate.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// Format timestamp into readable time
|
||||||
|
export default function formatTimestamp(timestamp) {
|
||||||
|
const date = new Date(timestamp);
|
||||||
|
return date.toLocaleString(); // or use toLocaleTimeString() for just the time
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
// function for sync
|
/**
|
||||||
export function tryCatchSync(callback) {
|
* A simple try/catch wrapper for synchronous code
|
||||||
|
*/
|
||||||
|
export default function tryCatchSync(callback) {
|
||||||
try {
|
try {
|
||||||
const data = callback();
|
const data = callback();
|
||||||
return { data, error: null };
|
return { data, error: null };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { data: null, error: error };
|
return { data: null, error };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user