📂 Adds filesystem service
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
import Settings from '~icons/mdi/settings';
|
import Settings from '~icons/mdi/settings';
|
||||||
import MdiController from '~icons/mdi/controller';
|
import MdiController from '~icons/mdi/controller';
|
||||||
import Health from '~icons/mdi/stethoscope';
|
import Health from '~icons/mdi/stethoscope';
|
||||||
|
import Folder from '~icons/mdi/folder-outline';
|
||||||
import Update from '~icons/mdi/reload';
|
import Update from '~icons/mdi/reload';
|
||||||
import WiFi from '~icons/mdi/wifi';
|
import WiFi from '~icons/mdi/wifi';
|
||||||
import Router from '~icons/mdi/router';
|
import Router from '~icons/mdi/router';
|
||||||
@@ -111,6 +112,13 @@
|
|||||||
feature: true,
|
feature: true,
|
||||||
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'File System',
|
||||||
|
icon: Folder,
|
||||||
|
href: '/system/filesystem',
|
||||||
|
feature: true,
|
||||||
|
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'System Metrics',
|
title: 'System Metrics',
|
||||||
icon: Metrics,
|
icon: Metrics,
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
import FileSystem from './FileSystem.svelte';
|
||||||
|
|
||||||
|
export let data: PageData;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="mx-0 my-1 flex flex-col space-y-4 sm:mx-8 sm:my-8">
|
||||||
|
<FileSystem />
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import type { PageLoad } from './$types';
|
||||||
|
|
||||||
|
export const load = (async () => {
|
||||||
|
return { title: 'File System' };
|
||||||
|
}) satisfies PageLoad;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<script>
|
||||||
|
import FileIcon from '~icons/mdi/file';
|
||||||
|
export let name;
|
||||||
|
// $: type = name.slice(name.lastIndexOf('.') + 1);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span class="flex pl-4 gap-2 items-center"><FileIcon/>{name}</span>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<script>
|
||||||
|
import SettingsCard from "$lib/components/SettingsCard.svelte";
|
||||||
|
import Spinner from "$lib/components/Spinner.svelte";
|
||||||
|
import FolderIcon from '~icons/mdi/folder-outline';
|
||||||
|
import Folder from "./Folder.svelte";
|
||||||
|
|
||||||
|
const getFiles = async () => {
|
||||||
|
const response = await fetch('/api/files/list');
|
||||||
|
if (response.ok) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<SettingsCard collapsible={false}>
|
||||||
|
<FolderIcon slot="icon" class="lex-shrink-0 mr-2 h-6 w-6 self-end" />
|
||||||
|
<span slot="title">File System</span>
|
||||||
|
<div class="w-full overflow-x-auto">
|
||||||
|
{#await getFiles()}
|
||||||
|
<Spinner />
|
||||||
|
{:then files}
|
||||||
|
<Folder name="/" files={files.root} expanded />
|
||||||
|
{/await}
|
||||||
|
</div>
|
||||||
|
</SettingsCard>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<script>
|
||||||
|
import File from './File.svelte';
|
||||||
|
import FolderIcon from '~icons/mdi/folder-outline';
|
||||||
|
import FolderOpenOutline from '~icons/mdi/folder-open-outline';
|
||||||
|
|
||||||
|
export let expanded = false;
|
||||||
|
export let name;
|
||||||
|
export let files;
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
expanded = !expanded;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button class="flex pl-2" on:click={toggle}>
|
||||||
|
{#if expanded}
|
||||||
|
<FolderOpenOutline class="w-6 h-6" />
|
||||||
|
{:else}
|
||||||
|
<FolderIcon class="w-6 h-6" />
|
||||||
|
{/if}
|
||||||
|
{name}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#if expanded}
|
||||||
|
<ul class="ml-5 border-l border-slate-600">
|
||||||
|
{#each Object.entries(files) as [name, content]}
|
||||||
|
<li class="p-1">
|
||||||
|
{#if typeof content == 'object'}
|
||||||
|
<svelte:self {name} files={content} />
|
||||||
|
{:else}
|
||||||
|
<File {name} />
|
||||||
|
{/if}
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
@@ -52,7 +52,8 @@ ESP32SvelteKit::ESP32SvelteKit(PsychicHttpServer *server, unsigned int numberEnd
|
|||||||
#endif
|
#endif
|
||||||
_restartService(server, &_securitySettingsService),
|
_restartService(server, &_securitySettingsService),
|
||||||
_factoryResetService(server, &ESPFS, &_securitySettingsService),
|
_factoryResetService(server, &ESPFS, &_securitySettingsService),
|
||||||
_systemStatus(server, &_securitySettingsService) {
|
_systemStatus(server, &_securitySettingsService),
|
||||||
|
_fileExplorer(server, &_securitySettingsService){
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP32SvelteKit::begin() {
|
void ESP32SvelteKit::begin() {
|
||||||
@@ -178,8 +179,8 @@ void ESP32SvelteKit::startServices() {
|
|||||||
#if FT_ENABLED(FT_BATTERY)
|
#if FT_ENABLED(FT_BATTERY)
|
||||||
_batteryService.begin();
|
_batteryService.begin();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_taskManager.begin();
|
_taskManager.begin();
|
||||||
|
_fileExplorer.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP32SvelteKit::_loop() {
|
void ESP32SvelteKit::_loop() {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <AnalyticsService.h>
|
#include <AnalyticsService.h>
|
||||||
#include <AuthenticationService.h>
|
#include <AuthenticationService.h>
|
||||||
#include <BatteryService.h>
|
#include <BatteryService.h>
|
||||||
|
#include <FileExplorerService.h>
|
||||||
#include <DownloadFirmwareService.h>
|
#include <DownloadFirmwareService.h>
|
||||||
#include <ESPFS.h>
|
#include <ESPFS.h>
|
||||||
#include <ESPmDNS.h>
|
#include <ESPmDNS.h>
|
||||||
@@ -153,6 +154,11 @@ public:
|
|||||||
return &_taskManager;
|
return &_taskManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileExplorer *getFileExplorer()
|
||||||
|
{
|
||||||
|
return &_fileExplorer;
|
||||||
|
}
|
||||||
|
|
||||||
void factoryReset()
|
void factoryReset()
|
||||||
{
|
{
|
||||||
_factoryResetService.factoryReset();
|
_factoryResetService.factoryReset();
|
||||||
@@ -209,6 +215,7 @@ private:
|
|||||||
FactoryResetService _factoryResetService;
|
FactoryResetService _factoryResetService;
|
||||||
SystemStatus _systemStatus;
|
SystemStatus _systemStatus;
|
||||||
TaskManager _taskManager;
|
TaskManager _taskManager;
|
||||||
|
FileExplorer _fileExplorer;
|
||||||
|
|
||||||
String _appName = APP_NAME;
|
String _appName = APP_NAME;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#ifndef FileExplorer_h
|
||||||
|
#define FileExplorer_h
|
||||||
|
|
||||||
|
#include <ESPFS.h>
|
||||||
|
#include <PsychicHttp.h>
|
||||||
|
#include <SecurityManager.h>
|
||||||
|
|
||||||
|
#define FILE_EXPLORER_SERVICE_PATH "/api/files/list"
|
||||||
|
|
||||||
|
class FileExplorer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileExplorer(PsychicHttpServer *server, SecurityManager *securityManager)
|
||||||
|
: _server(server), _securityManager(securityManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void begin()
|
||||||
|
{
|
||||||
|
_server->on(FILE_EXPLORER_SERVICE_PATH, HTTP_GET,
|
||||||
|
_securityManager->wrapRequest(std::bind(&FileExplorer::explore, this, std::placeholders::_1),
|
||||||
|
AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
|
|
||||||
|
ESP_LOGV("APStatus", "Registered GET endpoint: %s", FILE_EXPLORER_SERVICE_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PsychicHttpServer *_server;
|
||||||
|
SecurityManager *_securityManager;
|
||||||
|
esp_err_t explore(PsychicRequest *request)
|
||||||
|
{
|
||||||
|
return request->reply(200, "application/json", listFiles("/").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
String listFiles(const String &directory, bool isRoot = true)
|
||||||
|
{
|
||||||
|
File root = ESPFS.open(directory.startsWith("/") ? directory : "/" + directory);
|
||||||
|
if (!root.isDirectory())
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = root.openNextFile();
|
||||||
|
String output = isRoot ? "{ \"root\": {" : "{";
|
||||||
|
|
||||||
|
while (file)
|
||||||
|
{
|
||||||
|
if (file.isDirectory())
|
||||||
|
{
|
||||||
|
output += "\"" + String(file.name()) + "\": " + listFiles(file.name(), false) + ", ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
output += "\"" + String(file.name()) + "\": " + String(file.size()) + ", ";
|
||||||
|
}
|
||||||
|
file = root.openNextFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output.endsWith(", "))
|
||||||
|
{
|
||||||
|
output.remove(output.length() - 2);
|
||||||
|
}
|
||||||
|
output += "}";
|
||||||
|
if (isRoot)
|
||||||
|
{
|
||||||
|
output += "}";
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // end FileExplorer_h
|
||||||
Reference in New Issue
Block a user