|
@@ -0,0 +1,88 @@
|
|
|
|
|
+using MHD;
|
|
|
|
|
+
|
|
|
|
|
+namespace Astralis {
|
|
|
|
|
+
|
|
|
|
|
+ public class Server : Object {
|
|
|
|
|
+ private Daemon daemon;
|
|
|
|
|
+ private Router router;
|
|
|
|
|
+ private int port;
|
|
|
|
|
+
|
|
|
|
|
+ public Server(int port) {
|
|
|
|
|
+ this.port = port;
|
|
|
|
|
+ this.router = new Router();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void map_get(string path, owned RouteHandler handler) {
|
|
|
|
|
+ router.map_get(path, (owned) handler);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private int access_handler (Connection connection, string? url, string? method, string? version, string? upload_data, size_t* upload_data_size, void** con_cls) {
|
|
|
|
|
+
|
|
|
|
|
+ // Initial call for this request
|
|
|
|
|
+ if (con_cls[0] == null) {
|
|
|
|
|
+ // Determine request type, allocate context etc.
|
|
|
|
|
+ // For this simple example, we just mark it as seen (non-null).
|
|
|
|
|
+ con_cls[0] = (void*) 1;
|
|
|
|
|
+ return Result.YES;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (upload_data_size[0] != 0) {
|
|
|
|
|
+ // We don't handle upload data in this scaffold yet.
|
|
|
|
|
+ upload_data_size[0] = 0;
|
|
|
|
|
+ return Result.YES;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var request = new HttpRequest(connection, url ?? "", method ?? "", version ?? "");
|
|
|
|
|
+ var response = new HttpResponse();
|
|
|
|
|
+ var context = new HttpContext(request, response);
|
|
|
|
|
+
|
|
|
|
|
+ bool handled = router.handle(context);
|
|
|
|
|
+
|
|
|
|
|
+ if (!handled) {
|
|
|
|
|
+ response.status_code = 404;
|
|
|
|
|
+ response.body = "Not Found";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Create MHD response
|
|
|
|
|
+ var mhd_response = new Response.from_buffer(
|
|
|
|
|
+ response.body.length,
|
|
|
|
|
+ response.body.data,
|
|
|
|
|
+ ResponseMemoryMode.RESPMEM_MUST_COPY
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ mhd_response.add_header("Content-Type", response.content_type);
|
|
|
|
|
+
|
|
|
|
|
+ int ret = MHD.queue_response(connection, response.status_code, mhd_response);
|
|
|
|
|
+
|
|
|
|
|
+ // In C we'd destroy response here, but Vala handles memory management via the binding's free_function hopefully,
|
|
|
|
|
+ // OR we'd need to be careful. The VAPI says free_function = MHD_destroy_response, so Vala will call it when the object goes out of scope.
|
|
|
|
|
+ // However, MHD_queue_response usually increments refcount or copies?
|
|
|
|
|
+ // Actually MHD_create_response.. returns a response with refcount 1.
|
|
|
|
|
+ // MHD_queue_response increments it.
|
|
|
|
|
+ // So if our wrapper object dies, it calls destroy, which decrements.
|
|
|
|
|
+ // That should be correct.
|
|
|
|
|
+
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void run() {
|
|
|
|
|
+ daemon = Daemon.start(
|
|
|
|
|
+ MHD.USE_SELECT_INTERNALLY | MHD.USE_DEBUG,
|
|
|
|
|
+ (uint16) this.port,
|
|
|
|
|
+ null,
|
|
|
|
|
+ (connection, url, method, version, upload_data, upload_data_size, con_cls) => {
|
|
|
|
|
+ // Trampoline to instance method if needed, or just use lambda capturing 'this'
|
|
|
|
|
+ return this.access_handler(connection, url, method, version, upload_data, upload_data_size, con_cls);
|
|
|
|
|
+ },
|
|
|
|
|
+ MHD.OPTION_END
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (daemon == null) {
|
|
|
|
|
+ error("Failed to start daemon");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ print(@"Server running on port $port\nPress Ctrl+C to stop...\n");
|
|
|
|
|
+ new MainLoop().run();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|