mirror of
https://codeberg.org/PLG-Development/PLG-MuDiCS
synced 2026-07-06 00:47:09 +00:00
chore(control): follow api docs, improve api code structure
This commit is contained in:
@@ -1,10 +1,12 @@
|
|||||||
import { notifications } from "./stores/notification";
|
import { notifications } from "./stores/notification";
|
||||||
import { to_display_status, type DisplayStatus, type FolderElement, type TreeElement } from "./types";
|
import { to_display_status, type DisplayStatus, type FolderElement, type RequestResponse, type ShellCommandResponse, type TreeElement } from "./types";
|
||||||
import { get_uuid } from "./utils";
|
import { get_uuid } from "./utils";
|
||||||
|
|
||||||
export async function get_screenshot(ip: string): Promise<Blob|null> {
|
export async function get_screenshot(ip: string): Promise<Blob | null> {
|
||||||
const options = { method: 'PATCH' };
|
const options = { method: 'PATCH' };
|
||||||
return await request_display(ip, '/takeScreenshot', options);
|
const response = await request_display(ip, '/takeScreenshot', options);
|
||||||
|
if (!response.ok || !response.blob) return null;
|
||||||
|
return response.blob;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function open_file(ip: string, path_to_file: string): Promise<void> {
|
export async function open_file(ip: string, path_to_file: string): Promise<void> {
|
||||||
@@ -47,11 +49,11 @@ done
|
|||||||
` })
|
` })
|
||||||
};
|
};
|
||||||
const raw_response = await request_display(ip, '/shellCommand', options);
|
const raw_response = await request_display(ip, '/shellCommand', options);
|
||||||
if (is_cd_directory_error(ip, raw_response)) {
|
if (!raw_response.ok || !raw_response.json) return [];
|
||||||
return [];
|
const json_response = raw_response.json as ShellCommandResponse;
|
||||||
}
|
if (is_cd_directory_error(ip, json_response)) return [];
|
||||||
|
|
||||||
const response: FileInfo[] = raw_response.stdout.trim()
|
const response: FileInfo[] = json_response.stdout.trim()
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.map((line: string) => JSON.parse(line) as FileInfo);
|
.map((line: string) => JSON.parse(line) as FileInfo);
|
||||||
@@ -84,15 +86,16 @@ export async function get_file_tree_data(ip: string, path: string): Promise<Tree
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
const raw_response = await request_display(ip, '/shellCommand', options);
|
const raw_response = await request_display(ip, '/shellCommand', options);
|
||||||
if (is_cd_directory_error(ip, raw_response)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (JSON.parse(raw_response.stdout.trim()) as [TreeElement, any])[0].contents || null;
|
if (!raw_response.ok || !raw_response.json) return null;
|
||||||
|
const json_response = raw_response.json as ShellCommandResponse;
|
||||||
|
if (is_cd_directory_error(ip, json_response)) return null;
|
||||||
|
|
||||||
|
return (JSON.parse(json_response.stdout.trim()) as [TreeElement, any])[0].contents || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function show_blackscreen(ip: string) {
|
export async function show_blackscreen(ip: string): Promise<void> {
|
||||||
const options = {
|
const options = {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: { 'content-type': 'application/json' },
|
headers: { 'content-type': 'application/json' },
|
||||||
@@ -106,70 +109,82 @@ export async function show_blackscreen(ip: string) {
|
|||||||
|
|
||||||
export async function ping_ip(ip: string): Promise<DisplayStatus> {
|
export async function ping_ip(ip: string): Promise<DisplayStatus> {
|
||||||
const raw_response = await request_control(`/ping?ip=${ip}`, { method: 'GET' });
|
const raw_response = await request_control(`/ping?ip=${ip}`, { method: 'GET' });
|
||||||
if (!raw_response) return null;
|
if (!raw_response.ok || !raw_response.json) return null;
|
||||||
return raw_response.status ? to_display_status(raw_response.status) : null;
|
return raw_response.json.status ? to_display_status(raw_response.json.status) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get_thumbnail_blob(ip: string, path_to_file: string): Promise<Blob|null> {
|
export async function get_thumbnail_blob(ip: string, path_to_file: string): Promise<Blob | null> {
|
||||||
const raw_response = await request_display(ip, `/file/preview${path_to_file}`, { method: 'GET' });
|
const raw_response = await request_display(ip, `/file/preview${path_to_file}`, { method: 'GET' }, [415]);
|
||||||
return raw_response;
|
if (!raw_response.ok || !raw_response.blob) return null
|
||||||
|
return raw_response.blob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function request_display(ip: string, api_route: string, options: { method: string, headers?: Record<string, string>, body?: any }): Promise<null | any> {
|
async function request_display(ip: string, api_route: string, options: { method: string, headers?: Record<string, string>, body?: any }, supress_error_handling_http_codes: number[] = []): Promise<RequestResponse> {
|
||||||
const url = `http://${ip}:1323/api${api_route}`;
|
const url = `http://${ip}:1323/api${api_route}`;
|
||||||
return await raw_request(url, options);
|
return await request(url, options, supress_error_handling_http_codes);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function request_control(api_route: string, options: { method: string, headers?: Record<string, string>, body?: any }): Promise<null | any> {
|
async function request_control(api_route: string, options: { method: string, headers?: Record<string, string>, body?: any }): Promise<RequestResponse> {
|
||||||
const url = `${window.location.origin}/api${api_route}`;
|
const url = `${window.location.origin}/api${api_route}`;
|
||||||
return await raw_request(url, options);
|
return await request(url, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function raw_request(url: string, options: { method: string, headers?: Record<string, string>, body?: any }): Promise<null | any> {
|
async function request(url: string, options: { method: string, headers?: Record<string, string>, body?: any }, supress_error_handling_http_codes: number[] = []): Promise<RequestResponse> {
|
||||||
try {
|
try {
|
||||||
const cache_buster = `${url.includes('?') ? '&' : '?'}=${Date.now()}`;
|
const cache_buster = `${url.includes('?') ? '&' : '?'}=${Date.now()}`;
|
||||||
console.log(url + cache_buster)
|
console.log(url + cache_buster)
|
||||||
const response = await fetch(url + cache_buster, options);
|
const response = await fetch(url + cache_buster, options);
|
||||||
if (!response.ok) {
|
if (response.ok || supress_error_handling_http_codes.includes(response.status)) {
|
||||||
console.error(`HTTP error! Status: ${response.status}`);
|
const contentType = response.headers.get("content-type") || "";
|
||||||
notifications.push("error", `HTTP-Fehler bei API-Anfrage`, `${url}\nHTTP-Status: ${response.status}`);
|
let request_response: RequestResponse;
|
||||||
}
|
if (!contentType.includes("application/json")) {
|
||||||
const contentType = response.headers.get("content-type") || "";
|
const blob: Blob = await response.blob();
|
||||||
if (!contentType.includes("application/json")) {
|
request_response = { ok: response.ok, http_code: response.status, blob: blob };
|
||||||
return await response.blob();
|
} else {
|
||||||
} else {
|
const json: Object = await response.json();
|
||||||
const json = await response.json();
|
request_response = { ok: response.ok, http_code: response.status, json: json };
|
||||||
if (json.error && json.error !== '') {
|
|
||||||
notifications.push("error", `Interner Fehler bei API-Anfrage`, `${url}\nJSON: ${JSON.stringify(json)}`);
|
|
||||||
}
|
}
|
||||||
return json;
|
console.log(request_response);
|
||||||
|
return request_response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let error_description: string;
|
||||||
|
try {
|
||||||
|
const json: { description: string } = await response.json();
|
||||||
|
error_description = json.description;
|
||||||
|
} catch (error_on_json_parsing: any) {
|
||||||
|
error_description = `unknown error: ${error_on_json_parsing}`;
|
||||||
|
}
|
||||||
|
console.error(url, error_description);
|
||||||
|
notifications.push("error", `Fehler ${response.status} bei API-Anfrage`, `${url}\nFehler: ${error_description}`);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error instanceof TypeError && /fetch|NetworkError/i.test(error.message)) {
|
if (error instanceof TypeError && /fetch|NetworkError/i.test(error.message)) {
|
||||||
console.log("Request failed - Is the targeted device online?")
|
console.log("Request failed - Is the targeted device online?")
|
||||||
} else {
|
} else {
|
||||||
console.error(error);
|
console.error(url, error);
|
||||||
notifications.push("error", `Fehler bei API-Anfrage`, `${url}\nFehler: ${error}`);
|
notifications.push("error", `Fataler Fehler bei API-Anfrage`, `${url}\nFehler: ${error}`);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return { ok: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_cd_directory_error(ip: string, raw_response: any): boolean {
|
|
||||||
if (!raw_response) return true;
|
|
||||||
if (raw_response.exitCode !== 0) {
|
|
||||||
if (raw_response.stderr && /bash: line \d+: cd: .+: No such file or directory/.test(raw_response.stderr)) {
|
function is_cd_directory_error(ip: string, shell_response: ShellCommandResponse): boolean {
|
||||||
|
if (shell_response.exitCode !== 0) {
|
||||||
|
if (shell_response.stderr && /bash: line \d+: cd: .+: No such file or directory/.test(shell_response.stderr)) {
|
||||||
console.log("current file_path does not exist on display:", ip);
|
console.log("current file_path does not exist on display:", ip);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
console.error(raw_response);
|
console.error(shell_response);
|
||||||
notifications.push("error", "Fehler in ShellCommand", `Fehlercode: ${raw_response.exitCode}\nFehler: ${raw_response.stderr ?? ''}`)
|
notifications.push("error", "Fehler in ShellCommand", `Fehlercode: ${shell_response.exitCode}\nFehler: ${shell_response.stderr ?? ''}`)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (raw_response.stdout.trim() === '') return true;
|
if (shell_response.stdout.trim() === '') return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { get, writable, type Writable } from "svelte/store";
|
import { get, writable, type Writable } from "svelte/store";
|
||||||
import { get_thumbnail_blob } from "../api_handler";
|
import { get_thumbnail_blob } from "../api_handler";
|
||||||
import { type FolderElement } from "../types";
|
import { type FolderElement } from "../types";
|
||||||
import { db } from "../indexdb/file_thumbnails.db";
|
import { db, type ThumbnailBlobDBEntry } from "../indexdb/file_thumbnails.db";
|
||||||
import { get_file_type } from "../utils";
|
import { get_file_type } from "../utils";
|
||||||
|
|
||||||
export const active_thumbnail_urls: Writable<string[]> = writable<string[]>([]);
|
export const active_thumbnail_urls: Writable<string[]> = writable<string[]>([]);
|
||||||
@@ -17,9 +17,9 @@ export async function generate_thumbnail(display_ip: string, path: string, folde
|
|||||||
await db.thumbnail_blobs.add({ hash: hash, blob: thumbnail_blob });
|
await db.thumbnail_blobs.add({ hash: hash, blob: thumbnail_blob });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get_thumbnail_url(hash: string): Promise<string | null> {
|
export async function get_thumbnail_url(hash: string | null): Promise<string | null> {
|
||||||
if (hash === null) return null;
|
if (hash === null) return null;
|
||||||
const thumbnail_blob = await db.thumbnail_blobs.get(hash);
|
const thumbnail_blob = await db.thumbnail_blobs.get(hash) as ThumbnailBlobDBEntry;
|
||||||
if (!thumbnail_blob) return null;
|
if (!thumbnail_blob) return null;
|
||||||
const new_url = URL.createObjectURL(thumbnail_blob.blob);
|
const new_url = URL.createObjectURL(thumbnail_blob.blob);
|
||||||
active_thumbnail_urls.update((current: string[]) => {
|
active_thumbnail_urls.update((current: string[]) => {
|
||||||
|
|||||||
@@ -1,6 +1,19 @@
|
|||||||
import { FileBox, FileImage, FileText, FileVideoCamera, ImagePlay, type X } from "lucide-svelte";
|
import { FileBox, FileImage, FileText, FileVideoCamera, ImagePlay, type X } from "lucide-svelte";
|
||||||
import type { Snippet } from "svelte";
|
import type { Snippet } from "svelte";
|
||||||
|
|
||||||
|
export type RequestResponse = {
|
||||||
|
ok: boolean,
|
||||||
|
http_code?: number
|
||||||
|
blob?: Blob,
|
||||||
|
json?: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ShellCommandResponse = {
|
||||||
|
stdout: string,
|
||||||
|
stderr: string,
|
||||||
|
exitCode: number,
|
||||||
|
}
|
||||||
|
|
||||||
export type SupportedFileType = {
|
export type SupportedFileType = {
|
||||||
display_name: string;
|
display_name: string;
|
||||||
mime_type: string;
|
mime_type: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user