mirror of
https://github.com/jwetzell/psn-js.git
synced 2026-08-05 15:33:45 +00:00
133 lines
4.1 KiB
TypeScript
133 lines
4.1 KiB
TypeScript
import { Decoders } from './index.js';
|
|
import {
|
|
type DataPacketChunk,
|
|
type InfoPacketChunk,
|
|
type Tracker,
|
|
TrackerFromData,
|
|
TrackerFromInfo,
|
|
} from './models/index.js';
|
|
|
|
export class Decoder {
|
|
infoPacketFrames: { [key: number]: InfoPacketChunk[] } = {};
|
|
|
|
dataPacketFrames: { [key: number]: DataPacketChunk[] } = {};
|
|
|
|
trackers: { [key: string]: Tracker } = {};
|
|
|
|
systemName: string = '';
|
|
|
|
updateInfo(framePackets: InfoPacketChunk[]) {
|
|
framePackets.forEach((packet) => {
|
|
if (packet.data.systemName?.data) {
|
|
this.systemName = packet.data.systemName?.data.systemName;
|
|
}
|
|
|
|
if (packet.data.trackerList?.data) {
|
|
packet.data.trackerList.data.trackers.forEach((infoTrackerChunk) => {
|
|
if (!this.trackers[infoTrackerChunk.chunk.header.id]) {
|
|
const tracker = TrackerFromInfo(infoTrackerChunk);
|
|
if (tracker) {
|
|
this.trackers[infoTrackerChunk.chunk.header.id] = tracker;
|
|
}
|
|
}
|
|
const tracker = this.trackers[infoTrackerChunk.chunk.header.id];
|
|
tracker.updateInfo(infoTrackerChunk);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
updateData(framePackets: DataPacketChunk[]) {
|
|
framePackets.forEach((packet) => {
|
|
if (packet.data.trackerList) {
|
|
packet.data.trackerList?.data.trackers.forEach((dataTrackerChunk) => {
|
|
if (!this.trackers[dataTrackerChunk.chunk.header.id]) {
|
|
const tracker = TrackerFromData(dataTrackerChunk);
|
|
if (tracker) {
|
|
this.trackers[dataTrackerChunk.chunk.header.id] = tracker;
|
|
}
|
|
}
|
|
const tracker = this.trackers[dataTrackerChunk.chunk.header.id];
|
|
tracker.updateData(dataTrackerChunk);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// TODO(jwetzell): add invalid frame id decoding. Scenario where a frame id is reused before one is complete
|
|
decode(packetBuf: Uint8Array) {
|
|
const packet = Decoders.Chunk(packetBuf);
|
|
if (packet === undefined) {
|
|
return packet;
|
|
}
|
|
|
|
if (packet.header.id === 0x6756) {
|
|
const infoPacket = Decoders.InfoPacketChunk(packetBuf);
|
|
if (infoPacket?.chunk.header.hasSubchunks) {
|
|
const currentInfoPacketHeader = infoPacket.data.packetHeader;
|
|
if (!currentInfoPacketHeader) {
|
|
// NOTE(jwetzell): not sure that info packets without a header subchunk are valid?
|
|
throw new Error('malformed packet');
|
|
}
|
|
|
|
const systemSubChunk = infoPacket.data.systemName;
|
|
if (!systemSubChunk) {
|
|
// NOTE(jwetzell): not sure that info packets without a system subchunk are valid?
|
|
throw new Error('malformed packet');
|
|
}
|
|
if (currentInfoPacketHeader.data.frameId) {
|
|
if (
|
|
this.infoPacketFrames[currentInfoPacketHeader.data.frameId] ===
|
|
undefined
|
|
) {
|
|
this.infoPacketFrames[currentInfoPacketHeader.data.frameId] = [];
|
|
}
|
|
this.infoPacketFrames[currentInfoPacketHeader.data.frameId].push(
|
|
infoPacket
|
|
);
|
|
|
|
if (
|
|
this.infoPacketFrames[currentInfoPacketHeader.data.frameId]
|
|
.length === currentInfoPacketHeader.data.framePacketCount
|
|
) {
|
|
this.updateInfo(
|
|
this.infoPacketFrames[currentInfoPacketHeader.data.frameId]
|
|
);
|
|
delete this.infoPacketFrames[currentInfoPacketHeader.data.frameId];
|
|
}
|
|
}
|
|
}
|
|
} else if (packet.header.id === 0x6755) {
|
|
const dataPacket = Decoders.DataPacketChunk(packetBuf);
|
|
if (dataPacket.chunk.header.hasSubchunks) {
|
|
const currentDataPacketHeader = dataPacket.data.packetHeader;
|
|
if (!currentDataPacketHeader) {
|
|
// NOTE(jwetzell): not sure that info packets without a header subchunk are valid?
|
|
throw new Error('malformed packet');
|
|
}
|
|
|
|
if (currentDataPacketHeader.data.frameId) {
|
|
if (
|
|
this.dataPacketFrames[currentDataPacketHeader.data.frameId] ===
|
|
undefined
|
|
) {
|
|
this.dataPacketFrames[currentDataPacketHeader.data.frameId] = [];
|
|
}
|
|
this.dataPacketFrames[currentDataPacketHeader.data.frameId].push(
|
|
dataPacket
|
|
);
|
|
if (
|
|
this.dataPacketFrames[currentDataPacketHeader.data.frameId]
|
|
.length === currentDataPacketHeader.data.framePacketCount
|
|
) {
|
|
this.updateData(
|
|
this.dataPacketFrames[currentDataPacketHeader.data.frameId]
|
|
);
|
|
delete this.dataPacketFrames[currentDataPacketHeader.data.frameId];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|