Compare commits

...

2 Commits

11 changed files with 326 additions and 17 deletions

149
package-lock.json generated
View File

@@ -14,7 +14,9 @@
"axios": "^1.2.1", "axios": "^1.2.1",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"leaflet-geosearch": "^4.2.2", "leaflet-geosearch": "^4.2.2",
"pinia": "^3.0.4",
"quasar": "^2.16.0", "quasar": "^2.16.0",
"socket.io-client": "^4.8.3",
"vue": "^3.5.22", "vue": "^3.5.22",
"vue-router": "^5.0.0" "vue-router": "^5.0.0"
}, },
@@ -1937,6 +1939,12 @@
"win32" "win32"
] ]
}, },
"node_modules/@socket.io/component-emitter": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"license": "MIT"
},
"node_modules/@types/body-parser": { "node_modules/@types/body-parser": {
"version": "1.19.6", "version": "1.19.6",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
@@ -3872,7 +3880,6 @@
"version": "4.4.3", "version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
@@ -4111,6 +4118,28 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/engine.io-client": {
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz",
"integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.4.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.18.3",
"xmlhttprequest-ssl": "~2.1.1"
}
},
"node_modules/engine.io-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/entities": { "node_modules/entities": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
@@ -6021,7 +6050,6 @@
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/muggle-string": { "node_modules/muggle-string": {
@@ -6443,6 +6471,66 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/pinia": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz",
"integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==",
"license": "MIT",
"dependencies": {
"@vue/devtools-api": "^7.7.7"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"typescript": ">=4.5.0",
"vue": "^3.5.11"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/pinia/node_modules/@vue/devtools-api": {
"version": "7.7.9",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz",
"integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==",
"license": "MIT",
"dependencies": {
"@vue/devtools-kit": "^7.7.9"
}
},
"node_modules/pinia/node_modules/@vue/devtools-kit": {
"version": "7.7.9",
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz",
"integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==",
"license": "MIT",
"dependencies": {
"@vue/devtools-shared": "^7.7.9",
"birpc": "^2.3.0",
"hookable": "^5.5.3",
"mitt": "^3.0.1",
"perfect-debounce": "^1.0.0",
"speakingurl": "^14.0.1",
"superjson": "^2.2.2"
}
},
"node_modules/pinia/node_modules/@vue/devtools-shared": {
"version": "7.7.9",
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz",
"integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==",
"license": "MIT",
"dependencies": {
"rfdc": "^1.4.1"
}
},
"node_modules/pinia/node_modules/perfect-debounce": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
"license": "MIT"
},
"node_modules/pkg-types": { "node_modules/pkg-types": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz",
@@ -7755,6 +7843,34 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/socket.io-client": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz",
"integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.4.1",
"engine.io-client": "~6.6.1",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz",
"integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.4.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -9356,6 +9472,27 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1" "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
} }
}, },
"node_modules/ws": {
"version": "8.18.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/wsl-utils": { "node_modules/wsl-utils": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz",
@@ -9382,6 +9519,14 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/xmlhttprequest-ssl": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/y18n": { "node_modules/y18n": {
"version": "5.0.8", "version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",

View File

@@ -20,7 +20,9 @@
"axios": "^1.2.1", "axios": "^1.2.1",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"leaflet-geosearch": "^4.2.2", "leaflet-geosearch": "^4.2.2",
"pinia": "^3.0.4",
"quasar": "^2.16.0", "quasar": "^2.16.0",
"socket.io-client": "^4.8.3",
"vue": "^3.5.22", "vue": "^3.5.22",
"vue-router": "^5.0.0" "vue-router": "^5.0.0"
}, },

View File

@@ -12,7 +12,8 @@ export default defineConfig((/* ctx */) => {
// --> boot files are part of "main.js" // --> boot files are part of "main.js"
// https://v2.quasar.dev/quasar-cli-vite/boot-files // https://v2.quasar.dev/quasar-cli-vite/boot-files
boot: [ boot: [
'axios' 'axios',
'socket',
], ],
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#css // https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#css
@@ -98,9 +99,17 @@ export default defineConfig((/* ctx */) => {
proxy: { proxy: {
// proxy all requests starting with /api to jsonplaceholder // proxy all requests starting with /api to jsonplaceholder
'/api': { '/api': {
target: 'http://strixx.famor.org:8000', target: 'http://localhost:8000',
changeOrigin: true, changeOrigin: true,
}, },
'/socket.io': {
target: 'http://localhost:8000', // Your backend WebSocket server
secure: false, // Set to true if using wss://
ws: true, // Enable WebSocket proxying
rewriteWsOrigin: true,
changeOrigin: true,
// rewrite: (path) => path.replace(/^\/socket.io/, ''),
}
}, },
}, },

31
src/boot/socket.ts Normal file
View File

@@ -0,0 +1,31 @@
import { defineBoot } from '#q-app/wrappers';
import type { Socket } from 'socket.io-client';
import { io } from 'socket.io-client';
import type { StatusUpdate } from 'src/types';
interface ServerToClientEvents {
noArg: () => void;
basicEmit: (a: number, b: string, c: Buffer) => void;
withAck: (d: string, callback: (e: number) => void) => void;
status_update: (d: StatusUpdate) => void;
}
interface ClientToServerEvents {
message: (data: string) => void;
connect: () => void;
disconnect: () => void;
set_location: (latitude: number, longitude: number, callback: (response: { success: boolean; data: { latitude: number; longitude: number }; message?: string }) => void) => void;
request_update: (callback: (response: { statusUpdate: StatusUpdate }) => void) => void;
command: (command: string, callback: (response: { success: boolean; message?: string }) => void ) => void;
shutdown: (delay: number, callback: (response: { success: boolean; message?: string }) => void) => void;
// ... other events
}
const socket: Socket<ServerToClientEvents, ClientToServerEvents> = io();
export default defineBoot(({ app }) => {
app.config.globalProperties.$socket = socket;
});
export { socket };

View File

@@ -51,7 +51,7 @@ import "leaflet/dist/leaflet.css";
import type { Map, LeafletMouseEvent } from 'leaflet'; import type { Map, LeafletMouseEvent } from 'leaflet';
import SetLocationDialog from "components/SetLocationDialog.vue"; import SetLocationDialog from "components/SetLocationDialog.vue";
import StatusBar from "components/StatusBar.vue" import StatusBar from "components/StatusBar.vue"
import { api } from "src/boot/axios"; import { api } from "boot/axios";
const $q = useQuasar(); const $q = useQuasar();
const mapRef = ref(null); const mapRef = ref(null);

View File

@@ -0,0 +1,23 @@
<script setup lang="ts">
import { socket } from 'boot/socket';
import { useStatusStore } from 'stores/status';
import { computed } from 'vue';
const statusStore = useStatusStore();
const socketStatus = computed(() => statusStore.socketConnected ? 'green' : 'red');
socket.off();
statusStore.socketConnect();
statusStore.bindEvents();
</script>
<template>
<div class="flex flex-center col q-ma-lg q-gutter-md">
<q-btn round icon="webhook">
<q-badge floating :color="socketStatus" rounded />
</q-btn>
<q-btn label="Connect" @click="statusStore.socketConnect" />
<q-btn label="Disconnect" @click="statusStore.socketDisconnect" />
<q-btn label="Emit Hello" @click="socket.emit('message', 'Hello from Vue!')" />
</div>
</template>

View File

@@ -1,25 +1,33 @@
<script setup lang="ts"> <script setup lang="ts">
import { useQuasar } from 'quasar';
import { ref } from "vue"; import { ref, onMounted } from 'vue';
import { api } from 'boot/axios'; import { api } from 'boot/axios';
const $q = useQuasar();
const statusDev = ref({ color: 'red', deviceName: 'No connected Device' });
async function getStatus() {
const statusDev = ref( { "color": "red", "deviceName" : "No connected Device"} )
function getStatus():
try { try {
const { data } = await api( { const { data } = await api({
method: "get", method: 'get',
url: "/usbmux/status" url: '/status',
}); });
console.log("API Call: usbmux/status returned:" data) console.log('API Call: usbmux/status returned:', data);
} catch (error: unknown) {
if (error instanceof Error) {
console.error('Error setting location:', error.message);
$q.notify({ type: 'negative', message: error.message });
} else {
console.error('Error setting location:', error);
}
} }
}
onMounted(async () => {
await getStatus();
});
</script> </script>
<template> <template>

View File

@@ -1,5 +1,6 @@
<template> <template>
<q-page class="row items-start justify-evenly"> <q-page class="row items-start justify-evenly">
<SocketTest />
<div class="col"></div> <div class="col"></div>
<div class="col"> <div class="col">
<div class="q-pa-md"> <div class="q-pa-md">
@@ -15,6 +16,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useQuasar } from 'quasar' import { useQuasar } from 'quasar'
import { computed } from 'vue' import { computed } from 'vue'
import SocketTest from 'components/SocketTest.vue'
const $q = useQuasar() const $q = useQuasar()
const darkStatus = computed(() => $q.dark.isActive ? 'dark_mode' : 'light_mode') const darkStatus = computed(() => $q.dark.isActive ? 'dark_mode' : 'light_mode')

32
src/stores/index.ts Normal file
View File

@@ -0,0 +1,32 @@
import { defineStore } from '#q-app/wrappers'
import { createPinia } from 'pinia'
/*
* When adding new properties to stores, you should also
* extend the `PiniaCustomProperties` interface.
* @see https://pinia.vuejs.org/core-concepts/plugins.html#Typing-new-store-properties
*/
declare module 'pinia' {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface PiniaCustomProperties {
// add your custom properties here, if any
}
}
/*
* If not building with SSR mode, you can
* directly export the Store instantiation;
*
* The function below can be async too; either use
* async/await or return a Promise which resolves
* with the Store instance.
*/
export default defineStore((/* { ssrContext } */) => {
const pinia = createPinia()
// You can add Pinia plugins here
// pinia.use(SomePiniaPlugin)
return pinia
})

34
src/stores/status.ts Normal file
View File

@@ -0,0 +1,34 @@
import { acceptHMRUpdate, defineStore } from 'pinia';
import { socket } from 'boot/socket';
export const useStatusStore = defineStore('status', {
state: () => ({
device: {},
socketConnected: false,
}),
actions: {
bindEvents() {
socket.on('connect', () => {
this.socketConnected = true;
});
socket.on('disconnect', () => {
this.socketConnected = false;
});
socket.on('status_update', (data) => {
this.$patch((state) => {
Object.assign(state.device, data);
});
});
},
socketConnect() {
socket.connect();
},
socketDisconnect() {
socket.disconnect();
},
},
});
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useStatusStore, import.meta.hot));
}

23
src/types.ts Normal file
View File

@@ -0,0 +1,23 @@
export interface DeviceShort {
udid: string | null;
connection_type: string | null;
}
export interface StatusUpdate {
device_connected: boolean;
device_count: number;
// devices?: Array<DeviceShort>;
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;
}