use server sent events instead of polling
All checks were successful
Build Container / Build Container (push) Successful in 1m27s
All checks were successful
Build Container / Build Container (push) Successful in 1m27s
This commit is contained in:
parent
8bc4e7f28e
commit
8281848215
2 changed files with 90 additions and 46 deletions
|
|
@ -89,6 +89,23 @@ export interface paths {
|
|||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/locks/stream": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Watch Locks */
|
||||
get: operations["watch_locks_api_locks_stream_get"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/locks/{lock_id}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -135,7 +152,7 @@ export interface components {
|
|||
* @description Statically known HTTP problem types using the [type URI scheme](https://datatracker.ietf.org/doc/rfc4151/)
|
||||
* @enum {string}
|
||||
*/
|
||||
HttpProblemType: "type:noc@hamburg.ccc.de,2026:UNAUTHORIZED" | "type:noc@hamburg.ccc.de,2026:LOCK_NOT_FOUND";
|
||||
HttpProblemType: "type:noc@hamburg.ccc.de,2026:UNAUTHORIZED" | "type:noc@hamburg.ccc.de,2026,FORBIDDEN_TO_OPERATE" | "type:noc@hamburg.ccc.de,2026:LOCK_NOT_FOUND";
|
||||
/** Lock */
|
||||
Lock: {
|
||||
/** Name */
|
||||
|
|
@ -178,14 +195,17 @@ export interface components {
|
|||
};
|
||||
/** UserStatus */
|
||||
UserStatus: {
|
||||
/** Is Logged In */
|
||||
is_logged_in: boolean;
|
||||
/** Is Authorized */
|
||||
is_authorized: boolean;
|
||||
/** Guaranteed Session Until */
|
||||
guaranteed_session_until: string | null;
|
||||
/**
|
||||
* Guaranteed Session Until
|
||||
* Format: date-time
|
||||
*/
|
||||
guaranteed_session_until: string;
|
||||
/** Username */
|
||||
username: string | null;
|
||||
username: string;
|
||||
/** Ccchh Roles */
|
||||
ccchh_roles: string[];
|
||||
};
|
||||
/** ValidationError */
|
||||
ValidationError: {
|
||||
|
|
@ -332,6 +352,35 @@ export interface operations {
|
|||
};
|
||||
};
|
||||
};
|
||||
watch_locks_api_locks_stream_get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"text/event-stream": unknown;
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"text/event-stream": components["schemas"]["HttpProblemDetail"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
operate_lock_api_locks__lock_id__patch: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -365,6 +414,15 @@ export interface operations {
|
|||
"application/json": components["schemas"]["HttpProblemDetail"];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HttpProblemDetail"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import {Fetcher} from "openapi-typescript-fetch"
|
||||
import type {paths} from "../api/schema"
|
||||
import type {components, paths} from "../api/schema"
|
||||
import type {ui} from "../i18n/ui.ts"
|
||||
|
||||
const fetcher = Fetcher.for<paths>()
|
||||
|
|
@ -29,7 +29,7 @@ declare global {
|
|||
lang: keyof typeof ui;
|
||||
doors: Array<DoorType>;
|
||||
auth: AuthType;
|
||||
doorAction: (action: 'unlock' | 'lock', doorId: string) => void;
|
||||
doorAction: (action: "unlock" | "lock", doorId: string) => void;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -105,18 +105,18 @@ async function checkUser() {
|
|||
if (e instanceof getUserInfo.Error) {
|
||||
const error = e.getActualType()
|
||||
|
||||
if (error.status === 401) {
|
||||
if (!auth.recentLogout)
|
||||
auth.recentLogout = auth.authenticated // set recentLogout true, if user was logged in before
|
||||
auth.authenticated = false
|
||||
auth.authorized = false
|
||||
auth.until = null
|
||||
auth.username = ""
|
||||
} else if (error.status >= 500 && error.status < 600) {
|
||||
|
||||
if (error.status >= 500 && error.status < 600) {
|
||||
apiError.current = "serverError"
|
||||
} else {
|
||||
console.error("unknown error:", error)
|
||||
}
|
||||
|
||||
if (!auth.recentLogout)
|
||||
auth.recentLogout = auth.authenticated // set recentLogout true, if user was logged in before
|
||||
auth.authenticated = false
|
||||
auth.authorized = false
|
||||
auth.until = null
|
||||
auth.username = ""
|
||||
|
||||
}
|
||||
} finally {
|
||||
localStorage.setItem("auth", JSON.stringify(auth))
|
||||
|
|
@ -125,15 +125,24 @@ async function checkUser() {
|
|||
}
|
||||
}
|
||||
|
||||
async function fetchDoors() {
|
||||
async function subscribeDoorEvents() {
|
||||
if (doors.length === 0) {
|
||||
loading.doors = true
|
||||
}
|
||||
refresh()
|
||||
const getDoors = fetcher.path("/api/locks/").method("get").create()
|
||||
|
||||
try {
|
||||
const {data: doorInfo} = await getDoors({})
|
||||
const evtSource = new EventSource("/api/locks/stream")
|
||||
|
||||
evtSource.onerror = () => {
|
||||
if (!window.navigator.onLine) {
|
||||
apiError.current = "networkError"
|
||||
} else {
|
||||
apiError.current = "serverError"
|
||||
}
|
||||
}
|
||||
|
||||
evtSource.onmessage = (event) => {
|
||||
const doorInfo: Array<components["schemas"]["Lock"]> = JSON.parse(event.data)
|
||||
|
||||
apiError.current = null
|
||||
while (doors.length) {
|
||||
|
|
@ -164,29 +173,6 @@ async function fetchDoors() {
|
|||
|
||||
loading.doors = false
|
||||
refresh()
|
||||
} catch (e) {
|
||||
// check which operation threw the exception
|
||||
if (e instanceof getDoors.Error) {
|
||||
const error = e.getActualType()
|
||||
|
||||
if (error.status === 401) {
|
||||
console.log("unauthorized")
|
||||
loading.doors = false
|
||||
refresh()
|
||||
} else if (error.status >= 500 && error.status < 600) {
|
||||
apiError.current = "serverError"
|
||||
clearInterval(doorsInterval)
|
||||
} else {
|
||||
console.error("unknown error:", error)
|
||||
}
|
||||
}
|
||||
|
||||
if (e instanceof Error) {
|
||||
switch (e.name) {
|
||||
case "TypeError":
|
||||
apiError.current = "networkError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -295,7 +281,7 @@ function refresh() {
|
|||
|
||||
|
||||
loadAuthFromLocalStorage()
|
||||
const doorsInterval = setInterval(fetchDoors, 250) // TODO: replace with SSE
|
||||
subscribeDoorEvents()
|
||||
checkUser()
|
||||
|
||||
document.addEventListener("loadeddata", () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue