2023-08-16 14:37:39 +00:00
|
|
|
import handy_httpd;
|
|
|
|
import slf4d;
|
|
|
|
import slf4d.default_provider;
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
auto provider = new shared DefaultProvider(true, Levels.INFO);
|
2023-08-24 19:37:25 +00:00
|
|
|
// provider.getLoggerFactory().setModuleLevelPrefix("handy_httpd", Levels.DEBUG);
|
2023-08-16 14:37:39 +00:00
|
|
|
configureLoggingProvider(provider);
|
|
|
|
|
|
|
|
HttpServer server = initServer();
|
|
|
|
server.start();
|
|
|
|
}
|
|
|
|
|
2023-08-22 14:05:26 +00:00
|
|
|
/**
|
|
|
|
* Initializes the HTTP server that this app will run.
|
|
|
|
* Returns: The HTTP server to use.
|
|
|
|
*/
|
2023-08-16 14:37:39 +00:00
|
|
|
private HttpServer initServer() {
|
2023-11-16 20:29:36 +00:00
|
|
|
import handy_httpd.handlers.path_handler;
|
2023-08-16 14:37:39 +00:00
|
|
|
import handy_httpd.handlers.filtered_handler;
|
2023-08-18 14:37:52 +00:00
|
|
|
import d_properties;
|
2023-08-22 14:05:26 +00:00
|
|
|
import endpoints.auth;
|
|
|
|
import endpoints.lists;
|
2023-08-24 19:37:25 +00:00
|
|
|
import endpoints.admin;
|
2023-08-18 14:37:52 +00:00
|
|
|
import std.file;
|
|
|
|
import std.conv;
|
2023-08-16 14:37:39 +00:00
|
|
|
|
2023-08-24 19:37:25 +00:00
|
|
|
import auth : TokenFilter, AdminFilter, loadTokenSecret;
|
|
|
|
|
2023-08-16 14:37:39 +00:00
|
|
|
ServerConfig config = ServerConfig.defaultValues();
|
|
|
|
config.enableWebSockets = false;
|
|
|
|
config.workerPoolSize = 3;
|
|
|
|
config.connectionQueueSize = 10;
|
2023-08-22 14:05:26 +00:00
|
|
|
bool useCorsHeaders = true;
|
2023-08-18 14:37:52 +00:00
|
|
|
if (exists("application.properties")) {
|
|
|
|
Properties props = Properties("application.properties");
|
|
|
|
if (props.has("port")) {
|
|
|
|
config.port = props.get("port").to!ushort;
|
|
|
|
}
|
|
|
|
if (props.has("workers")) {
|
|
|
|
config.workerPoolSize = props.get("workers").to!size_t;
|
|
|
|
}
|
|
|
|
if (props.has("hostname")) {
|
|
|
|
config.hostname = props.get("hostname");
|
|
|
|
}
|
2023-08-22 14:05:26 +00:00
|
|
|
if (props.has("useCorsHeaders")) {
|
|
|
|
useCorsHeaders = props.get("useCorsHeaders").to!bool;
|
|
|
|
}
|
2023-08-18 14:37:52 +00:00
|
|
|
}
|
|
|
|
|
2023-08-22 14:05:26 +00:00
|
|
|
if (useCorsHeaders) {
|
|
|
|
// Set some CORS headers to prevent headache.
|
|
|
|
config.defaultHeaders["Access-Control-Allow-Origin"] = "*";
|
|
|
|
config.defaultHeaders["Access-Control-Allow-Credentials"] = "true";
|
|
|
|
config.defaultHeaders["Access-Control-Allow-Methods"] = "*";
|
|
|
|
config.defaultHeaders["Vary"] = "origin";
|
|
|
|
config.defaultHeaders["Access-Control-Allow-Headers"] = "Authorization";
|
|
|
|
}
|
2023-08-16 14:37:39 +00:00
|
|
|
|
2023-08-18 14:37:52 +00:00
|
|
|
immutable string API_PATH = "/api";
|
2023-08-16 14:37:39 +00:00
|
|
|
|
2023-11-16 20:29:36 +00:00
|
|
|
PathHandler mainHandler = new PathHandler();
|
2023-08-22 14:44:10 +00:00
|
|
|
mainHandler.addMapping(Method.GET, API_PATH ~ "/status", &handleStatus);
|
2023-08-24 19:37:25 +00:00
|
|
|
mainHandler.addMapping(Method.POST, API_PATH ~ "/register", &createNewUser);
|
|
|
|
mainHandler.addMapping(Method.POST, API_PATH ~ "/login", &handleLogin);
|
|
|
|
// mainHandler.addMapping(Method.GET, API_PATH ~ "/shutdown", (ref HttpRequestContext ctx) {
|
|
|
|
// ctx.response.writeBodyString("Shutting down!");
|
|
|
|
// ctx.server.stop();
|
|
|
|
// });
|
2023-08-17 15:55:05 +00:00
|
|
|
|
2023-08-24 19:37:25 +00:00
|
|
|
HttpRequestHandler optionsHandler = toHandler((ref HttpRequestContext ctx) {
|
2023-08-17 15:55:05 +00:00
|
|
|
ctx.response.setStatus(HttpStatus.OK);
|
|
|
|
});
|
2023-08-24 19:37:25 +00:00
|
|
|
mainHandler.addMapping(Method.OPTIONS, API_PATH ~ "/**", optionsHandler);
|
2023-08-17 15:55:05 +00:00
|
|
|
|
2023-08-24 19:37:25 +00:00
|
|
|
// Separate handler for authenticated paths, protected by a TokenFilter.
|
2023-11-16 20:29:36 +00:00
|
|
|
PathHandler authHandler = new PathHandler();
|
2023-08-24 19:37:25 +00:00
|
|
|
authHandler.addMapping(Method.GET, API_PATH ~ "/me", &getMyUser);
|
|
|
|
authHandler.addMapping(Method.DELETE, API_PATH ~ "/me", &deleteMyUser);
|
|
|
|
authHandler.addMapping(Method.GET, API_PATH ~ "/renew-token", &renewToken);
|
2023-08-18 14:37:52 +00:00
|
|
|
|
2023-08-24 19:37:25 +00:00
|
|
|
authHandler.addMapping(Method.GET, API_PATH ~ "/lists", &getNoteLists);
|
|
|
|
authHandler.addMapping(Method.POST, API_PATH ~ "/lists", &createNoteList);
|
2023-11-16 20:29:36 +00:00
|
|
|
authHandler.addMapping(Method.GET, API_PATH ~ "/lists/:id:ulong", &getNoteList);
|
|
|
|
authHandler.addMapping(Method.DELETE, API_PATH ~ "/lists/:id:ulong", &deleteNoteList);
|
|
|
|
authHandler.addMapping(Method.POST, API_PATH ~ "/lists/:listId:ulong/notes", &createNote);
|
|
|
|
authHandler.addMapping(Method.DELETE, API_PATH ~ "/lists/:listId:ulong/notes/:noteId:ulong", &deleteNote);
|
|
|
|
authHandler.addMapping(Method.DELETE, API_PATH ~ "/lists/:listId:ulong/notes", &deleteAllNotes);
|
2023-08-24 19:37:25 +00:00
|
|
|
HttpRequestFilter tokenFilter = new TokenFilter(loadTokenSecret());
|
|
|
|
HttpRequestFilter adminFilter = new AdminFilter();
|
2023-08-18 14:37:52 +00:00
|
|
|
|
2023-08-24 19:37:25 +00:00
|
|
|
// Separate handler for admin paths, protected by an AdminFilter.
|
2023-11-16 20:29:36 +00:00
|
|
|
PathHandler adminHandler = new PathHandler();
|
2023-08-24 19:37:25 +00:00
|
|
|
adminHandler.addMapping(Method.GET, API_PATH ~ "/admin/users", &getAllUsers);
|
|
|
|
mainHandler.addMapping(API_PATH ~ "/admin/**", new FilteredRequestHandler(adminHandler, [tokenFilter, adminFilter]));
|
|
|
|
|
|
|
|
mainHandler.addMapping(API_PATH ~ "/**", new FilteredRequestHandler(authHandler, [tokenFilter]));
|
2023-08-18 14:37:52 +00:00
|
|
|
|
2023-08-16 14:37:39 +00:00
|
|
|
return new HttpServer(mainHandler, config);
|
|
|
|
}
|
2023-08-22 14:44:10 +00:00
|
|
|
|
|
|
|
void handleStatus(ref HttpRequestContext ctx) {
|
|
|
|
import resusage;
|
|
|
|
import std.process;
|
|
|
|
import std.json;
|
|
|
|
|
|
|
|
immutable int pId = thisProcessID();
|
|
|
|
ProcessMemInfo procInfo = processMemInfo(pId);
|
|
|
|
JSONValue data = JSONValue(string[string].init);
|
|
|
|
data.object["virtualMemory"] = JSONValue(procInfo.usedVirtMem);
|
|
|
|
data.object["physicalMemory"] = JSONValue(procInfo.usedRAM);
|
|
|
|
ctx.response.writeBodyString(data.toString(), "application/json");
|
|
|
|
}
|