Files
PhotonVision/photon-client/src/lib/PhotonUtils.ts
Alan Everett 0525e762b4 Switch from FasterXML Jackson to Avaje Jsonb (#2503)
## Description

WPILib switched from FasterXML Jackson to Avaje Jsonb for speed reasons
in https://github.com/wpilibsuite/allwpilib/pull/8721. This does the
same for PhotonVision. Some temporary Jackson adapters are present to
allow compatibility with alpha-4 ahead of updating Photon's WPILib
version. A few old backwards compatibility migrations were also dropped
if they were difficult to port to Avaje Jsonb or otherwise complicated
the code.

## Meta

Merge checklist:
- [x] Pull Request title is [short, imperative
summary](https://cbea.ms/git-commit/) of proposed changes
- [x] The description documents the _what_ and _why_, including events
that led to this PR
- [ ] If this PR changes behavior or adds a feature, user documentation
is updated
- [ ] If this PR touches photon-serde, all messages have been
regenerated and hashes have not changed unexpectedly
- [ ] If this PR touches configuration, this is backwards compatible
with all settings going back to the previous seasons's last release
(seasons end after champs ends)
- [ ] If this PR touches pipeline settings or anything related to data
exchange, the frontend typing is updated
- [ ] If this PR addresses a bug, a regression test for it is added
- [ ] If this PR adds a dependency, the license has been checked for
compatibility and steps taken to follow it

---------

Co-authored-by: samfreund <samf.236@proton.me>
Co-authored-by: Matt Morley <matthew.morley.ca@gmail.com>
2026-05-24 17:05:10 +00:00

112 lines
4.1 KiB
TypeScript

import { useStateStore } from "@/stores/StateStore";
import type { Resolution } from "@/types/SettingTypes";
import axios, { type AxiosRequestConfig } from "axios";
export const resolutionsAreEqual = (a: Resolution, b: Resolution) => {
return a.height === b.height && a.width === b.width;
};
/**
* Checks the status of the backend by polling the "/status" endpoint.
*
* This function will repeatedly attempt to send a GET request to the backend
* until a successful response is received or the specified timeout is reached.
*
* @param timeout - The maximum time in milliseconds to wait for a successful response.
* @param ip - Optional IP address of the backend server. If not provided, the default endpoint is used. This is meant for the case where the backend is running on a different IP than the frontend.
* @returns A promise that resolves to a boolean indicating whether the backend is responsive (true) or not (false).
*/
export const statusCheck = async (timeout: number, ip?: string): Promise<boolean> => {
// Poll the backend until it's responsive or we hit the timeout
let pollLimit = Math.floor(timeout / 100);
while (pollLimit > 0) {
try {
pollLimit--;
await axios.get(ip ? `http://${ip}/api/status` : "/status");
return true;
} catch {
// Backend not ready yet, wait and retry
await new Promise((resolve) => setTimeout(resolve, 100));
}
}
return false;
};
/**
* Forces a page reload after a brief delay and a status check.
*/
export const forceReloadPage = async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
useStateStore().showSnackbarMessage({
message: "Reloading the page to apply changes...",
color: "success"
});
await statusCheck(20000);
window.location.reload();
};
export const getResolutionString = (resolution: Resolution): string => `${resolution.width}x${resolution.height}`;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const parseJsonFile = async <T extends Record<string, any>>(file: File): Promise<T> => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = (event) => {
const target: FileReader | null = event.target;
if (target === null) reject(new Error("FileReader event target is null"));
else resolve(JSON.parse(target.result as string) as T);
};
fileReader.onerror = () => reject(new Error("Error reading file"));
fileReader.readAsText(file);
});
};
/**
* A helper function to make POST requests using axios with standardized success and error handling.
*
* @param url The endpoint URL to which the POST request is sent
* @param description A brief description of the request for users, e.g., "import object detection models".
* @param data Payload to be sent in the POST request
* @param config Optional axios request configuration
* @returns A promise that resolves to true if the POST request is successful, or false if an error occurs.
*/
export const axiosPost = async (
url: string,
description: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data?: any,
config?: AxiosRequestConfig
): Promise<boolean> => {
try {
await axios.post(url, data, config);
useStateStore().showSnackbarMessage({
message: "Successfully dispatched the request to " + description + ". Waiting for backend to respond",
color: "success"
});
return true;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
if (error.response) {
useStateStore().showSnackbarMessage({
message: "The backend is unable to fulfill the request to " + description + ".",
color: "error"
});
} else if (error.request) {
useStateStore().showSnackbarMessage({
message: "Error while trying to process the request to " + description + "! The backend didn't respond.",
color: "error"
});
} else {
useStateStore().showSnackbarMessage({
message: "An error occurred while trying to process the request to " + description + ".",
color: "error"
});
}
return false;
}
};