Cleaned up the code a bit, added some testing code for UDAs for path handler stuff.
This commit is contained in:
parent
b7da823ddb
commit
d9310d5979
|
|
@ -152,6 +152,9 @@ private void map(
|
|||
handler.addMapping(method, API_PATH ~ subPath, HttpRequestHandler.of(fn));
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter that adds CORS response headers.
|
||||
*/
|
||||
private class CorsFilter : HttpRequestFilter {
|
||||
private string webOrigin;
|
||||
|
||||
|
|
@ -168,6 +171,10 @@ private class CorsFilter : HttpRequestFilter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter that rejects requests with a body that's too large, to avoid issues
|
||||
* later with handling such large objects in memory.
|
||||
*/
|
||||
private class ContentLengthFilter : HttpRequestFilter {
|
||||
const MAX_LENGTH = 1024 * 1024 * 20; // 2MB limit
|
||||
|
||||
|
|
@ -192,6 +199,10 @@ private class ContentLengthFilter : HttpRequestFilter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter that catches any exception thrown by the filter chain, and nicely
|
||||
* formats the response status and message.
|
||||
*/
|
||||
private class ExceptionHandlingFilter : HttpRequestFilter {
|
||||
void doFilter(ref ServerHttpRequest request, ref ServerHttpResponse response, FilterChain filterChain) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,37 +1,73 @@
|
|||
import handy_http_transport;
|
||||
import slf4d;
|
||||
import slf4d.default_provider;
|
||||
import scheduled;
|
||||
import std.datetime;
|
||||
|
||||
import api_mapping;
|
||||
import util.config;
|
||||
import analytics;
|
||||
import scheduled_jobs;
|
||||
|
||||
/**
|
||||
* Starts the Finnow API.
|
||||
*/
|
||||
void main() {
|
||||
// testUDA();
|
||||
|
||||
const config = readConfig();
|
||||
configureSlf4d(config);
|
||||
startScheduledJobs();
|
||||
startWebServer(config);
|
||||
}
|
||||
|
||||
void configureSlf4d(in AppConfig config) {
|
||||
Level logLevel = getConfiguredLoggingLevel(config);
|
||||
auto provider = new DefaultProvider(logLevel);
|
||||
configureLoggingProvider(provider);
|
||||
infoF!"Loaded app config: port = %d, webOrigin = %s"(config.port, config.webOrigin);
|
||||
|
||||
// Start scheduled tasks in a separate thread:
|
||||
JobSchedule analyticsSchedule = new FixedIntervalSchedule(
|
||||
hours(1),
|
||||
Clock.currTime(UTC()) + seconds(10)
|
||||
);
|
||||
|
||||
JobScheduler jobScheduler = new TaskPoolScheduler();
|
||||
jobScheduler.addJob(() {
|
||||
info("Computing account balance time series analytics for all users...");
|
||||
doForAllUserProfiles(&computeAccountBalanceTimeSeries);
|
||||
doForAllUserProfiles(&computeCategorySpendTimeSeries);
|
||||
info("Done computing analytics!");
|
||||
}, analyticsSchedule);
|
||||
jobScheduler.start();
|
||||
}
|
||||
|
||||
void startWebServer(in AppConfig config) {
|
||||
Http1TransportConfig transportConfig = defaultConfig();
|
||||
transportConfig.port = config.port;
|
||||
HttpTransport transport = new TaskPoolHttp1Transport(mapApiHandlers(config.webOrigin), transportConfig);
|
||||
transport.start();
|
||||
}
|
||||
|
||||
// void testUDA() {
|
||||
// import std.traits : getSymbolsByUDA;
|
||||
// import std.stdio;
|
||||
// static assert(getSymbolsByUDA!(app, Attr).length == 2);
|
||||
// Attr a;
|
||||
// static foreach(symbol; getSymbolsByUDA!(app, Attr)) {
|
||||
// pragma(msg, symbol);
|
||||
// pragma(msg, __traits(identifier, symbol));
|
||||
// pragma(msg, "------------------");
|
||||
// static foreach(attr; __traits(getAttributes, symbol)) {
|
||||
// pragma(msg, "Attribute:");
|
||||
// pragma(msg, attr);
|
||||
// pragma(msg, __traits(identifier, attr));
|
||||
// static if (is(typeof(attr) == Attr)) {
|
||||
// pragma(msg, "Found target attribute!");
|
||||
// pragma(msg, attr.val);
|
||||
// a = attr;
|
||||
// writefln!"Function %s has attr val = %d"((__traits(identifier, symbol)), a.val);
|
||||
// } else {
|
||||
// pragma(msg, "Other attribute :(");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// struct Attr {
|
||||
// int val;
|
||||
// }
|
||||
|
||||
// enum OtherAttr;
|
||||
|
||||
// @Attr(5) @OtherAttr
|
||||
// void testMethod1() {
|
||||
// int x = 5;
|
||||
// }
|
||||
|
||||
// @Attr(42)
|
||||
// void testMethod2() {
|
||||
// int y = 5;
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
module scheduled_jobs;
|
||||
|
||||
import scheduled;
|
||||
import std.datetime;
|
||||
import slf4d;
|
||||
|
||||
import analytics;
|
||||
|
||||
void startScheduledJobs() {
|
||||
JobSchedule analyticsSchedule = new FixedIntervalSchedule(
|
||||
hours(1),
|
||||
Clock.currTime(UTC()) + seconds(5)
|
||||
);
|
||||
|
||||
JobScheduler jobScheduler = new TaskPoolScheduler();
|
||||
jobScheduler.addJob(() {
|
||||
info("Computing account balance time series analytics for all users...");
|
||||
doForAllUserProfiles(&computeAccountBalanceTimeSeries);
|
||||
doForAllUserProfiles(&computeCategorySpendTimeSeries);
|
||||
info("Done computing analytics!");
|
||||
}, analyticsSchedule);
|
||||
jobScheduler.start();
|
||||
}
|
||||
|
|
@ -2,12 +2,34 @@ module util.config;
|
|||
|
||||
import std.stdio;
|
||||
import slf4d;
|
||||
import asdf;
|
||||
|
||||
/**
|
||||
* The path of the config file to attempt to load.
|
||||
*/
|
||||
private const CONFIG_FILE = "finnow-api-config.json";
|
||||
|
||||
/**
|
||||
* Finnow API configuration struct, which contains properties used to
|
||||
* configure various parts of the API.
|
||||
*/
|
||||
struct AppConfig {
|
||||
/**
|
||||
* The port on which the HTTP server will accept requests.
|
||||
*/
|
||||
ushort port;
|
||||
/**
|
||||
* The address at which the corresponding Finnow website is available to
|
||||
* clients. In development, this will be another localhost address, but in
|
||||
* deployed environments, it'll be the actual website with a legitimate
|
||||
* domain name. This is used to supply the Access-Control-Allow-Origin
|
||||
* CORS header, which can help to prevent cross-site-scripting attacks.
|
||||
*/
|
||||
string webOrigin;
|
||||
/**
|
||||
* The logging level to use globally in the application. See SLF4D for more:
|
||||
* <a>https://andrewlalis.github.io/slf4d/guide/using-slf4d.html#logging-levels</a>
|
||||
*/
|
||||
string logLevel;
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +53,8 @@ AppConfig readConfig() {
|
|||
);
|
||||
// Local dev environment if no config is given.
|
||||
if (!exists(CONFIG_FILE)) {
|
||||
const defaultConfigJson = serializeToJson(defaultConfig);
|
||||
infoF!"No config file \"%s\" found. Using defaults: %s."(CONFIG_FILE, defaultConfigJson);
|
||||
return defaultConfig;
|
||||
}
|
||||
JSONValue obj;
|
||||
|
|
|
|||
Loading…
Reference in New Issue