diff --git a/quasar.config.ts b/quasar.config.ts index 20a0172..424e67f 100644 --- a/quasar.config.ts +++ b/quasar.config.ts @@ -106,12 +106,12 @@ export default defineConfig((/* ctx */) => { proxy: { // proxy all requests starting with /api to jsonplaceholder '/api': { - target: 'http://localhost:8000', + target: 'http://localhost:49151', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ''), }, '/socket.io': { - target: 'http://localhost:8000', // Your backend WebSocket server + target: 'http://localhost:49151', // Your backend WebSocket server secure: false, // Set to true if using wss:// ws: true, // Enable WebSocket proxying rewriteWsOrigin: true, @@ -141,7 +141,7 @@ export default defineConfig((/* ctx */) => { }, // animations: 'all', // --- includes all animations // https://v2.quasar.dev/options/animations - animations: [], + animations: ['slideInLeft', 'slideOutLeft', 'slideOutRight'], // https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#sourcefiles // sourceFiles: { diff --git a/src/components/LRoutingMachine.vue b/src/components/LRoutingMachine.vue index 2d97fe9..fa4b347 100644 --- a/src/components/LRoutingMachine.vue +++ b/src/components/LRoutingMachine.vue @@ -1,84 +1,73 @@ + + + + diff --git a/src/components/LeafletTest.vue b/src/components/LeafletTest.vue index 6db9ed0..e8665aa 100644 --- a/src/components/LeafletTest.vue +++ b/src/components/LeafletTest.vue @@ -1,64 +1,168 @@ - - + - - - - + + + + + + + + Find My Location + + + + + Sim Location + + + + + + + + + + + Location Queue + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/src/components/LocationMark.vue b/src/components/LocationMark.vue new file mode 100644 index 0000000..416a869 --- /dev/null +++ b/src/components/LocationMark.vue @@ -0,0 +1,226 @@ + + + + + + {{ formatAddress(address) }} + {{ latitude }}, {{ longitude }} + + + start: {{ humanReadableDateTime(start) }} + + + end: {{ humanReadableDateTime(end) }} + + + + + {{ calculateDeltaT }} + + + + {{ + active ? '*' : locationQueueOrder.indexOf(loc_id) + }} + + + + + + + diff --git a/src/components/MenuBar.vue b/src/components/MenuBar.vue index ce541c3..231ea5e 100644 --- a/src/components/MenuBar.vue +++ b/src/components/MenuBar.vue @@ -1,6 +1,6 @@ - - + + - + - + - + - {{ fav.name }} + {{ favObj.name }} - + - {{ fav.name }} + {{ favObj.name }} - + - + - {{ f.name }} + {{ favSubObj.name }} @@ -156,12 +203,13 @@ function handleControlClick(cmdAttr: CtrlAttr) { clickable v-ripple v-close-popup - @click="handleControlClick(controls.sim_start)"> + @click="handleControlClick(controls.simulation.start)" + > - + - {{ controls.sim_start.name }} + {{ controls.simulation.start.name }} - + - {{ controls.sim_pause.name }} + {{ controls.simulation.pause.name }} - + - {{ controls.sim_resume.name }} + {{ controls.simulation.resume.name }} + @click="handleControlClick(controls.simulation.clear)" + > - + - {{ controls.sim_clear.name }} + {{ controls.simulation.clear.name }} + @click="handleControlClick(controls.simulation.end)" + > - + - {{ controls.sim_end.name }} + {{ controls.simulation.end.name }} + + + + iCloud Monitor Controls + + + + + + {{ controls.icloudmonitor.start.name }} + + + + + + + + {{ controls.icloudmonitor.stop.name }} Device Controls - + - + - {{ controls.dev_reboot.name }} + {{ controls.device.reboot.name }} - + - + - {{ controls.dev_shutdown.name }} + {{ controls.device.shutdown.name }} diff --git a/src/components/SetLocationDialog.vue b/src/components/SetLocationDialog.vue index 6031fdb..45aa1c7 100644 --- a/src/components/SetLocationDialog.vue +++ b/src/components/SetLocationDialog.vue @@ -9,7 +9,14 @@ Are you sure you want to set location to {{ latitude }}, {{ longitude }} ? - + @@ -37,6 +44,6 @@ defineEmits([...useDialogPluginComponent.emits]); const { dialogRef: dlgRef, onDialogOK, onDialogCancel } = useDialogPluginComponent(); function onOkClick() { - onDialogOK(); + onDialogOK(delay.value); } diff --git a/src/components/StatusBar.vue b/src/components/StatusBar.vue index 1d7282b..058c1c7 100644 --- a/src/components/StatusBar.vue +++ b/src/components/StatusBar.vue @@ -8,6 +8,7 @@ const { deviceConnected, tunnelConnected, simulationRunning, + icloudMonitor, currentLocation, nextLocation, } = storeToRefs(socketioStore); @@ -33,23 +34,54 @@ function statusDevColor(state: string | boolean): string { - Status: - - - - - - - Device Connection - - - - tunneld - - - - Location Simulation - + + + + + + + + + + + + + + + + + diff --git a/src/components/iCloudCodeDialog.vue b/src/components/iCloudCodeDialog.vue new file mode 100644 index 0000000..1a330fd --- /dev/null +++ b/src/components/iCloudCodeDialog.vue @@ -0,0 +1,41 @@ + + + + + + iCloud Account requires Two-factor authentication. + + + + + + + + + + + + + diff --git a/src/components/models.ts b/src/components/models.ts index e2cf6bf..462954e 100644 --- a/src/components/models.ts +++ b/src/components/models.ts @@ -1,12 +1,14 @@ - -export type SimulationCommands = "start" | "pause" | "resume" | "clear" | "end" | "add"; - -export type DeviceCommands= "start_tunnel" | "stop_tunnel" | "shutdown"; - export interface CtrlAttrs { [key: string]: CtrlAttr; } + +export type SimulationCommands = 'start' | 'pause' | 'resume' | 'clear' | 'end' | 'add'; + +export type DeviceCommands = 'start_tunnel' | 'stop_tunnel' | 'shutdown' | 'reboot'; + +export type TunnelCommands = 'start' | 'start-watcher' | 'end-watcher' | 'shutdown' | 'restart' | 'clear' | 'cancel' ; + export interface CtrlAttr { name: string; cmd: string; @@ -16,6 +18,15 @@ export interface CtrlAttr { delay: number; } +export interface DevCtrlAttr { + name: string; + cmd: DeviceCommands; + cmdClass: 'device_control'; + icon: string; + cnfrm: boolean; + delay: number; +} + export interface LocationQueue { [key: string]: LocationMark } @@ -24,9 +35,155 @@ interface LocationMark { loc_id: string; latitude: number | undefined | null; longitude: number | undefined | null; + address?: string | undefined | null; delay?: number | undefined | null; - start_time: string | undefined | null; - end_time?: string | undefined | null ; + start?: string | undefined | null; + end?: string | undefined | null ; +} + +// SERVER TO CLIENT + +export interface ServerToClientEvents { + noArg: () => void; + withAck: (a: string, callback: (b: number) => void) => void; + simulation_status: (c: SimulationStatus) => void; + status: (d: StatusUpdate) => void; + device_status: (d: DeviceStatus) => void; + error: (data: ErrorFull) => void; + message: (e: string) => void; + icloud_2fa_request: (callback: (e: number) => void) => void; + fmf_update: (d: FindMyUpdate) => void; +} + +interface SimulationStatus { + status: boolean; + data: { + latitude: number; + longitude: number; + start: string; + end?: string; + next_move?: number; + }; +} + +export interface StatusUpdate { + connected_clients: { [key: string]: string }; + current_location: { + loc_id: string; + latitude: number | undefined | null; + longitude: number | undefined | null; + start?: string | undefined | null; + }; + device_name: string | undefined | null; + fmf_location: FindMyUpdate | undefined | null; + icloud: { + consumer_queue: number | undefined | null; + consumer_task: string | undefined | null; + monitor_enabled: boolean; + monitor_task: string | undefined | null; + monitor_running: boolean; + }; + next_move?: number | undefined | null; + set_location_enabled: boolean; + simulation_queue: { + active: boolean; + data: { + [key: string]: LocationMark; + }; + order: string[]; + state: string | undefined | null; + worker_task: string | undefined | null; + }; + test_mode: boolean; + tunnel: string | undefined | null; + tunnel_watcher_running: boolean; + device_count?: number | undefined | null; + udid?: string | null; + product_version?: string | null | undefined; + phone_number?: string | null | undefined; + developer_mode_enabled?: boolean | undefined | null; + ddi_mounted?: boolean; + rsd_address?: string | null | undefined; + rsd_port?: number | undefined | null; + lockdown_trusted_port?: number | undefined | null; + lockdown_untrusted_port?: number | undefined | null; + lockdown_trusted_reachable?: boolean | undefined | null; + lockdown_untrusted_reachable?: boolean | undefined | null; + dtservicehub_reachable?: boolean | undefined | null; +} + +interface DeviceStatus { + device_connected: boolean; + device_count: number; + udid?: string | null; + device_name?: string | null; + product_version?: string | null; + phone_number?: string | null; + developer_mode_enabled?: boolean; + ddi_mounted?: boolean; + rsd_address?: string | null; + rsd_port?: number; + lockdown_trusted_port?: number; + lockdown_untrusted_port?: number; + lockdown_trusted_reachable?: boolean; + lockdown_untrusted_reachable?: boolean; + dtservicehub_reachable?: boolean; +} + +export interface ErrorFull { + type: string; + error: string; +} + +export interface FindMyUpdate { + altitude: number; + batteryLevel: number; + deviceDisplayName: string; + deviceStatus: number; + horizontalAccuracy: number; + latitude: number; + longitude: number; + name: string; + timeStamp: number; + verticalAccuracy: number; +} + +// END SERVER TO CLIENT + +// CLIENT TO SERVER + +export interface ClientToServerEvents { + message: (e: string, callback: (b: boolean, r: string) => void) => void; + request_update: (callback: (response: StatusUpdate) => void) => void; + simulation_control: ( + args: { + command: SimulationCommands; + latitude?: number | null | undefined; + longitude?: number | null | undefined; + delay?: number | undefined; + }, + callback: (response: SimulationControlResponse) => void, + ) => void; + device_control: ( + args: { + command: DeviceCommands; + delay?: number; + }, + callback?: (response: DeviceControlResponse) => void, + ) => void; + tunnel_control: ( + args: { + command: TunnelCommands; + delay?: number; + }, + callback?: (response: DeviceControlResponse) => void, + ) => void; + icloud_monitor_control: ( + args: { + command: string; + }, + callback?: (response: iCloudMonitorResponse) => void, + ) => void; } export interface SimulationControlResponse { @@ -47,119 +204,20 @@ interface DeviceControlResponse { delay?: number; } -interface StatusUpdate { - simulation_active: boolean; - set_location_enabled: boolean; - queue: number, - latitude: number | undefined | null; - longitude: number | undefined | null; - next_move?: number | undefined | null; - queue_list: LocationQueue[] - queue_state: string | undefined | null; - queue_status: boolean; - simulation_task: string | undefined | null; - test_mode: boolean - tunnel: string | undefined | null; - device_count?: number | undefined | null; - udid?: string | null; - device_name?: string | null | undefined; - product_version?: string | null | undefined; - phone_number?: string | null | undefined; - developer_mode_enabled?: boolean | undefined | null; - ddi_mounted?: boolean ; - rsd_address?: string | null | undefined; - rsd_port?: number | undefined | null; - lockdown_trusted_port?: number | undefined | null; - lockdown_untrusted_port?: number | undefined | null; - lockdown_trusted_reachable?: boolean | undefined | null; - lockdown_untrusted_reachable?: boolean | undefined | null; - dtservicehub_reachable?: boolean | undefined | null +export interface iCloudMonitorResponse { + status: string; + command: string; + icloud_monitor_enabled?: boolean | undefined | null; + icloud_monitor_running?: boolean | undefined | null; + message?: string | undefined | null; } -export interface ServerToClientEvents { - noArg: () => void; - withAck: (a: string, callback: (b: number) => void) => void; - simulationStatus: (c: SimulationStatus) => void; - status: (d: StatusUpdate) => void; - device_status: (d: DeviceStatus) => void; - error: (data: ErrorFull) => void; - message: (e: string) => void; -} - -export interface ClientToServerEvents { - message: (e: string, callback: (b: boolean, r: string) => void) => void; - simulation_control: ( - args: { - command: SimulationCommands, - latitude?: number | null | undefined, - longitude?: number | null | undefined, - delay?: number | undefined - }, - callback: (response: SimulationControlResponse) => void - ) => void; - device_control: ( - args: { - command: DeviceCommands, - delay?: number - }, - callback?: (response: DeviceControlResponse) => void - ) => void; -} - -interface SimulationStatus { - status: boolean; - data: { - latitude: number; - longitude: number; - start: string; - end?: string; - next_move?: number; - }; -} +// END CLIENT TO SERVER export interface Meta { totalCount: number; } - -interface DeviceStatus { - device_connected: boolean; - device_count: number; - udid?: string | null; - device_name?: string | null; - product_version?: string | null; - phone_number?: string | null; - developer_mode_enabled?: boolean; - ddi_mounted?: boolean; - rsd_address?: string | null; - rsd_port?: number; - lockdown_trusted_port?: number; - lockdown_untrusted_port?: number; - lockdown_trusted_reachable?: boolean; - lockdown_untrusted_reachable?: boolean; - dtservicehub_reachable?: boolean; -} - -export type Control = DeviceControl | SimulationControl; - -export interface DeviceControl { - id: number; - name: string; - cmd: DeviceCommands - cmdClass: "device_control" - icon: string; - confirm: boolean; -} - -export interface SimulationControl { - id: number; - name: string; - cmd: SimulationCommands; - cmdClass: 'simulation_control'; - icon: string; - confirm: boolean; -} - export interface coords { lat: number; lng: number; @@ -183,9 +241,11 @@ export interface SearchControlProps { export interface CurrentLocation { loc_id: string; - latitude: number; - longitude: number; - next_move?: number | null + latitude: number| null | undefined; + longitude: number| null | undefined; +// start_time?: string | null | undefined; +// end_time?: string | null | undefined + next_move?: number | null | undefined; } export interface NextLocation { @@ -195,7 +255,4 @@ export interface NextLocation { time_at_location?: number | null; } -export interface ErrorFull { - type: string; - error: string; -} + diff --git a/src/constants/controls.ts b/src/constants/controls.ts index 4a734c3..77caabd 100644 --- a/src/constants/controls.ts +++ b/src/constants/controls.ts @@ -1,62 +1,82 @@ import type { CtrlAttrs } from 'components/models'; -export const controls: CtrlAttrs = { - sim_start: { - name: 'Start Location Sim', - cmd: 'start', - cmdClass: 'simulation_control', - icon: 'play_arrow', - cnfrm: false, - delay: 0, +export const controls = { + simulation: { + start: { + name: 'Start Location Sim', + cmd: 'start', + cmdClass: 'sim_cntrl_class', + icon: 'play_arrow', + cnfrm: false, + delay: 0, + }, + pause: { + name: 'Pause Location Sim', + cmd: 'pause', + cmdClass: 'sim_cntrl_class', + icon: 'pause', + cnfrm: false, + delay: 0, + }, + resume: { + name: 'Resume Location Simulation', + cmd: 'resume', + cmdClass: 'sim_cntrl_class', + icon: 'play_arrow', + cnfrm: false, + delay: 0, + }, + clear: { + name: 'Clear Location Queue', + cmd: 'clear', + cmdClass: 'sim_cntrl_class', + icon: 'directions_off', + cnfrm: false, + delay: 0, + }, + end: { + name: 'End Location Sim', + cmd: 'end', + cmdClass: 'sim_cntrl_class', + icon: 'stop', + cnfrm: true, + delay: 0, + }, }, - sim_pause: { - name: 'Pause Location Sim', - cmd: 'pause', - cmdClass: 'simulation_control', - icon: 'pause', - cnfrm: false, - delay: 0, - }, - sim_resume: { - name: 'Resume Location Simulation', - cmd: 'resume', - cmdClass: 'simulation_control', - icon: 'play_arrow', - cnfrm: false, - delay: 0, - }, - sim_clear: { - name: 'Clear Location Queue', - cmd: 'clear', - cmdClass: 'simulation_control', - icon: 'directions_off', - cnfrm: false, - delay: 0, - }, - sim_end: { - name: 'End Location Sim', - cmd: 'end', - cmdClass: 'simulation_control', - icon: 'stop', - cnfrm: true, - delay: 0, - }, - dev_shutdown: { - name: 'Shutdown', - cmd: 'shutdown', - cmdClass: 'device_control', - icon: 'power_settings_new', - cnfrm: true, - delay: 5, - }, - dev_reboot: { - name: 'Reboot', - cmd: 'reboot', - cmdClass: 'device_control', - icon: 'restart_alt', - cnfrm: true, - delay: 5, + device: { + shutdown: { + name: 'Shutdown', + cmd: 'shutdown', + cmdClass: 'dev_cntrl_class', + icon: 'power_settings_new', + cnfrm: true, + delay: 5, + }, + reboot: { + name: 'Reboot', + cmd: 'reboot', + cmdClass: 'dev_cntrl_class', + icon: 'restart_alt', + cnfrm: true, + delay: 5, + } }, + icloudmonitor: { + start: { + name: 'Start iCloud Monitor', + cmd: 'start', + cmdClass: 'icloud-monitor_cntrl_class', + icon: 'play_arrow', + cnfrm: false, + delay: 0, + }, + stop: { + name: 'Stop iCloud Monitor', + cmd: 'stop', + cmdClass: 'icloud-monitor_cntrl_class', + icon: 'stop', + cnfrm: false, + delay: 0, + } + } }; - - diff --git a/src/constants/favorites.ts b/src/constants/favorites.ts index 70f599f..cdb5e6b 100644 --- a/src/constants/favorites.ts +++ b/src/constants/favorites.ts @@ -1,5 +1,5 @@ -export const favorites = [ - { +export const favorites = { + home: { name: 'Home', icon: 'home', coords: { @@ -7,11 +7,11 @@ export const favorites = [ lng: -73.891069806448, }, }, - { - name: "Work Places", - icon: "work", - subitems: [ - { + work_places: { + name: 'Work Places', + icon: 'work', + subitems: { + jeong: { name: 'Jeong', icon: 'language_korean_latin', coords: { @@ -20,17 +20,17 @@ export const favorites = [ }, address: '35-02 150th Pl, Flushing, NY 11354', }, - { + santos: { name: 'Santos', icon: 'rice_bowl', coords: { lat: 40.74504671877868, lng: -73.8880099638491, }, - address: '77-08 Broadway, Elmhurst, NY 11373' + address: '77-08 Broadway, Elmhurst, NY 11373', }, - { - name: 'Natalyaa (Qns)', + natalya_qns: { + name: 'Natalya (Qns)', icon: 'currency_ruble', coords: { lat: 40.69644966409178, @@ -38,8 +38,8 @@ export const favorites = [ }, address: '110-14 Jamaica Ave, Richmond Hill, NY 11418', }, - { - name: 'Natalyaa (Bronx)', + natalya_bx: { + name: 'Natalya (Bronx)', icon: 'currency_ruble', coords: { lat: 40.85384419116598, @@ -47,7 +47,7 @@ export const favorites = [ }, address: '2109 Matthews Ave, Bronx, NY 10462', }, - { + office: { name: 'Linwood Plaza', icon: 'dermatology', coords: { @@ -56,9 +56,9 @@ export const favorites = [ }, address: '158 Linwood Plaza, Fort Lee, NJ 07024', }, - ], + }, }, - { + strg: { name: 'Man Mini Storage', icon: 'box', coords: { @@ -67,8 +67,8 @@ export const favorites = [ }, address: '31-08 Northern Blvd, Long Island City, NY 11101', }, - { - name: 'Acmd', + acme: { + name: 'Acme', icon: 'grocery', coords: { lat: 40.90930366920829, @@ -76,4 +76,4 @@ export const favorites = [ }, address: '31-08 Northern Blvd, Long Island City, NY 11101', }, -]; +}; diff --git a/src/functions/routingControl.ts b/src/functions/routingControl.ts index 5d2e050..5211671 100644 --- a/src/functions/routingControl.ts +++ b/src/functions/routingControl.ts @@ -1,15 +1,15 @@ -import { Utilities } from "@vue-leaflet/vue-leaflet"; -import type * as L from "leaflet"; -import type { IRouter, IGeocoder, LineOptions } from "leaflet-routing-machine"; +import { Utilities } from '@vue-leaflet/vue-leaflet'; +import type L from 'leaflet'; +import type { IRouter, IGeocoder, LineOptions } from 'leaflet-routing-machine'; -// Props typing +// ---- Props typing ---- export interface RoutingControlProps { - waypoints: L.LatLng[]; + waypoints: L.Routing.Waypoint[]; router?: IRouter; - plan?: any; // L.Routing.Plan (can refine if you typed it) + plan?: L.Routing.Plan; fitSelectedRoutes?: string | boolean; lineOptions?: LineOptions; - routeLine?: (...args: any[]) => any; + routeLine?: (route: any) => L.Layer; autoRoute?: boolean; routeWhileDragging?: boolean; routeDragInterval?: number; @@ -19,30 +19,30 @@ export interface RoutingControlProps { altLineOptions?: LineOptions; } -// Vue-style prop definitions (still needed for runtime) +// ---- Vue-compatible prop definition ---- export const routingControlProps = { waypoints: { - type: Array as () => L.LatLng[], + type: Array as () => L.Routing.Waypoint[], default: () => [], }, router: { - type: Object as () => IRouter, + type: Object as () => IRouter | undefined, default: undefined, }, plan: { - type: Object as () => any, + type: Object as () => L.Routing.Plan | undefined, default: undefined, }, fitSelectedRoutes: { - type: [String, Boolean] as () => string | boolean, - default: "smart", + type: [String, Boolean] as unknown as () => string | boolean, + default: 'smart', }, lineOptions: { - type: Object as () => LineOptions, + type: Object as () => LineOptions | undefined, default: undefined, }, routeLine: { - type: Function as () => (...args: any[]) => any, + type: Function as unknown as () => ((route: any) => L.Layer) | undefined, default: undefined, }, autoRoute: { @@ -59,7 +59,7 @@ export const routingControlProps = { }, waypointMode: { type: String, - default: "connect", + default: 'connect', }, useZoomParameter: { type: Boolean, @@ -70,17 +70,17 @@ export const routingControlProps = { default: false, }, altLineOptions: { - type: Object as () => LineOptions, + type: Object as () => LineOptions | undefined, default: undefined, }, }; -// Setup function +// ---- Setup function ---- export const setupRoutingControl = (props: RoutingControlProps) => { const options = Utilities.propsToLeafletOptions( props, - routingControlProps - ); + routingControlProps, + ) as L.Routing.RoutingControlOptions; return { options, diff --git a/src/stores/leaflet.ts b/src/stores/leaflet.ts index 9677db3..52b0abe 100644 --- a/src/stores/leaflet.ts +++ b/src/stores/leaflet.ts @@ -1,19 +1,36 @@ import { defineStore, acceptHMRUpdate } from 'pinia'; +import { favorites } from 'constants/favorites' interface State { zoom: number - center: [number, number] - markerLatLng: [number, number] + center: [number, number] | [null, null] | null + markerLatLng: [number, number] | [null, null] | null + qLocDrawer: boolean } export const useLeafletStore = defineStore('leaflet', { state: (): State => { return { zoom: 10, - center: [40.71278, -74.00594], - markerLatLng: [40.71278, -74.00594], + center: [favorites.home.coords.lat, favorites.home.coords.lng], + markerLatLng: null, + qLocDrawer: false, } }, + actions: { + setCenter(lat: number, lng: number) { + this.center = [lat, lng]; + }, + setZoom(zoom: number) { + this.zoom = zoom; + }, + setMarkerLatLng(lat: number, lng: number) { + this.markerLatLng = [lat, lng]; + }, + toggleQLocDrawer() { + this.qLocDrawer = !this.qLocDrawer + } + } }) if (import.meta.hot) { diff --git a/src/stores/socketio.ts b/src/stores/socketio.ts index ad51188..0e238c8 100644 --- a/src/stores/socketio.ts +++ b/src/stores/socketio.ts @@ -1,48 +1,61 @@ import { defineStore, acceptHMRUpdate } from 'pinia'; import { socket } from 'boot/socketio'; +import { useQuasar } from 'quasar'; +import iCloudCodeDialog from 'components/iCloudCodeDialog.vue'; import type { CurrentLocation, NextLocation, ErrorFull, - SimulationControl, - SimulationCommands, LocationQueue, SimulationControlResponse, - StatusUpdate + StatusUpdate, + FindMyUpdate, + iCloudMonitorResponse, } from 'components/models'; - +const $q = useQuasar(); +const debugLog: boolean = true; export const useSocketioStore = defineStore('socketio', { state: () => { return { sockConnected: false as boolean, socketID: null as string | null | undefined, + testMode: null as boolean | undefined | null, deviceConnected: false as boolean, tunnelConnected: false as boolean, simulationRunning: false as boolean | string, simulationState: null as string | null | undefined, - simulationQueneLength: 0 as number, - currentLocation: null as CurrentLocation | null, + simulationQueueLength: 0 as number | null | undefined, + currentLocation: null as CurrentLocation | null | undefined, nextLocation: null as NextLocation | null, messageList: [''] as string[], errorList: [] as ErrorFull[], - locationQueue: [] as LocationQueue[], - leafLetZoom: 10 as number, - + locationQueueData: {} as LocationQueue, + locationQueueOrder: [] as string[], + leafletZoom: 10 as number, + icloudMonitor: false as boolean, + findMyUpdate: null as FindMyUpdate | null | undefined, }; }, getters: { sockState: (state) => state.sockConnected, deviceState: (state) => state.deviceConnected, - markerLatLng: (state) => { - return [state.currentLocation.latitude, state.currentLocation.longitude] + lMarkerLatLng: (state): [number, number] => { + if ( + state.currentLocation == null || + !state.currentLocation.latitude || + !state.currentLocation.longitude + ) { + return [0, 0]; + } + return [state.currentLocation.latitude, state.currentLocation.longitude]; }, - center(): [number, number] { - return this.leafletCurrentMarker + lCenter(): [number, number] { + return this.lMarkerLatLng; }, - zoom: (state) => state.leafletZoom, + lZoom: (state): number => state.leafletZoom, }, actions: { setSockStatus() { @@ -54,9 +67,13 @@ export const useSocketioStore = defineStore('socketio', { socket.on('connect', () => { this.setSockStatus(); socket.emit('message', 'Hello from client', (e: boolean) => { - console.log('Message delivered: ' + e); + if (debugLog) { + console.log('Message delivered: ' + e); + } }); - console.log('Connected to server'); + if (debugLog) { + console.log('Connected to server'); + } }); socket.on('disconnect', () => { @@ -67,31 +84,79 @@ export const useSocketioStore = defineStore('socketio', { socket.on('message', (e: string) => { this.setSockStatus(); this.messageList.push(e); - console.log('Websock message received!'); + if (debugLog) { + console.log('Websock message received!'); + } }); socket.on('error', (data: ErrorFull) => { this.setSockStatus(); const errorFull = { type: data.type, error: data.error }; this.errorList.push(errorFull); + console.error('Error Received: ', data); }); socket.on('status', (data: StatusUpdate): void => { - console.log("StatusUpdate received: ", data); - this.simulationRunning = data.simulation_active; - this.simulationState = data.queue_state; - this.simulationQueneLength = data.quene_length; - this.tunnelConnected = !!data.tunnel; - this.currentLocation = { loc_id: data.loc_id, latitude: data.latitude, longitude: data.longitude, next_move: data.next_mode }; + if (debugLog) { + console.log('StatusUpdate received: ', data); + } + this.digestUpdate(data); + }); + + socket.on('fmf_update', (data: FindMyUpdate): void => { + if (debugLog) { + console.log('event: fmf_update received: ', data); + } + this.findMyUpdate = data; + }); + + socket.on('icloud_2fa_request', (callback) => { + if (debugLog) { + console.log('iCloud 2FA Request'); + } + $q.dialog({ + component: iCloudCodeDialog, + }) + .onOk((code: number) => { + if (callback && typeof callback === 'function') { + callback(code); + } + }) + .onCancel(() => { + if (debugLog) { + console.log('Dialog cancelled'); + } + }) + .onDismiss(() => { + if (debugLog) { + console.log('Dialog dismissed'); + } + }); }); socket.onAny((eventName, ...args) => { - this.setSockStatus(); - console.log(`Received event: ${eventName}`, args); + console.log('Event received: ', eventName, ' Args: ', args, ''); + /* if (serverToClientKnownEvents.includes(eventName)) { + console.log('Known event received: ', eventName, ' Args: ', args, ''); + } else { + console.log( + 'Known events: ', + serverToClientKnownEvents, + ' Received Event: ', + eventName, + ' Args: ', + args, + '', + ); + console.log(`Received UNKNOWN Event: ${eventName}`, args); + } + */ }); }, connect() { - console.log('Connecting to server...'); + if (debugLog) { + console.log('Connecting to server...'); + } socket.connect(); this.setSockStatus(); }, @@ -108,63 +173,202 @@ export const useSocketioStore = defineStore('socketio', { } this.setSockStatus(); }, - setSimulationRunning(isRunning: boolean, states: string ): void { + setSimulationRunning(isRunning: boolean, states: string): void { this.setSockStatus(); this.simulationState = states; this.simulationRunning = isRunning; }, - simulationControl(command: SimulationCommands, delay?: number, latitude?: number | null, longitude?: number | null): string | never { + icloudMonitorControl(command: string) { + let fnctRtn: { sts: string; msg?: string | undefined } = { sts: '', msg: '' }; + switch (command) { + case 'start': + if (debugLog) { + console.log('socketStore: got command: icloudMonitor start'); + } + if (this.icloudMonitor) { + fnctRtn = { sts: 'error', msg: 'iCloud Monitor is already running' }; + throw new Error('iCloud Monitor is already running'); + } + if (debugLog) { + console.log('Emitting icloud_monitor_control: start'); + } + socket.emit( + 'icloud_monitor_control', + { command: 'start' }, + (response: iCloudMonitorResponse) => { + fnctRtn.sts = response.status; + if (response.status == 'error') { + if (response.message) { + if (debugLog) { + console.log(response.message); + } + fnctRtn.msg = response.message; + } else { + fnctRtn.msg = 'Error'; + } + throw new Error(fnctRtn.msg); + } else { + fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status }; + this.icloudMonitor = true; + } + }); + break; + case 'stop': + if (debugLog) { + console.log('socketStore: got command: icloudMonitor stop'); + } + if (!this.icloudMonitor) { + fnctRtn = { sts: 'error', msg: 'iCloud Monitor is not running' }; + throw new Error('iCloud Monitor is not running'); + } + if (debugLog) { + console.log('Emitting icloud_monitor_control: stop'); + } + socket.emit( + 'icloud_monitor_control', + { command: 'stop' }, + (response: iCloudMonitorResponse) => { + fnctRtn.sts = response.status; + if (response.status == 'error') { + if (response.message) { + if (debugLog) { + console.log(response.message); + } + fnctRtn.msg = response.message; + } else { + fnctRtn.msg = 'Error'; + } + throw new Error(fnctRtn.msg); + } else { + fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status }; + this.icloudMonitor = false; + } + }); + break; + case 'status': + if (debugLog) { + console.log('socketStore: got command: icloudMonitor status'); + } + if (debugLog) { + console.log('Emitting icloud_monitor_control: status'); + } + socket.emit( + 'icloud_monitor_control', + { command: 'status' }, + (response: iCloudMonitorResponse) => { + fnctRtn.sts = response.status; + if (response.status == 'error') { + if (response.message) { + if (debugLog) { + console.log(response.message); + } + fnctRtn.msg = response.message; + } else { + fnctRtn.msg = 'Error'; + } + throw new Error(fnctRtn.msg); + } else { + fnctRtn = { + sts: 'OK', + msg: + 'iCloud Monitor Enabled: ' + + response.icloud_monitor_enabled + + 'iCloud Monitor Running: ' + + response.icloud_monitor_running + }; + } + this.icloudMonitor = !!(response.icloud_monitor_enabled && response.icloud_monitor_running); + }); + break; + default: + fnctRtn = { sts: 'error', msg: 'Invalid command' }; + throw new Error('Invalid command'); + } + return fnctRtn; + }, + simulationControl( + command: string, + delay?: number, + latitude?: number | null, + longitude?: number | null, + ) { + let fnctRtn: { sts: string; msg?: string | undefined } = { sts: '', msg: '' }; this.setSockStatus(); switch (command) { case 'start': - console.log("socketStore: got command: start"); - if (this.simulationRunning || this.simulationState == "RUNNING" || this.simulationState == "PAUSED") { + if (debugLog) { + console.log('socketStore: got command: start'); + } + if ( + this.simulationRunning || + this.simulationState == 'RUNNING' || + this.simulationState == 'PAUSED' + ) { + fnctRtn = { sts: 'error', msg: 'Simulation is already running' }; throw new Error('Simulation is already running' + this.simulationState); } - console.log("Emmitting simulation_control: start") - socket.emit('simulation_control', { command: 'start', delay: 0, latitude: null, longitude: null}, (response: SimulationControlResponse) => { - if (response.status == "error") { - throw new Error(response.message); - } else { - this.simulationState = response.status; - console.log(response.message); - return response.message; - } - }); + if (debugLog) { + console.log('Emitting simulation_control: start'); + } + socket.emit( + 'simulation_control', + { command: 'start', delay: 0, latitude: null, longitude: null }, + (response: SimulationControlResponse) => { + if (response.status == 'error') { + fnctRtn = { sts: 'error', msg: response.message?.toString() }; + throw new Error(response.message); + } else { + fnctRtn = { sts: 'OK', msg: response.message?.toString() }; + this.simulationState = response.status; + if (debugLog) { + console.log(response.message); + } + // return response.message; + } + }, + ); break; case 'pause': - if (this.simulationState !== "RUNNING" ) { + if (this.simulationState !== 'RUNNING') { throw new Error('Simulation is not running'); } - socket.emit('simulation_control', { command: 'pause' }, (response: SimulationControlResponse) => { - if (response.status === "error") { - throw new Error(response.message); - } else { - this.simulationState = response.status; - console.log(response.message); - return response.message; - } - }); + socket.emit( + 'simulation_control', + { command: 'pause' }, + (response: SimulationControlResponse) => { + if (response.status === 'error') { + throw new Error(response.message); + } else { + this.simulationState = response.status; + if (debugLog) { + console.log(response.message); + } + return response.message; + } + }, + ); break; case 'resume': - if (this.simulationState !== "PAUSED") { + if (this.simulationState !== 'PAUSED') { throw new Error('Simulation is not paused'); } socket.emit('simulation_control', { command: 'resume' }, (response) => { - if (response.status == "error") { - throw new Error(response.message) + if (response.status == 'error') { + throw new Error(response.message); } else { this.simulationState = response.status; - console.log(response.message) - return response.message + if (debugLog) { + console.log(response.message); + } + return response.message; } }); break; case 'clear': - if (this.simulationQueueLength== 0) { + if (this.simulationQueueLength == 0) { throw new Error('Simulation queue is empty'); } - if (this.simulationState == "STOPPED " || !this.simulationRunning) { + if (this.simulationState == 'STOPPED ' || !this.simulationRunning) { throw new Error('Simulation is not running'); } socket.emit('simulation_control', { command: 'clear' }, (response) => { @@ -172,13 +376,15 @@ export const useSocketioStore = defineStore('socketio', { throw new Error(response.message); } else { this.simulationState = response.status; - console.log(response.message); + if (debugLog) { + console.log(response.message); + } return response.message; } }); break; case 'end': - if (this.simulationState == "ENDED" || !this.simulationRunning) { + if (this.simulationState == 'ENDED' || !this.simulationRunning) { throw new Error('Simulation is already ended'); } socket.emit('simulation_control', { command: 'end' }, (response) => { @@ -186,41 +392,73 @@ export const useSocketioStore = defineStore('socketio', { throw new Error(response.message); } else { this.simulationState = response.status; - console.log(response.message); + if (debugLog) { + console.log(response.message); + } return response.message; } }); break; case 'add': - if (this.simulationState == "ENDED" || !this.simulationRunning) { - throw new Error('Simulation is not running'); +// if (this.simulationState == 'ENDED' || !this.simulationRunning) { +// throw new Error('Simulation is not running'); +// } + if (!latitude || !longitude) { + throw new Error('latitude or longitude not set'); } - if (!latitude || !longitude) { - throw new Error ("latitude or longitude not set"); - } - socket.emit('simulation_control',{ command: 'add', latitude: latitude, longitude: longitude, delay: delay }, (response) => { - if (response.status == "error") { - throw new Error(response.message) - } else { - this.simulationState = response.status; - console.log("response from simulate_control_add: ", response); - const locMrk = { - [response.loc_id]: { - loc_id: response.loc_id, - latitude: response.latitude, - longitude: response.longitude, - delay: response.delay, - start_time: response.start_time, - }, - }; - this.locationQueue.push(locMrk); - return response.message; - } - }); + socket.emit( + 'simulation_control', + { command: 'add', latitude: latitude, longitude: longitude, delay: delay }, + (response) => { + if (response.status == 'error') { + throw new Error(response.message); + } else { + this.simulationState = response.status; + if (debugLog) { + console.log('response from simulate_control_add: ', response); + } + const locMrk = { + [response.loc_id]: { + loc_id: response.loc_id, + latitude: response.latitude, + longitude: response.longitude, + delay: response.delay, + start_time: response.start_time, + }, + }; + return response.message; + } + }, + ); break; default: + fnctRtn = { sts: 'error', msg: 'Invalid command' }; throw new Error('Invalid command'); } + return fnctRtn; + }, + requestUpdate(): void { + socket.emit('request_update', (response: StatusUpdate) => { + this.digestUpdate(response); + }); + }, + digestUpdate(data: StatusUpdate): void { + this.deviceConnected = !!(data.udid && data.tunnel); + this.testMode = data.test_mode; + this.simulationRunning = data.simulation_queue.active; + this.simulationState = data.simulation_queue.state; + this.simulationQueueLength = data.simulation_queue.order.length; + this.tunnelConnected = !!data.tunnel; + this.icloudMonitor = data.icloud.monitor_enabled; + this.currentLocation = { + loc_id: data.current_location.loc_id, + latitude: data.current_location.latitude, + longitude: data.current_location.longitude, + next_move: data.next_move, + }; + this.locationQueueData = data.simulation_queue.data; + this.locationQueueOrder = data.simulation_queue.order; + this.findMyUpdate = data.fmf_location; }, setDeviceState(state: boolean) { this.deviceConnected = state;