Cleaned up the frame.ts by splitting payload parsing to subpackages

This commit is contained in:
2026-03-20 10:38:36 +01:00
parent 1aa8eb363f
commit 75e31c2008
26 changed files with 2695 additions and 2429 deletions

135
src/payload.thirdparty.ts Normal file
View File

@@ -0,0 +1,135 @@
import { FieldType, type Segment } from "@hamradio/packet";
import { Frame } from "./frame";
import { DataType, type Payload, type ThirdPartyPayload, UserDefinedPayload } from "./frame.types";
export const decodeUserDefinedPayload = (
raw: string,
withStructure: boolean = false
): {
payload: Payload | null;
segment?: Segment[];
} => {
try {
if (raw.length < 2) return { payload: null };
// content after '{'
const rest = raw.substring(1);
// user packet type is first token (up to first space) often like '01' or 'TYP'
const match = rest.match(/^([^\s]+)\s*(.*)$/s);
let userPacketType = "";
let data = "";
if (match) {
userPacketType = match[1] || "";
data = (match[2] || "").trim();
}
const payload: UserDefinedPayload = {
type: DataType.UserDefined,
userPacketType,
data
} as const;
if (withStructure) {
const segments: Segment[] = [];
segments.push({
name: "user-defined",
data: new TextEncoder().encode(rest).buffer,
isString: true,
fields: [{ type: FieldType.STRING, name: "raw", length: rest.length }]
});
segments.push({
name: "user-packet-type",
data: new TextEncoder().encode(userPacketType).buffer,
isString: true,
fields: [
{
type: FieldType.STRING,
name: "type",
length: userPacketType.length
}
]
});
segments.push({
name: "user-data",
data: new TextEncoder().encode(data).buffer,
isString: true,
fields: [{ type: FieldType.STRING, name: "data", length: data.length }]
});
return { payload, segment: segments };
}
return { payload };
} catch {
return { payload: null };
}
};
export const decodeThirdPartyPayload = (
raw: string,
withStructure: boolean = false
): {
payload: Payload | null;
segment?: Segment[];
} => {
try {
if (raw.length < 2) return { payload: null };
// Content after '}' is the encapsulated third-party frame or raw data
const rest = raw.substring(1);
// Attempt to parse the embedded text as a full APRS frame (route:payload)
let nestedFrame: Frame | undefined;
try {
// parseFrame is defined in this module; use Frame.parse to attempt parse
nestedFrame = Frame.parse(rest);
} catch {
nestedFrame = undefined;
}
const payload: ThirdPartyPayload = {
type: DataType.ThirdParty,
comment: rest,
...(nestedFrame ? { frame: nestedFrame } : {})
} as const;
if (withStructure) {
const segments: Segment[] = [];
segments.push({
name: "third-party",
data: new TextEncoder().encode(rest).buffer,
isString: true,
fields: [{ type: FieldType.STRING, name: "raw", length: rest.length }]
});
if (nestedFrame) {
// Include a short section pointing to the nested frame's data (stringified)
const nf = nestedFrame;
const nfStr = `${nf.source.toString()}>${nf.destination.toString()}:${nf.payload}`;
segments.push({
name: "third-party-nested-frame",
data: new TextEncoder().encode(nfStr).buffer,
isString: true,
fields: [
{
type: FieldType.STRING,
name: "nested",
length: nfStr.length
}
]
});
}
return { payload, segment: segments };
}
return { payload };
} catch {
return { payload: null };
}
};