remove und rename ins protokoll eingefügt (firmware)

This commit is contained in:
2026-03-17 16:11:52 +01:00
parent 735129d83d
commit 7c7f19a4b7
3 changed files with 147 additions and 11 deletions

View File

@@ -40,6 +40,8 @@ enum buzz_data_type
BUZZ_DATA_FILE_PUT = 0x21, BUZZ_DATA_FILE_PUT = 0x21,
BUZZ_DATA_TAGS_GET = 0x22, BUZZ_DATA_TAGS_GET = 0x22,
BUZZ_DATA_TAGS_PUT = 0x23, BUZZ_DATA_TAGS_PUT = 0x23,
BUZZ_DATA_RM_FILE = 0x24,
BUZZ_DATA_RENAME_FILE = 0x25,
BUZZ_DATA_FW_UPDATE = 0x30, BUZZ_DATA_FW_UPDATE = 0x30,
@@ -98,6 +100,23 @@ struct __attribute__((packed)) buzz_resp_fs_info
uint8_t data[]; /* Pfadnamen */ uint8_t data[]; /* Pfadnamen */
}; };
/* Payload für das Entfernen einer Datei */
struct __attribute__((packed)) buzz_rm_file_payload
{
uint8_t data_type; /* BUZZ_DATA_RM_FILE */
uint8_t path_length;
char path[]; /* Variabler String ohne Null-Terminierung */
};
/* Payload für das Umbenennen einer Datei */
struct __attribute__((packed)) buzz_rename_file_payload
{
uint8_t data_type; /* BUZZ_DATA_RENAME_FILE */
uint8_t old_path_length;
uint8_t new_path_length;
char paths[]; /* Variabler String ohne Null-Terminierung */
};
/* Payload für das Credit-System (ACK) */ /* Payload für das Credit-System (ACK) */
struct __attribute__((packed)) buzz_ack_payload struct __attribute__((packed)) buzz_ack_payload
{ {

View File

@@ -382,6 +382,113 @@ static void handle_file_get_request(struct buzz_frame_msg *msg, bool only_tags)
} }
} }
static void process_rm_request(struct buzz_frame_msg *msg)
{
struct buzz_proto_header *hdr = (struct buzz_proto_header *)msg->data_ptr;
uint16_t payload_len = sys_le16_to_cpu(hdr->payload_length);
struct buzz_rm_file_payload *req = (struct buzz_rm_file_payload *)(msg->data_ptr + sizeof(*hdr));
if (payload_len < (sizeof(req->data_type) + sizeof(req->path_length)))
{
LOG_ERR("Invalid payload for RM_FILE request");
send_error_frame(msg, EINVAL);
return;
}
if ((sizeof(req->data_type) + sizeof(req->path_length) + req->path_length) != payload_len)
{
LOG_ERR("Path length in RM_FILE does not match payload length");
send_error_frame(msg, EINVAL);
return;
}
if (req->path_length >= sizeof(src_path))
{
LOG_ERR("Path too long for RM_FILE request");
send_error_frame(msg, ENAMETOOLONG);
return;
}
memcpy(src_path, req->path, req->path_length);
src_path[req->path_length] = '\0';
int rc = fs_mgmt_pm_unlink(src_path);
if (rc != 0)
{
LOG_ERR("Failed to remove file '%s': %d", src_path, rc);
send_error_frame(msg, abs(rc));
return;
}
LOG_INF("File '%s' removed successfully", src_path);
hdr->frame_type = BUZZ_FRAME_SUCCESS;
hdr->payload_length = sys_cpu_to_le16(sizeof(struct buzz_resp_success));
struct buzz_resp_success *resp_data = (struct buzz_resp_success *)(msg->data_ptr + sizeof(*hdr));
resp_data->data_type = BUZZ_DATA_RM_FILE;
if (msg->reply_cb)
{
msg->reply_cb(msg->data_ptr, sizeof(*hdr) + sizeof(*resp_data));
}
}
static void process_move_request(struct buzz_frame_msg *msg)
{
struct buzz_proto_header *hdr = (struct buzz_proto_header *)msg->data_ptr;
uint16_t payload_len = sys_le16_to_cpu(hdr->payload_length);
struct buzz_rename_file_payload *req = (struct buzz_rename_file_payload *)(msg->data_ptr + sizeof(*hdr));
if (payload_len < (sizeof(req->data_type) + sizeof(req->old_path_length) + sizeof(req->new_path_length)))
{
LOG_ERR("Invalid payload for RENAME_FILE request");
send_error_frame(msg, EINVAL);
return;
}
if ((sizeof(req->data_type) + sizeof(req->old_path_length) + sizeof(req->new_path_length) + req->old_path_length + req->new_path_length) != payload_len)
{
LOG_ERR("Path lengths in RENAME_FILE do not match payload length");
send_error_frame(msg, EINVAL);
return;
}
if (req->old_path_length >= sizeof(src_path) || req->new_path_length >= sizeof(dst_path))
{
LOG_ERR("Source or destination path too long for RENAME_FILE request");
send_error_frame(msg, ENAMETOOLONG);
return;
}
memcpy(src_path, req->paths, req->old_path_length);
src_path[req->old_path_length] = '\0';
memcpy(dst_path, req->paths + req->old_path_length, req->new_path_length);
dst_path[req->new_path_length] = '\0';
int rc = fs_mgmt_pm_rename(src_path, dst_path);
if (rc != 0)
{
LOG_ERR("Failed to rename file from '%s' to '%s': %d", src_path, dst_path, rc);
send_error_frame(msg, abs(rc));
return;
}
LOG_INF("File renamed from '%s' to '%s' successfully", src_path, dst_path);
hdr->frame_type = BUZZ_FRAME_SUCCESS;
hdr->payload_length = sys_cpu_to_le16(sizeof(struct buzz_resp_success));
struct buzz_resp_success *resp_data = (struct buzz_resp_success *)(msg->data_ptr + sizeof(*hdr));
resp_data->data_type = BUZZ_DATA_RENAME_FILE;
if (msg->reply_cb)
{
msg->reply_cb(msg->data_ptr, sizeof(*hdr) + sizeof(*resp_data));
}
}
static void process_file_get_stream(void) static void process_file_get_stream(void)
{ {
uint8_t *buf = NULL; uint8_t *buf = NULL;
@@ -595,12 +702,22 @@ static void handle_request(struct buzz_frame_msg *msg)
send_error_frame(msg, EBUSY); send_error_frame(msg, EBUSY);
} }
break; break;
case BUZZ_DATA_TAGS_GET: case BUZZ_DATA_TAGS_GET:
LOG_DBG("Received TAGS_GET Request"); LOG_DBG("Received TAGS_GET Request");
handle_file_get_request(msg, true); handle_file_get_request(msg, true);
break; break;
case BUZZ_DATA_RM_FILE:
LOG_DBG("Received RM_FILE Request");
process_rm_request(msg);
break;
case BUZZ_DATA_RENAME_FILE:
LOG_DBG("Received RENAME_FILE Request");
process_move_request(msg);
break;
default: default:
LOG_WRN("Unknown request data_type: 0x%02x", req_data->data_type); LOG_WRN("Unknown request data_type: 0x%02x", req_data->data_type);
send_error_frame(msg, EINVAL); send_error_frame(msg, EINVAL);

