diff --git a/railsignal-app/src/api/components.js b/railsignal-app/src/api/components.js new file mode 100644 index 0000000..ecb5c76 --- /dev/null +++ b/railsignal-app/src/api/components.js @@ -0,0 +1,80 @@ +import axios from "axios"; +import {API_URL} from "./constants"; + +export function refreshComponents(rs) { + return new Promise((resolve, reject) => { + axios.get(`${API_URL}/rs/${rs.id}/c`) + .then(response => { + const previousSelectedComponentId = rs.selectedComponent ? rs.selectedComponent.id : null; + rs.components = response.data; + if (previousSelectedComponentId !== null) { + const previousComponent = rs.components.find(c => c.id === previousSelectedComponentId); + if (previousComponent) { + rs.selectedComponent = previousComponent; + } else { + rs.selectedComponent = null; + } + } else { + rs.selectedComponent = null; + } + resolve(); + }) + .catch(reject); + }); +} + +export function refreshSomeComponents(rs, components) { + const promises = []; + for (let i = 0; i < components.length; i++) { + const promise = new Promise((resolve, reject) => { + axios.get(`${API_URL}/rs/${rs.id}/c/${components[i].id}`) + .then(resp => { + const idx = rs.components.findIndex(c => c.id === resp.data.id); + if (idx > -1) rs.components[idx] = resp.data; + resolve(); + }) + .catch(reject); + }); + promises.push(promise); + } + return Promise.all(promises); +} + +export function getComponent(rs, id) { + return new Promise((resolve, reject) => { + axios.get(`${this.apiUrl}/rs/${rs.id}/c/${id}`) + .then(response => resolve(response.data)) + .catch(reject); + }); +} + +export function createComponent(rs, data) { + return new Promise((resolve, reject) => { + axios.post(`${API_URL}/rs/${rs.id}/c`, data) + .then(response => { + const newComponentId = response.data.id; + refreshComponents(rs) + .then(() => { + const newComponent = rs.components.find(c => c.id === newComponentId); + if (newComponent) { + rs.selectedComponent = newComponent; + } + resolve(); + }) + .catch(reject); + }) + .catch(reject); + }); +} + +export function removeComponent(rs, id) { + return new Promise((resolve, reject) => { + axios.delete(`${API_URL}/rs/${rs.id}/c/${id}`) + .then(() => { + refreshComponents(rs) + .then(resolve) + .catch(reject); + }) + .catch(reject); + }); +} diff --git a/railsignal-app/src/api/constants.js b/railsignal-app/src/api/constants.js new file mode 100644 index 0000000..51239b5 --- /dev/null +++ b/railsignal-app/src/api/constants.js @@ -0,0 +1,2 @@ +export const API_URL = import.meta.env.VITE_API_URL; +export const WS_URL = import.meta.env.VITE_WS_URL; \ No newline at end of file diff --git a/railsignal-app/src/api/paths.js b/railsignal-app/src/api/paths.js new file mode 100644 index 0000000..afd74f5 --- /dev/null +++ b/railsignal-app/src/api/paths.js @@ -0,0 +1,44 @@ +import axios from "axios"; +import {API_URL} from "./constants"; +import {refreshSomeComponents} from "./components"; + +export function updateConnections(rs, node) { + return new Promise((resolve, reject) => { + axios.patch( + `${API_URL}/rs/${rs.id}/c/${node.id}/connectedNodes`, + node + ) + .then(response => { + node.connectedNodes = response.data.connectedNodes; + resolve(); + }) + .catch(reject); + }); +} + +export function addConnection(rs, node, other) { + node.connectedNodes.push(other); + return updateConnections(rs, node); +} + +export function removeConnection(rs, node, other) { + const idx = node.connectedNodes.findIndex(n => n.id === other.id); + return new Promise((resolve, reject) => { + if (idx > -1) { + node.connectedNodes.splice(idx, 1); + updateConnections(rs, node) + .then(() => { + const nodes = []; + nodes.push(...node.connectedNodes); + nodes.push(other); + refreshSomeComponents(rs, nodes) + .then(resolve) + .catch(reject); + }) + .catch(reject); + } else { + resolve(); + } + }); + +} \ No newline at end of file diff --git a/railsignal-app/src/api/railSystems.js b/railsignal-app/src/api/railSystems.js new file mode 100644 index 0000000..10b8660 --- /dev/null +++ b/railsignal-app/src/api/railSystems.js @@ -0,0 +1,38 @@ +import axios from "axios"; +import {API_URL} from "./constants"; + +export function refreshRailSystems(rsStore) { + return new Promise(resolve => { + axios.get(`${API_URL}/rs`) + .then(response => { + rsStore.railSystems = response.data; + resolve(); + }) + .catch(error => console.error(error)); + }) +} + +export function createRailSystem(rsStore, name) { + return new Promise((resolve, reject) => { + axios.post(`${API_URL}/rs`, {name: name}) + .then(response => { + const newId = response.data.id; + refreshRailSystems(rsStore) + .then(() => resolve(rsStore.railSystems.find(rs => rs.id === newId))) + .catch(error => reject(error)); + }) + .catch(error => reject(error)); + }); +} + +export function removeRailSystem(rsStore, id) { + return new Promise((resolve, reject) => { + axios.delete(`${API_URL}/rs/${id}`) + .then(() => { + rsStore.selectedRailSystem = null; + refreshRailSystems(rsStore) + .then(() => resolve) + .catch(error => reject(error)); + }); + }); +} diff --git a/railsignal-app/src/api/segments.js b/railsignal-app/src/api/segments.js new file mode 100644 index 0000000..c49e0ec --- /dev/null +++ b/railsignal-app/src/api/segments.js @@ -0,0 +1,50 @@ +import axios from "axios"; +import {API_URL} from "./constants"; + +/** + * Fetches the set of segments for a rail system. + * @param {Number} rsId + * @returns {Promise<[Object]>} + */ +export function getSegments(rsId) { + return new Promise((resolve, reject) => { + axios.get(`${API_URL}/rs/${rsId}/s`) + .then(response => resolve(response.data)) + .catch(error => reject(error)); + }); +} + +export function refreshSegments(rs) { + return new Promise(resolve => { + getSegments(rs.id) + .then(segments => { + rs.segments = segments; + resolve(); + }) + .catch(error => console.error(error)); + }); +} + +export function createSegment(rs, name) { + return new Promise((resolve, reject) => { + axios.post(`${API_URL}/rs/${rs.id}/s`, {name: name}) + .then(() => { + refreshSegments(rs) + .then(() => resolve()) + .catch(error => reject(error)); + }) + .catch(error => reject(error)); + }); +} + +export function removeSegment(rs, segmentId) { + return new Promise((resolve, reject) => { + axios.delete(`${API_URL}/rs/${rs.id}/${segmentId}`) + .then(() => { + refreshSegments(rs) + .then(() => resolve()) + .catch(error => reject(error)); + }) + .catch(error => reject(error)); + }); +} diff --git a/railsignal-app/src/api/websocket.js b/railsignal-app/src/api/websocket.js new file mode 100644 index 0000000..3f4276d --- /dev/null +++ b/railsignal-app/src/api/websocket.js @@ -0,0 +1,33 @@ +import {WS_URL} from "./constants"; + +export function establishWebsocketConnection(rs) { + if (rs.websocket) { + rs.websocket.close(); + } + rs.websocket = new WebSocket(`${WS_URL}/${rs.id}`); + rs.websocket.onopen = () => { + console.log("Opened websocket connection to rail system " + rs.id); + }; + rs.websocket.onclose = event => { + if (event.code !== 1000) { + console.warn("Lost websocket connection. Attempting to reestablish."); + setTimeout(() => { + establishWebsocketConnection(rs); + }, 3000); + } + console.log("Closed websocket connection to rail system " + rs.id); + }; + rs.websocket.onmessage = msg => { + console.log(msg); + }; + rs.websocket.onerror = error => { + console.log(error); + }; +} + +export function closeWebsocketConnection(rs) { + if (rs.websocket) { + rs.websocket.close(); + rs.websocket = null; + } +} diff --git a/railsignal-app/src/components/AppNavbar.vue b/railsignal-app/src/components/AppNavbar.vue index cf86a87..efc5878 100644 --- a/railsignal-app/src/components/AppNavbar.vue +++ b/railsignal-app/src/components/AppNavbar.vue @@ -23,7 +23,7 @@