cleanup directory strucutre and fine tune

This commit is contained in:
Joe Tretter
2022-09-30 10:55:07 -05:00
parent dae7fbc9e7
commit 9b25fa2eda
19 changed files with 69 additions and 27 deletions

18
app/Dockerfile Normal file
View File

@@ -0,0 +1,18 @@
FROM node:current-slim
# To Create nodejsapp directory
WORKDIR /nodejsapp
# To Install All dependencies
COPY package*.json .
RUN npm install
# To copy all application packages
COPY . .
# expose the data dir as a volume
VOLUME [ "dataDir" ]
# Expose port 1280 and Run the server.js file to start node js application
EXPOSE 1280
CMD [ "node", "dumbserver.js" ]

233
app/dumbserver.js Normal file
View File

@@ -0,0 +1,233 @@
//
// Dependencies
//
let http = require("http");
let fs = require("fs");
//
// Constants
//
let DATA_LOCATION = "dataDir/data"; // both the url root and the location of data file
let DATA_LOCATION_LEN = DATA_LOCATION.length;
let DATA_FILE = __dirname + "/" + DATA_LOCATION;
let PORT = 1280;
//
// Load store file
//
let store = {}; // deafult empty object
let json = "";
try {
let json = fs.readFileSync(DATA_FILE);
store = JSON.parse(json);
console.log("Read store file");
} catch (e) {
// lazy error handling
console.log("Could not load store file. Using empty array.");
}
//
// Flush to store file on exit
//
let flush = function () {
console.log("Flushing data to file [" + DATA_FILE + "]\n");
fs.writeFileSync(DATA_FILE, JSON.stringify(store));
};
let handleInterrupt = function () {
flush();
process.exit();
};
process.on("SIGINT", handleInterrupt);
process.on("SIGTERM", handleInterrupt);
process.on("SIGHUP", flush); // HUP flushes to file but keeps the server running
//
// If request URI is prefixed with the value of DATA_LOCATION, we treat incoming request as a REST request
// Otherwise we serve the file referenced by the URI
//
let serveFile = function (loc, req, resp) {
let fullPath = __dirname + "/" + loc;
console.log("Trying to serve file at [" + fullPath + "]");
if (req.method !== "GET") {
// read only!
resp.writeHead(405);
resp.write("Unsupported method\n");
resp.end();
} else if (fs.existsSync(fullPath)) {
resp.writeHead(200);
fs.createReadStream(fullPath).pipe(resp);
} else {
resp.writeHead(404);
resp.write("Not Found\n");
resp.end();
}
};
let serveRestData = function (urlPath, req, resp) {
console.log(req.method + " request for path [" + urlPath + "]");
switch (req.method) {
case "GET":
let exactMatch = !urlPath.endsWith("/");
let matchFound = false;
if (exactMatch) {
// assumes that only a single resource has this ID.
console.log(" - Exact Match.");
if (store.hasOwnProperty(urlPath)) {
resp.writeHead(200, { "Content-Type": "application/json" });
resp.write(JSON.stringify(store[urlPath]) + "\n");
matchFound = true;
}
} else {
console.log(" - All Matches.");
let matches = [];
Object.keys(store).forEach((theKey) => {
if (theKey.startsWith(urlPath)) {
matches.push(store[theKey]);
matchFound = true;
}
});
if (matchFound) {
resp.writeHead(200, { "Content-Type": "application/json" });
resp.write(JSON.stringify(matches));
}
}
if (!matchFound) {
console.log(" - Match NOT found.");
resp.writeHead(404, { "Content-Type": "application/json" });
resp.write('{"success":false, "error":"Not Found"}');
} else {
console.log(" - Match found.");
}
resp.end();
break;
case "PUT":
json = "";
req.on("data", function (chunk) {
json += chunk;
});
req.on("end", function () {
try {
let data = JSON.parse(json);
store[urlPath] = data;
resp.writeHead(201, { "Content-Type": "application/json" });
resp.write('{"success":true}');
} catch (e) {
resp.writeHead(400, { "Content-Type": "application/json" });
resp.write('{"success":false, "error":"Invalid JSON"}');
}
resp.end();
flush();
});
break;
case "POST":
json = "";
req.on("data", function (chunk) {
json += chunk;
});
req.on("end", function () {
try {
let data = JSON.parse(json);
if (data.ID === undefined) {
resp.writeHead(400, { "Content-Type": "application/json" });
resp.write('{"success":false, "error":"The ID Field needs to be given"}');
} else {
// make sure the ID from the data is used as the final resource Identifier,
// even if the URL has none or says different.
let re = new RegExp("/[^/]*$");
urlPath = urlPath.replace(re, "");
urlPath = urlPath + "/" + data.ID;
console.log(" - storing with resource key: [" + urlPath + "]");
store[urlPath] = data;
resp.writeHead(201, { "Content-Type": "application/json" });
resp.write(JSON.stringify(store[urlPath]));
}
} catch (e) {
resp.writeHead(400, { "Content-Type": "application/json" });
resp.write('{"success":false, "error":"Invalid JSON"}');
}
resp.end();
flush();
});
break;
case "PATCH":
json = "";
req.on("data", function (chunk) {
json += chunk;
});
req.on("end", function () {
try {
let data = JSON.parse(json);
Object.keys(data).forEach((theKey) => {
store[urlPath][theKey] = data[theKey];
});
resp.writeHead(201, { "Content-Type": "application/json" });
resp.write('{"success":true}');
} catch (e) {
resp.writeHead(400, { "Content-Type": "application/json" });
resp.write('{"success":false, "error":"Invalid JSON"}');
}
resp.end();
flush();
});
break;
case "OPTIONS":
resp.end();
break;
case "DELETE":
if (store.hasOwnProperty(urlPath)) {
delete store[urlPath];
resp.writeHead(204, { "Content-Type": "application/json" });
resp.write('{"success":true}');
} else {
resp.writeHead(404, { "Content-Type": "application/json" });
resp.write('{"success":false, "error":"Not Found"}');
}
resp.end();
flush();
break;
default:
resp.writeHead(405, { "Content-Type": "application/json" });
resp.write('{"success":false, "error":"Unsupported method"}');
resp.end();
}
};
//
// Listen for connections
//
http
.createServer(function (req, resp) {
// CORS headers
resp.setHeader("Access-Control-Allow-Origin", "*");
resp.setHeader("Access-Control-Allow-Headers", "X-Request-With, content-type");
resp.setHeader("Vary", "Origin");
resp.setHeader("Access-Control-Allow-Methods", "GET, PATCH, POST, PUT, DELETE, OPTIONS");
console.log("Serving [" + req.url + "]");
if (req.url === "/") {
// server index file
serveFile("index.html", req, resp);
} else {
// rest request
serveRestData(req.url, req, resp);
}
})
.listen(PORT);

9
app/index.html Normal file
View File

@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
Dumbserver
</head>
<body>
<p>Server version: 2022-09-30_10_21_17</p>
</body>
</html>

19
app/package.json Normal file
View File

@@ -0,0 +1,19 @@
{
"name": "dumbserver",
"version": "1.0.0",
"description": "",
"main": "dumbserver.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/noelbennett/dumbserver.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/noelbennett/dumbserver/issues"
},
"homepage": "https://github.com/noelbennett/dumbserver#readme"
}