mirror of
https://github.com/ad1217/PrinterStatus
synced 2024-11-10 18:45:08 -05:00
Move octoprint communication to the server side with websockets
This commit is contained in:
parent
f163fde565
commit
ba54ba3db4
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
/.cache/
|
||||
/dist/
|
||||
/node_modules/
|
||||
/src/*.js
|
||||
/config.yaml
|
||||
|
71
package-lock.json
generated
71
package-lock.json
generated
@ -177,6 +177,32 @@
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@types/js-yaml": {
|
||||
"version": "3.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.1.tgz",
|
||||
"integrity": "sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "12.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.4.tgz",
|
||||
"integrity": "sha512-W0+n1Y+gK/8G2P/piTkBBN38Qc5Q1ZSO6B5H3QmPCUewaiXOo2GCAWZ4ElZCcNhjJuBSUSLGFUJnmlCn5+nxOQ=="
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.0.tgz",
|
||||
"integrity": "sha512-TLFRywthBgL68auWj+ziWu+vnmmcHCDFC/sqCOQf1xTz4hRq8cu79z8CtHU9lncExGBsB8fXA4TiLDLt6xvMzw==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/ws": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.3.tgz",
|
||||
"integrity": "sha512-yBTM0P05Tx9iXGq00BbJPo37ox68R5vaGTXivs6RGh/BQ6QP5zqZDGWdAO6JbRE/iR1l80xeGAwCQS2nMV9S/w==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@vue/component-compiler-utils": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.0.0.tgz",
|
||||
@ -248,6 +274,14 @@
|
||||
"readable-stream": "^2.0.6"
|
||||
}
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"requires": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
|
||||
@ -261,6 +295,11 @@
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
},
|
||||
"async-limiter": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
|
||||
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
@ -478,6 +517,11 @@
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
@ -735,6 +779,15 @@
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.13.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
|
||||
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"jsbn": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||
@ -861,6 +914,11 @@
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
|
||||
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
|
||||
},
|
||||
"node-gyp": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.0.3.tgz",
|
||||
@ -1095,6 +1153,11 @@
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
|
||||
},
|
||||
"sshpk": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
|
||||
@ -1317,6 +1380,14 @@
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.1.2.tgz",
|
||||
"integrity": "sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg==",
|
||||
"requires": {
|
||||
"async-limiter": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||
|
14
package.json
14
package.json
@ -7,9 +7,21 @@
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/js-yaml": "^3.12.1",
|
||||
"@types/node": "^12.7.4",
|
||||
"@types/node-fetch": "^2.5.0",
|
||||
"@types/ws": "^6.0.3",
|
||||
"js-yaml": "^3.13.1",
|
||||
"node-fetch": "^2.6.0",
|
||||
"node-gyp": "^5.0.3",
|
||||
"vue": "^2.6.10",
|
||||
"vue-hot-reload-api": "^2.3.3",
|
||||
"vue-property-decorator": "^8.2.2"
|
||||
"vue-property-decorator": "^8.2.2",
|
||||
"ws": "^7.1.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc src/server.ts",
|
||||
"start": "parcel src/index.html",
|
||||
"serve": "npm run build && node src/server.js"
|
||||
}
|
||||
}
|
||||
|
51
src/App.vue
51
src/App.vue
@ -1,30 +1,47 @@
|
||||
<template>
|
||||
<div>
|
||||
<PrinterTile
|
||||
v-for="printer in printers"
|
||||
:key="printer.address"
|
||||
v-bind="printer"
|
||||
<PrinterCard
|
||||
v-for="(status, name) in printers"
|
||||
:key="name"
|
||||
:name="name"
|
||||
:status="status"
|
||||
>
|
||||
</PrinterTile>
|
||||
</PrinterCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component, Prop } from 'vue-property-decorator';
|
||||
|
||||
import PrinterTile from './PrinterTile.vue';
|
||||
import * as messages from './messages';
|
||||
import * as octoprint from './octoprint';
|
||||
import PrinterCard from './PrinterCard.vue';
|
||||
|
||||
@Component({ components: { PrinterTile } })
|
||||
@Component({ components: { PrinterCard } })
|
||||
export default class App extends Vue {
|
||||
printers = [
|
||||
{
|
||||
address: 'http://octopi.local:5000/',
|
||||
apikey: 'BEF073DD42A64431BDD72D83FA563DF5',
|
||||
},
|
||||
{
|
||||
address: 'http://octopi.local:5000/',
|
||||
apikey: 'BEF073DD42A64431BDD72D83FA563DF5',
|
||||
},
|
||||
];
|
||||
websocket!: WebSocket;
|
||||
printers: {
|
||||
[key: string]: octoprint.CurrentOrHistoryPayload | null;
|
||||
} = {};
|
||||
|
||||
mounted() {
|
||||
let loc = window.location;
|
||||
// TODO: make dynamic
|
||||
// const ws_uri: string = loc.protocol === 'https' ? 'wss://' : 'ws://' + loc.host + '/ws';
|
||||
const ws_uri = 'ws://localhost:4321';
|
||||
this.websocket = new WebSocket(ws_uri);
|
||||
this.websocket.onmessage = (ev: MessageEvent) => {
|
||||
const event: messages.ExtendedMessage = JSON.parse(ev.data as string);
|
||||
console.log(event);
|
||||
|
||||
if ('init' in event) {
|
||||
this.$set(this.printers, event.printer, null);
|
||||
} else if ('current' in event) {
|
||||
this.$set(this.printers, event.printer, event.current);
|
||||
} else if ('history' in event) {
|
||||
this.$set(this.printers, event.printer, event.history);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
60
src/PrinterCard.vue
Normal file
60
src/PrinterCard.vue
Normal file
@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-header">{{ name || 'Unknown' }}</div>
|
||||
<div v-if="webcamURL">
|
||||
<img class="webcam" :src="webcamURL" />
|
||||
</div>
|
||||
<div v-if="status">
|
||||
<div>{{ status.state.text }}</div>
|
||||
<div>Job File Name: {{ status.job.file.name || 'None' }}</div>
|
||||
<div>
|
||||
Job Completion:
|
||||
<progress
|
||||
v-if="status.progress.completion"
|
||||
:value="status.progress.completion"
|
||||
>
|
||||
{{ status.progress.completion }}
|
||||
</progress>
|
||||
<span v-else> - </span>
|
||||
</div>
|
||||
<div>User: {{ status.job.user || '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component, Prop } from 'vue-property-decorator';
|
||||
|
||||
import * as octoprint from './octoprint';
|
||||
|
||||
@Component
|
||||
export default class PrinterCard extends Vue {
|
||||
@Prop(String) readonly name!: string;
|
||||
@Prop(String) readonly webcamURL!: string;
|
||||
@Prop(Object) readonly status?: octoprint.CurrentOrHistoryPayload;
|
||||
|
||||
mounted() {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.card {
|
||||
display: inline-block;
|
||||
margin: 1em;
|
||||
padding: 1em;
|
||||
border-radius: 3px;
|
||||
box-shadow: rgba(0, 0, 0, 0.2) 0px 3px 1px -2px,
|
||||
rgba(0, 0, 0, 0.14) 0px 2px 2px 0px, rgba(0, 0, 0, 0.12) 0px 1px 5px 0px;
|
||||
|
||||
.card-header {
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
padding-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
.webcam {
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
@ -1,107 +0,0 @@
|
||||
<template>
|
||||
<div v-if="currentJob" class="card">
|
||||
<div class="card-header">{{ name || 'Unknown' }}</div>
|
||||
<div v-if="webcamURL">
|
||||
<img class="webcam" :src="webcamURL" />
|
||||
</div>
|
||||
<div>Job File Name: {{ currentJob.job.file.name || 'None' }}</div>
|
||||
<div>
|
||||
Job Completion:
|
||||
<progress
|
||||
v-if="currentJob.progress.completion"
|
||||
:value="currentJob.progress.completion"
|
||||
>
|
||||
{{ currentJob.progress.completion }}
|
||||
</progress>
|
||||
<span v-else> - </span>
|
||||
</div>
|
||||
<div>User: {{ currentJob.job.user || '-' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component, Prop } from 'vue-property-decorator';
|
||||
|
||||
interface IJobInfo {
|
||||
job: {
|
||||
file: {
|
||||
name: string;
|
||||
display: string;
|
||||
path: string;
|
||||
type: string;
|
||||
typePath: Array<string>;
|
||||
};
|
||||
user?: string;
|
||||
estimatedPrintTime?: number;
|
||||
lastPrintTime?: number;
|
||||
filament?: {
|
||||
length?: number;
|
||||
volume?: number;
|
||||
};
|
||||
};
|
||||
progress: {
|
||||
completion: number;
|
||||
filepos: number;
|
||||
printTime: number;
|
||||
printTimeLeft: number;
|
||||
};
|
||||
state: string;
|
||||
}
|
||||
|
||||
@Component
|
||||
export default class PrinterTile extends Vue {
|
||||
@Prop(String) readonly address!: string;
|
||||
@Prop(String) readonly apikey!: string;
|
||||
|
||||
name: string = '';
|
||||
webcamURL: string | null = null;
|
||||
currentJob: IJobInfo | null = null;
|
||||
|
||||
mounted() {
|
||||
fetch(this.address + '/api/settings', {
|
||||
headers: {
|
||||
'X-Api-Key': this.apikey,
|
||||
},
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(r => {
|
||||
this.webcamURL = r.webcam.streamUrl;
|
||||
this.name = r.appearance.name;
|
||||
})
|
||||
.then(() =>
|
||||
fetch(this.address + '/api/job', {
|
||||
headers: {
|
||||
'X-Api-Key': this.apikey,
|
||||
},
|
||||
})
|
||||
)
|
||||
.then(r => r.json())
|
||||
.then(r => {
|
||||
this.currentJob = r;
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.card {
|
||||
display: inline-block;
|
||||
margin: 1em;
|
||||
padding: 1em;
|
||||
border-radius: 3px;
|
||||
box-shadow: rgba(0, 0, 0, 0.2) 0px 3px 1px -2px,
|
||||
rgba(0, 0, 0, 0.14) 0px 2px 2px 0px, rgba(0, 0, 0, 0.12) 0px 1px 5px 0px;
|
||||
|
||||
.card-header {
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
padding-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
.webcam {
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
5
src/messages.d.ts
vendored
Normal file
5
src/messages.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
import { Message } from './octoprint';
|
||||
|
||||
export type ExtendedMessage = (Message | { init?: null }) & {
|
||||
printer: string;
|
||||
};
|
113
src/octoprint.d.ts
vendored
Normal file
113
src/octoprint.d.ts
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
export interface JobInformation {
|
||||
file: {
|
||||
name: string;
|
||||
display: string;
|
||||
path: string;
|
||||
type: string;
|
||||
typePath: Array<string>;
|
||||
};
|
||||
user?: string;
|
||||
estimatedPrintTime?: number;
|
||||
lastPrintTime?: number;
|
||||
filament?: {
|
||||
length?: number;
|
||||
volume?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface JobResponse {
|
||||
job: JobInformation;
|
||||
progress: ProgressInformation;
|
||||
state: string;
|
||||
}
|
||||
|
||||
export interface ProgressInformation {
|
||||
completion: number;
|
||||
filepos: number;
|
||||
printTime: number;
|
||||
printTimeLeft: number;
|
||||
}
|
||||
|
||||
export interface PrinterState {
|
||||
text: string;
|
||||
flags: {
|
||||
operational: boolean;
|
||||
paused: boolean;
|
||||
printing: boolean;
|
||||
pausing: boolean;
|
||||
cancelling: boolean;
|
||||
sdReady: boolean;
|
||||
error: boolean;
|
||||
ready: boolean;
|
||||
closedOrError: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface TemperatureOffsets {
|
||||
// 'tool{n}' or 'bed'
|
||||
[key: string]: number;
|
||||
}
|
||||
|
||||
export interface TemperatureData {
|
||||
actual: number;
|
||||
target: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
export interface HistoricTemperatureDataPoint {
|
||||
time: number; // unix timestamp
|
||||
bed: TemperatureData;
|
||||
// 'tool{n}'
|
||||
[key: string]: TemperatureData | number;
|
||||
}
|
||||
|
||||
export interface LoginResponse {
|
||||
name: string;
|
||||
active: boolean;
|
||||
admin: boolean;
|
||||
user: boolean;
|
||||
apikey: string;
|
||||
settings: { [key: string]: string };
|
||||
session: string;
|
||||
_is_external_client: boolean;
|
||||
}
|
||||
|
||||
export interface CurrentOrHistoryPayload {
|
||||
state: PrinterState;
|
||||
job: JobInformation;
|
||||
progress: ProgressInformation;
|
||||
currentZ: number;
|
||||
offsets?: TemperatureOffsets;
|
||||
temps: HistoricTemperatureDataPoint;
|
||||
}
|
||||
|
||||
export interface SlicingProgressMessage {
|
||||
slicingProgress: {
|
||||
slicer: string;
|
||||
source_location: string;
|
||||
source_path: string;
|
||||
dest_location: string;
|
||||
dest_path: string;
|
||||
progress: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface ConnectedMessage {
|
||||
connected: {
|
||||
apikey: string;
|
||||
version: string;
|
||||
branch: string;
|
||||
display_version: string;
|
||||
plugin_hash: string;
|
||||
config_hash: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface CurrentOrHistoryMessage {
|
||||
current: CurrentOrHistoryPayload;
|
||||
history: CurrentOrHistoryPayload;
|
||||
}
|
||||
|
||||
export type Message = Partial<
|
||||
SlicingProgressMessage | ConnectedMessage | CurrentOrHistoryMessage
|
||||
>;
|
131
src/server.ts
Normal file
131
src/server.ts
Normal file
@ -0,0 +1,131 @@
|
||||
import * as fs from 'fs';
|
||||
import * as url from 'url';
|
||||
|
||||
import fetch from 'node-fetch';
|
||||
import * as messages from './messages';
|
||||
import * as octoprint from './octoprint';
|
||||
import * as WebSocket from 'ws';
|
||||
import * as yaml from 'js-yaml';
|
||||
|
||||
// Load config
|
||||
const config: {
|
||||
printers: { address: string; apikey: string }[];
|
||||
} = yaml.safeLoad(fs.readFileSync('config.yaml', 'utf8'));
|
||||
|
||||
const proxyServer = new WebSocket.Server({ host: '127.0.0.1', port: 4321 });
|
||||
let printerStatuses: PrinterStatus[] = [];
|
||||
|
||||
function broadcast(data: WebSocket.Data) {
|
||||
proxyServer.clients.forEach((client: WebSocket) => {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.send(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function broadcastPayload(payload: messages.ExtendedMessage) {
|
||||
broadcast(JSON.stringify(payload));
|
||||
}
|
||||
|
||||
class PrinterStatus {
|
||||
wss: WebSocket.Server;
|
||||
address: string;
|
||||
apikey: string;
|
||||
|
||||
webcamURL?: string;
|
||||
name?: string;
|
||||
|
||||
websocket?: WebSocket;
|
||||
lastStatus?: messages.ExtendedMessage;
|
||||
|
||||
constructor(wss: WebSocket.Server, address: string, apikey: string) {
|
||||
this.wss = wss;
|
||||
this.address = address;
|
||||
this.apikey = apikey;
|
||||
|
||||
try {
|
||||
this.init(); // async init
|
||||
} catch (e) {
|
||||
throw 'Failed to Init' + e;
|
||||
}
|
||||
}
|
||||
|
||||
async init() {
|
||||
// TODO: error handling (try/catch)
|
||||
const settings = await this.api_get('settings');
|
||||
this.webcamURL = settings.webcam.streamUrl;
|
||||
this.name = settings.appearance.name;
|
||||
|
||||
// do passive login to get a session key from the API key
|
||||
const login: octoprint.LoginResponse = await this.api_post('login', {
|
||||
passive: 'true',
|
||||
});
|
||||
|
||||
this.websocket = new WebSocket(
|
||||
url.resolve(this.address, '/sockjs/websocket')
|
||||
);
|
||||
this.websocket
|
||||
.on('open', () => {
|
||||
this.websocket!.send(
|
||||
JSON.stringify({ auth: login.name + ':' + login.session })
|
||||
);
|
||||
})
|
||||
.on('message', (data: WebSocket.Data) => {
|
||||
const event: octoprint.Message = JSON.parse(data as string);
|
||||
console.log(event);
|
||||
|
||||
let ext_event: messages.ExtendedMessage = {
|
||||
...event,
|
||||
printer: this.name!,
|
||||
};
|
||||
broadcastPayload(ext_event);
|
||||
|
||||
if ('current' in event || 'history' in event) {
|
||||
this.lastStatus = ext_event;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async api_get(endpoint: string): Promise<any> {
|
||||
const r = await fetch(url.resolve(this.address, '/api/' + endpoint), {
|
||||
headers: { 'X-Api-Key': this.apikey },
|
||||
});
|
||||
return await r.json();
|
||||
}
|
||||
|
||||
async api_post(endpoint: string, data: any): Promise<any> {
|
||||
const r = await fetch(url.resolve(this.address, '/api/' + endpoint), {
|
||||
headers: {
|
||||
'X-Api-Key': this.apikey,
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
return await r.json();
|
||||
}
|
||||
|
||||
send_init(ws: WebSocket) {
|
||||
let payload: messages.ExtendedMessage;
|
||||
console.log(this.lastStatus);
|
||||
if (this.lastStatus) {
|
||||
payload = this.lastStatus;
|
||||
} else {
|
||||
payload = { init: null, printer: this.name! };
|
||||
}
|
||||
ws.send(JSON.stringify(payload));
|
||||
}
|
||||
}
|
||||
|
||||
function init_printers() {
|
||||
printerStatuses = config.printers.map(
|
||||
printer => new PrinterStatus(proxyServer, printer.address, printer.apikey)
|
||||
);
|
||||
}
|
||||
|
||||
init_printers();
|
||||
|
||||
proxyServer.on('connection', (ws: WebSocket) => {
|
||||
printerStatuses.forEach((ps: PrinterStatus) => ps.send_init(ws));
|
||||
});
|
Loading…
Reference in New Issue
Block a user