View File

@@ -40,7 +40,7 @@ export async function refreshRemote() {
const audioFiles = await fetchDirectory(currentFsInfo?.audioPath || "/lfs/a"); const audioFiles = await fetchDirectory(currentFsInfo?.audioPath || "/lfs/a");
let mappedAudio = audioFiles.map(mapToBuzzerFile); let mappedAudio = audioFiles.map(mapToBuzzerFile);
// Dateien sofort im UI anzeigen, bevor die Tags geladen sind // Dateien sofort im UI anzeigen, bevor die Tags geladen sind
buzzerAudioFiles.set([...mappedAudio]); buzzerAudioFiles.set([...mappedAudio]);
@@ -52,7 +52,7 @@ export async function refreshRemote() {
mappedAudio[i].sysTags = tags.sysTags; mappedAudio[i].sysTags = tags.sysTags;
mappedAudio[i].metaTags = tags.metaTags; mappedAudio[i].metaTags = tags.metaTags;
mappedAudio[i].tagsLoaded = true; mappedAudio[i].tagsLoaded = true;
// Store aktualisieren, um das UI pro Datei neu zu rendern // Store aktualisieren, um das UI pro Datei neu zu rendern
buzzerAudioFiles.set([...mappedAudio]); buzzerAudioFiles.set([...mappedAudio]);
} catch (error) { } catch (error) {
@@ -72,7 +72,7 @@ export async function refreshLocal() {
isFetchingLocal.set(true); isFetchingLocal.set(true);
try { try {
const dbFiles = await getLocalFiles(); const dbFiles = await getLocalFiles();
// Paralleles Parsen aller Blobs in der lokalen Datenbank // Paralleles Parsen aller Blobs in der lokalen Datenbank
const files: BuzzerFile[] = await Promise.all(dbFiles.map(async (record) => { const files: BuzzerFile[] = await Promise.all(dbFiles.map(async (record) => {
const { sysTags, metaTags } = await parseAudioFileTags(record.blob, record.name); const { sysTags, metaTags } = await parseAudioFileTags(record.blob, record.name);
@@ -87,7 +87,7 @@ export async function refreshLocal() {
selected: false, selected: false,
}; };
})); }));
localAudioFiles.set(files); localAudioFiles.set(files);
} catch (error) { } catch (error) {
console.error("Fehler beim Laden der lokalen Datenbank:", error); console.error("Fehler beim Laden der lokalen Datenbank:", error);
@@ -119,11 +119,11 @@ export async function downloadSelectedFiles() {
isFetchingRemote.set(true); isFetchingRemote.set(true);
try { try {
for (const file of files) { for (const file of files) {
console.debug(`Starte Download von: ${file.name}`); console.debug(`Starte Download von: ${file.name}`);
transferStats.update(s => ({ ...s, pendingFileName: file.name })); transferStats.update(s => ({ ...s, pendingFileName: file.name }));
const fullPath = `${pathPrefix}/${file.name}`; const fullPath = `${pathPrefix}/${file.name}`;
await new Promise(r => setTimeout(r, SETTINGS.ui.transferUpdateIntervalMs)); // Kurze Verzögerung für UI-Update await new Promise(r => setTimeout(r, SETTINGS.ui.transferUpdateIntervalMs)); // Kurze Verzögerung für UI-Update
await getFile(fullPath); await getFile(fullPath);
@@ -156,7 +156,7 @@ export async function deleteSelectedLocalFiles() {
for (const file of selectedFiles) { for (const file of selectedFiles) {
await deleteLocalFile(file.name); await deleteLocalFile(file.name);
} }
await refreshLocal(); await refreshLocal();
} catch (error) { } catch (error) {
console.error("Fehler beim Löschen lokaler Dateien:", error); console.error("Fehler beim Löschen lokaler Dateien:", error);
@@ -196,8 +196,8 @@ export async function uploadSelectedFiles() {
} }
const fullPath = `${pathPrefix}/${file.name}`; const fullPath = `${pathPrefix}/${file.name}`;
await new Promise(r => setTimeout(r, SETTINGS.ui.transferUpdateIntervalMs)); await new Promise(r => setTimeout(r, SETTINGS.ui.transferUpdateIntervalMs));
await putFile(dbRecord.blob, fullPath, file.name); await putFile(dbRecord.blob, fullPath, file.name);
} }
@@ -205,7 +205,7 @@ export async function uploadSelectedFiles() {
const avgSpeedKbs = ((totalBytes / 1024) / totalTimeSec).toFixed(1); const avgSpeedKbs = ((totalBytes / 1024) / totalTimeSec).toFixed(1);
addToast(` ${files.length === 1 ? "Eine Datei" : files.length + " Dateien"} erfolgreich hochgeladen. (${avgSpeedKbs} kB/s)`, "success"); addToast(` ${files.length === 1 ? "Eine Datei" : files.length + " Dateien"} erfolgreich hochgeladen. (${avgSpeedKbs} kB/s)`, "success");
// Buzzer-Ansicht nach erfolgreichem Upload aktualisieren // Buzzer-Ansicht nach erfolgreichem Upload aktualisieren
refreshRemote(); refreshRemote();
} catch (error) { } catch (error) {