-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathserver.js
141 lines (117 loc) · 4.28 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// node server.js --port 8080 --meshtastic-api-url https://10.1.0.249
import axios from "axios";
import express from "express";
import commandLineArgs from "command-line-args";
import commandLineUsage from "command-line-usage";
// fixme: setup http agent to allow invalid cert for axios instead?
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
const optionsList = [
{
name: "help",
alias: "h",
type: Boolean,
description: "Display this usage guide."
},
{
name: "port",
type: Number,
description: "Port to serve Web UI and API from. e.g: 8080",
},
{
name: "meshtastic-api-url",
type: String,
description: "The URL to a Meshtastic devices HTTP API. e.g: https://10.1.0.123",
},
];
// parse command line args
const options = commandLineArgs(optionsList);
function main() {
// show help
if(options.help){
const usage = commandLineUsage([
{
header: "MeshTXT Server",
content: "A server that hosts the MeshTXT Web UI and runs a proxy to a Meshtastic devices HTTP API.",
},
{
header: "Options",
optionList: optionsList,
},
]);
console.log(usage);
return;
}
// get options and fallback to default values
const port = options["port"] ?? 8080;
const meshtasticApiUrl = options["meshtastic-api-url"] ?? "https://localhost";
// if provided, ensure meshtastic api url is http or https
if(meshtasticApiUrl !== "" && !meshtasticApiUrl.startsWith("http://") && !meshtasticApiUrl.startsWith("https://")){
console.log("ERROR: --meshtastic-api-url must start with http:// or https://");
return;
}
// create express app
const app = express();
// allow retrieving raw request body as buffer
app.use((req, res, next) => {
const chunks = [];
req.on("data", (chunk) => chunks.push(chunk));
req.on("end", () => {
req.rawBody = Buffer.concat(chunks);
next();
});
});
// serve vite app from /dist
app.use("/", express.static("./dist"));
// setup proxy endpoints to meshtasticd if api url was provided
if(meshtasticApiUrl !== ""){
// proxy fromradio to meshtasticd to allow connecting to localhost to bypass cors
app.get("/api/v1/fromradio", async (req, res) => {
try {
// proxy fromradio request to meshtasticd endpoint
const response = await axios({
method: "GET",
responseType: "arraybuffer",
url: `${meshtasticApiUrl}/api/v1/fromradio`,
params: req.query,
});
// send response back
res.status(response.status).set({
"Content-Type": "application/x-protobuf",
"Content-Length": response.data.length,
}).send(response.data);
} catch(e) {
console.error(`Proxy error: ${e.message}`);
res.status(502).send("Proxy Error");
}
});
app.put("/api/v1/toradio", async (req, res) => {
try {
// proxy toradio request to meshtasticd endpoint
const response = await axios({
method: "PUT",
responseType: "arraybuffer",
url: `${meshtasticApiUrl}/api/v1/toradio`,
headers: {
"Content-Type": "application/x-protobuf",
"Content-Length": req.rawBody.length,
},
data: req.rawBody,
params: req.query,
});
// send response back
res.status(response.status).set({
"Content-Type": "application/x-protobuf",
"Content-Length": response.data.length,
}).send(response.data);
} catch(e) {
console.error(`Proxy error: ${e.message}`);
res.status(502).send("Proxy Error");
}
});
}
// run server
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
}
main();