multiple-connection-handling (#3)

Reviewed-on: #3
This commit was merged in pull request #3.
This commit is contained in:
2026-03-08 18:05:34 -04:00
parent 56acf92f75
commit c034999d20
8 changed files with 191 additions and 29 deletions
+28 -15
View File
@@ -7,13 +7,26 @@
*/
const API_BASE = import.meta.env.VITE_API_BASE || '';
import { pendingRequests } from './stores.js';
/**
* Wrapper around fetch that tracks the number of pending requests globally
*/
async function trackedFetch(url, options = {}) {
pendingRequests.update(n => n + 1);
try {
return await fetch(url, options);
} finally {
pendingRequests.update(n => Math.max(0, n - 1));
}
}
/**
* Fetch system information from the ESP32.
* @returns {Promise<{chip: string, freeHeap: number, uptime: number, firmware: string, connection: string}>}
*/
export async function getSystemInfo() {
const res = await fetch(`${API_BASE}/api/system/info`);
const res = await trackedFetch(`${API_BASE}/api/system/info`);
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
@@ -29,7 +42,7 @@ export async function getSystemInfo() {
* @returns {Promise<{message: string}>}
*/
export async function reboot() {
const res = await fetch(`${API_BASE}/api/system/reboot`, {
const res = await trackedFetch(`${API_BASE}/api/system/reboot`, {
method: 'POST',
});
if (!res.ok) {
@@ -43,7 +56,7 @@ export async function reboot() {
* @returns {Promise<{active_slot: number, active_partition: string, target_partition: string, partitions: any[], running_firmware_label: string, running_firmware_slot: number}>}
*/
export async function getOTAStatus() {
const res = await fetch(`${API_BASE}/api/ota/status`);
const res = await trackedFetch(`${API_BASE}/api/ota/status`);
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
@@ -56,7 +69,7 @@ export async function getOTAStatus() {
* @returns {Promise<{status: string, message: string}>}
*/
export async function uploadOTAFrontend(file) {
const res = await fetch(`${API_BASE}/api/ota/frontend`, {
const res = await trackedFetch(`${API_BASE}/api/ota/frontend`, {
method: 'POST',
body: file, // Send the raw file Blob/Buffer
headers: {
@@ -79,7 +92,7 @@ export async function uploadOTAFrontend(file) {
* @returns {Promise<{status: string, message: string}>}
*/
export async function uploadOTAFirmware(file) {
const res = await fetch(`${API_BASE}/api/ota/firmware`, {
const res = await trackedFetch(`${API_BASE}/api/ota/firmware`, {
method: 'POST',
body: file,
headers: {
@@ -101,7 +114,7 @@ export async function uploadOTAFirmware(file) {
* @returns {Promise<{status: string, message: string}>}
*/
export async function uploadOTABundle(file) {
const res = await fetch(`${API_BASE}/api/ota/bundle`, {
const res = await trackedFetch(`${API_BASE}/api/ota/bundle`, {
method: 'POST',
body: file,
headers: {
@@ -124,7 +137,7 @@ export async function uploadOTABundle(file) {
* @returns {Promise<Array<{id: number, name: string}>>}
*/
export async function getUsers() {
const res = await fetch(`${API_BASE}/api/users`);
const res = await trackedFetch(`${API_BASE}/api/users`);
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
return res.json();
}
@@ -135,7 +148,7 @@ export async function getUsers() {
* @returns {Promise<{id: number, name: string}>}
*/
export async function addUser(name) {
const res = await fetch(`${API_BASE}/api/users`, {
const res = await trackedFetch(`${API_BASE}/api/users`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name })
@@ -153,7 +166,7 @@ export async function addUser(name) {
* @returns {Promise<{status: string}>}
*/
export async function removeUser(id) {
const res = await fetch(`${API_BASE}/api/users?id=${id}`, {
const res = await trackedFetch(`${API_BASE}/api/users?id=${id}`, {
method: 'DELETE'
});
if (!res.ok) {
@@ -170,7 +183,7 @@ export async function removeUser(id) {
* @returns {Promise<{status: string}>}
*/
export async function updateUser(id, name) {
const res = await fetch(`${API_BASE}/api/users/update`, {
const res = await trackedFetch(`${API_BASE}/api/users/update`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, name })
@@ -190,7 +203,7 @@ export async function updateUser(id, name) {
* @returns {Promise<Array<{id: number, user_id: number, title: string, due_date: number, completed: boolean}>>}
*/
export async function getTasks(userId) {
const res = await fetch(`${API_BASE}/api/tasks?user_id=${userId}`);
const res = await trackedFetch(`${API_BASE}/api/tasks?user_id=${userId}`);
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
return res.json();
}
@@ -200,7 +213,7 @@ export async function getTasks(userId) {
* @returns {Promise<{users: Array<{id: number, name: string, tasks: Array}>}>}
*/
export async function getUpcomingTasks() {
const res = await fetch(`${API_BASE}/api/tasks/upcoming`);
const res = await trackedFetch(`${API_BASE}/api/tasks/upcoming`);
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
return res.json();
}
@@ -213,7 +226,7 @@ export async function getUpcomingTasks() {
* @returns {Promise<{id: number, user_id: number, title: string, due_date: number, completed: boolean}>}
*/
export async function addTask(userId, title, dueDate) {
const res = await fetch(`${API_BASE}/api/tasks`, {
const res = await trackedFetch(`${API_BASE}/api/tasks`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_id: userId, title, due_date: dueDate })
@@ -232,7 +245,7 @@ export async function addTask(userId, title, dueDate) {
* @returns {Promise<{status: string}>}
*/
export async function updateTask(id, fields) {
const res = await fetch(`${API_BASE}/api/tasks/update`, {
const res = await trackedFetch(`${API_BASE}/api/tasks/update`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, ...fields })
@@ -250,7 +263,7 @@ export async function updateTask(id, fields) {
* @returns {Promise<{status: string}>}
*/
export async function deleteTask(id) {
const res = await fetch(`${API_BASE}/api/tasks?id=${id}`, {
const res = await trackedFetch(`${API_BASE}/api/tasks?id=${id}`, {
method: 'DELETE'
});
if (!res.ok) {