From 87625b18df78485092e4b3f982fa06e984afc7c9 Mon Sep 17 00:00:00 2001 From: Rafael Araujo Lehmkuhl Date: Thu, 16 Nov 2023 16:49:49 -0300 Subject: [PATCH 1/4] Create utility functions for storing and retrieving Cockpit data from BlueOS vehicle --- src/libs/blueos.ts | 75 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/libs/blueos.ts diff --git a/src/libs/blueos.ts b/src/libs/blueos.ts new file mode 100644 index 000000000..3abdc7195 --- /dev/null +++ b/src/libs/blueos.ts @@ -0,0 +1,75 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export const getBagOfHoldingFromVehicle = async ( + vehicleAddress: string, + bagName: string +): Promise> => { + try { + const response = await fetch(`http://${vehicleAddress}/bag/v1.0/get/${bagName}`) + if (!(await response.ok)) { + throw new Error(await response.text()) + } + return await response.json() + } catch (error) { + throw new Error(`Could not get bag of holdings for ${bagName}. ${error}`) + } +} + +export const getCockpitStorageFromVehicle = async (vehicleAddress: string): Promise> => { + try { + return await getBagOfHoldingFromVehicle(vehicleAddress, 'cockpit') + } catch (error) { + throw new Error(`Could not get Cockpit's storage data from vehicle. ${error}`) + } +} + +export const getKeyDataFromCockpitVehicleStorage = async ( + vehicleAddress: string, + storageKey: string +): Promise | undefined> => { + const cockpitVehicleStorage = await getCockpitStorageFromVehicle(vehicleAddress) + return cockpitVehicleStorage[storageKey] +} + +export const setBagOfHoldingOnVehicle = async ( + vehicleAddress: string, + bagName: string, + bagData: Record | any +): Promise => { + try { + await fetch(`http://${vehicleAddress}/bag/v1.0/set/${bagName}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(bagData), + }) + } catch (error) { + throw new Error(`Could not set bag of holdings for ${bagName}. ${error}`) + } +} + +export const setCockpitStorageOnVehicle = async ( + vehicleAddress: string, + storageData: Record | any +): Promise => { + try { + await setBagOfHoldingOnVehicle(vehicleAddress, 'cockpit', storageData) + } catch (error) { + throw new Error(`Could not set Cockpit's storage data on vehicle. ${error}`) + } +} + +export const setKeyDataOnCockpitVehicleStorage = async ( + vehicleAddress: string, + storageKey: string, + storageData: Record | any +): Promise => { + let previousVehicleStorage: Record = {} + try { + previousVehicleStorage = await getCockpitStorageFromVehicle(vehicleAddress) + } catch (error) { + console.error(error) + } + const newVehicleStorage = previousVehicleStorage + newVehicleStorage[storageKey] = storageData + + await setCockpitStorageOnVehicle(vehicleAddress, newVehicleStorage) +} From a10df7eec4c3cd25562ed499cbf6182057ba0a83 Mon Sep 17 00:00:00 2001 From: Rafael Araujo Lehmkuhl Date: Thu, 16 Nov 2023 17:32:42 -0300 Subject: [PATCH 2/4] Allow syncing Cockpit profiles with the vehicle --- src/components/EditMenu.vue | 10 ++++++++++ src/stores/widgetManager.ts | 24 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/components/EditMenu.vue b/src/components/EditMenu.vue index f67424c96..af3572047 100644 --- a/src/components/EditMenu.vue +++ b/src/components/EditMenu.vue @@ -43,6 +43,16 @@ +
+
diff --git a/src/stores/widgetManager.ts b/src/stores/widgetManager.ts index cdf1a483a..1f6a8cd90 100644 --- a/src/stores/widgetManager.ts +++ b/src/stores/widgetManager.ts @@ -9,6 +9,7 @@ import { computed, onBeforeMount, onBeforeUnmount, ref, watch } from 'vue' import { widgetProfiles } from '@/assets/defaults' import { miniWidgetsProfile } from '@/assets/defaults' +import { getKeyDataFromCockpitVehicleStorage, setKeyDataOnCockpitVehicleStorage } from '@/libs/blueos' import * as Words from '@/libs/funny-name/words' import { CockpitAction, registerActionCallback, unregisterActionCallback } from '@/libs/joystick/protocols' import { isEqual } from '@/libs/utils' @@ -16,7 +17,10 @@ import type { Point2D, SizeRect2D } from '@/types/general' import type { MiniWidget, MiniWidgetContainer } from '@/types/miniWidgets' import { type Profile, type View, type Widget, isProfile, isView, WidgetType } from '@/types/widgets' +import { useMainVehicleStore } from './mainVehicle' + export const useWidgetManagerStore = defineStore('widget-manager', () => { + const vehicleStore = useMainVehicleStore() const editingMode = ref(false) const showGrid = ref(true) const gridInterval = ref(0.01) @@ -159,6 +163,24 @@ export const useWidgetManagerStore = defineStore('widget-manager', () => { reader.readAsText(e.target.files[0]) } + const importProfilesFromVehicle = async (): Promise => { + const newProfiles = await getKeyDataFromCockpitVehicleStorage( + vehicleStore.globalAddress, + 'cockpit-saved-profiles-v7' + ) + savedProfiles.value = newProfiles + Swal.fire({ icon: 'success', text: 'Cockpit profiles imported from vehicle.', timer: 3000 }) + } + + const exportProfilesToVehicle = async (): Promise => { + await setKeyDataOnCockpitVehicleStorage( + vehicleStore.globalAddress, + 'cockpit-saved-profiles-v7', + savedProfiles.value + ) + Swal.fire({ icon: 'success', text: 'Cockpit profiles exported to vehicle.', timer: 3000 }) + } + /** * Adds new view to the store, with a randomly generated hash with UUID4 pattern */ @@ -483,5 +505,7 @@ export const useWidgetManagerStore = defineStore('widget-manager', () => { openWidgetConfigMenu, toggleFullScreen, isFullScreen, + importProfilesFromVehicle, + exportProfilesToVehicle, } }) From 9ce3199ee9889534f83f6cda569819663c302418 Mon Sep 17 00:00:00 2001 From: Rafael Araujo Lehmkuhl Date: Thu, 16 Nov 2023 17:42:31 -0300 Subject: [PATCH 3/4] Verify if imported profiles from vehicle are indeed profiles --- src/stores/widgetManager.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/stores/widgetManager.ts b/src/stores/widgetManager.ts index 1f6a8cd90..4d77e391b 100644 --- a/src/stores/widgetManager.ts +++ b/src/stores/widgetManager.ts @@ -168,6 +168,10 @@ export const useWidgetManagerStore = defineStore('widget-manager', () => { vehicleStore.globalAddress, 'cockpit-saved-profiles-v7' ) + if (!Array.isArray(newProfiles) || !newProfiles.every((profile) => isProfile(profile))) { + Swal.fire({ icon: 'error', text: 'Could not import profiles from vehicle. Invalid data.', timer: 3000 }) + return + } savedProfiles.value = newProfiles Swal.fire({ icon: 'success', text: 'Cockpit profiles imported from vehicle.', timer: 3000 }) } From d7576255c57665acc48d0e1cb930f90ae348206f Mon Sep 17 00:00:00 2001 From: Rafael Araujo Lehmkuhl Date: Thu, 16 Nov 2023 18:57:21 -0300 Subject: [PATCH 4/4] Auto-fetch saved profiles from vehicle on cold boots This way, if someone has already saved it's profiles in the vehicle using a topside computer, it will auto-download the same profiles on new computers. --- src/stores/widgetManager.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/stores/widgetManager.ts b/src/stores/widgetManager.ts index 4d77e391b..7c9262b1c 100644 --- a/src/stores/widgetManager.ts +++ b/src/stores/widgetManager.ts @@ -422,8 +422,9 @@ export const useWidgetManagerStore = defineStore('widget-manager', () => { } } - // If the user does not have it's own profiles yet, create them + // If the user does not have it's own profiles yet, try to fetch them from the vehicle, and if it fails, create default ones if (savedProfiles.value.isEmpty()) { + importProfilesFromVehicle() widgetProfiles.forEach((profile) => { // @ts-ignore: structuredClone is a thing since a long time ago const userProfile = structuredClone(profile)