154 lines
4.8 KiB
JavaScript
154 lines
4.8 KiB
JavaScript
/**
|
|
* @fileoverview
|
|
* Global mixin providing access to the LabThings (WoT) API.
|
|
*
|
|
* This mixin is registered globally in `main.js` using. Do not
|
|
* manually import it in components.
|
|
*/
|
|
import axios from "axios";
|
|
import { useWotStore } from "@/stores/wot.js";
|
|
import { useSettingsStore } from "@/stores/settings.js";
|
|
import { mapState, mapStores } from "pinia";
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
pollTimers: {},
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
...mapState(useSettingsStore, ["baseUri"]),
|
|
...mapStores(useWotStore),
|
|
},
|
|
|
|
methods: {
|
|
thingDescription(thing) {
|
|
return this.wotStore.thingDescriptions[thing];
|
|
},
|
|
thingList() {
|
|
return this.wotStore.thingList();
|
|
},
|
|
thingAvailable(thing) {
|
|
return this.wotStore.thingAvailable(thing);
|
|
},
|
|
thingPropertyUrl(thing, property, allowUndefined = false) {
|
|
return this.wotStore.thingPropertyUrl(thing, property, "readproperty", allowUndefined);
|
|
},
|
|
thingActionUrl(thing, action, allowUndefined = false) {
|
|
return this.wotStore.thingActionUrl(thing, action, "invokeaction", allowUndefined);
|
|
},
|
|
thingActionAvailable(thing, action) {
|
|
return this.wotStore.thingAffordanceAvailable(thing, "actions", action);
|
|
},
|
|
thingPropertyAvailable(thing, property) {
|
|
return this.wotStore.thingAffordanceAvailable(thing, "properties", property);
|
|
},
|
|
async readThingProperty(thing, property, silenceErrors = false) {
|
|
let url = this.wotStore.thingPropertyUrl(thing, property, "readproperty", false);
|
|
try {
|
|
let response = await axios.get(url);
|
|
return response.data;
|
|
} catch (error) {
|
|
if (!silenceErrors) this.modalError(error);
|
|
return undefined;
|
|
}
|
|
},
|
|
async writeThingProperty(thing, property, value) {
|
|
let url = this.wotStore.thingPropertyUrl(thing, property, "writeproperty", false);
|
|
// `false` and 0 fail because axios turns it to ""
|
|
// Other values should not be stringified or pydantic
|
|
// can't parse them.
|
|
if (value === false || value === true || value === 0) {
|
|
value = JSON.stringify(value);
|
|
}
|
|
await axios.put(url, value);
|
|
},
|
|
async invokeAction(thing, action, data, handleErrors = true) {
|
|
let url = this.thingActionUrl(thing, action);
|
|
try {
|
|
let response = await axios.post(url, data);
|
|
return response;
|
|
} catch (error) {
|
|
if (handleErrors) {
|
|
this.modalError(error);
|
|
return undefined;
|
|
} else {
|
|
throw error;
|
|
}
|
|
}
|
|
},
|
|
async pollUntilComplete(
|
|
taskUrl,
|
|
ongoingMethod,
|
|
finalMethod,
|
|
interval = 500,
|
|
modalErrors = true,
|
|
) {
|
|
let response;
|
|
let finalMethodCalled = false;
|
|
try {
|
|
response = await axios.get(taskUrl, { baseURL: this.baseUri });
|
|
const result = response.data.status;
|
|
|
|
if (result === "running" || result === "pending") {
|
|
ongoingMethod?.(response);
|
|
this.pollTimers[taskUrl] = setTimeout(() => {
|
|
this.pollUntilComplete(taskUrl, ongoingMethod, finalMethod, interval);
|
|
}, interval);
|
|
} else {
|
|
clearTimeout(this.pollTimers[taskUrl]);
|
|
delete this.pollTimers[taskUrl];
|
|
finalMethodCalled = true;
|
|
finalMethod?.(response);
|
|
}
|
|
} catch (error) {
|
|
this.$emit("error", error);
|
|
if (modalErrors) {
|
|
this.modalError(error);
|
|
}
|
|
clearTimeout(this.pollTimers[taskUrl]);
|
|
delete this.pollTimers[taskUrl];
|
|
if (!finalMethodCalled) {
|
|
finalMethod?.(response);
|
|
}
|
|
}
|
|
},
|
|
terminateAction(taskUrl) {
|
|
axios.delete(taskUrl, { baseURL: this.baseUri });
|
|
},
|
|
async findOngoingActions(thing, action) {
|
|
let url = this.thingActionUrl(thing, action);
|
|
try {
|
|
return await axios.get(url);
|
|
} catch (error) {
|
|
console.warn("checkExistingTasks: request failed", error);
|
|
return null;
|
|
}
|
|
},
|
|
/**
|
|
* Find and ongoing Action and return its task response.
|
|
*
|
|
* Returns null if there is no ongoing action
|
|
*/
|
|
async getOngoingAction(thing, action) {
|
|
let response = await this.findOngoingActions(thing, action);
|
|
// Exit if response is null, due to an error.
|
|
if (response == null) return null;
|
|
// Check for a task that is ongoing.
|
|
// We can't handle multiple tasks ongoing, so this picks the first.
|
|
// ?? Is the "Nullish Coalescing-Operator" to turn undefined into null.
|
|
return response.data.find((t) => ["pending", "running"].includes(t.status)) ?? null;
|
|
},
|
|
|
|
async getThingEndpoint(thing, endpoint) {
|
|
let url = `${this.baseUri}/${thing}/${endpoint}`;
|
|
try {
|
|
const response = await axios.get(url);
|
|
return response.data;
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
},
|
|
},
|
|
};
|