From 5967b959b45d5ca92bc0e4a406314fe81d378b94 Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Sun, 19 May 2019 14:45:58 -0400 Subject: [PATCH 1/8] remove spurious dependency --- cgi.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgi.d b/cgi.d index 2d3a872..d4e44c5 100644 --- a/cgi.d +++ b/cgi.d @@ -7264,7 +7264,7 @@ auto serveStaticFile(string urlPrefix, string filename = null, string contentTyp contentType = "application/javascript"; } - static bool handler(string urlPrefix, Cgi cgi, WebPresenter!() presenter, DispatcherDetails details) { + static bool handler(string urlPrefix, Cgi cgi, Object presenter, DispatcherDetails details) { if(details.contentType.indexOf("image/") == 0) cgi.setCache(true); cgi.setResponseContentType(details.contentType); From 67d1e861154cd28f60c5bf339ed9154a7e38ccfa Mon Sep 17 00:00:00 2001 From: Murilo Miranda Date: Mon, 3 Jun 2019 03:51:48 -0300 Subject: [PATCH 2/8] Adding 2 more properties I have added properties for the other 2 vertexes of the Rectangle, the upperRight and the lowerLeft vertexes. --- color.d | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/color.d b/color.d index dd863d0..e7d17d1 100644 --- a/color.d +++ b/color.d @@ -1480,15 +1480,29 @@ struct Rectangle { this(upperLeft.x, upperLeft.y, upperLeft.x + size.width, upperLeft.y + size.height); } - /// - @property Point upperLeft() { - return Point(left, top); - } + /// + @property Point upperLeft() + { + return Point(left, top); + } - /// - @property Point lowerRight() { - return Point(right, bottom); - } + /// + @property Point upperRight() + { + return Point(right, top); + } + + /// + @property Point lowerLeft() + { + return Point(left, bottom); + } + + /// + @property Point lowerRight() + { + return Point(right, bottom); + } /// @property Size size() { From 6ab8c638a1f3fbdcd2259ae16f4d6e2e45db94f8 Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Mon, 3 Jun 2019 08:33:47 -0400 Subject: [PATCH 3/8] thanks to MuriloMir for finding bug --- color.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/color.d b/color.d index dd863d0..9c73dcc 100644 --- a/color.d +++ b/color.d @@ -1512,7 +1512,7 @@ struct Rectangle { /// ditto bool contains(in Point p) { - return (p.x >= left && p.y < right && p.y >= top && p.y < bottom); + return (p.x >= left && p.x < right && p.y >= top && p.y < bottom); } /// Returns true of the two rectangles at any point overlap From 9dd03c3158977038302feb9bb45cc6cd77bb89d5 Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Mon, 3 Jun 2019 08:39:56 -0400 Subject: [PATCH 4/8] change style to mine again --- color.d | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/color.d b/color.d index caeaea6..897db9a 100644 --- a/color.d +++ b/color.d @@ -1480,29 +1480,25 @@ struct Rectangle { this(upperLeft.x, upperLeft.y, upperLeft.x + size.width, upperLeft.y + size.height); } - /// - @property Point upperLeft() - { - return Point(left, top); - } + /// + @property Point upperLeft() { + return Point(left, top); + } - /// - @property Point upperRight() - { - return Point(right, top); - } + /// + @property Point upperRight() { + return Point(right, top); + } - /// - @property Point lowerLeft() - { - return Point(left, bottom); - } + /// + @property Point lowerLeft() { + return Point(left, bottom); + } - /// - @property Point lowerRight() - { - return Point(right, bottom); - } + /// + @property Point lowerRight() { + return Point(right, bottom); + } /// @property Size size() { From 856da3de534e86e7b8465b38ef3f801810b8f622 Mon Sep 17 00:00:00 2001 From: Andre Pany Date: Fri, 14 Jun 2019 13:36:01 +0200 Subject: [PATCH 5/8] Dub.json update for terminal, cgi, http2 --- dub.json | 28 ++++++++++++++++++++-------- package.d | 1 + 2 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 package.d diff --git a/dub.json b/dub.json index 364dda4..7441070 100644 --- a/dub.json +++ b/dub.json @@ -1,9 +1,15 @@ { "name": "arsd-official", - "targetType": "none", - "sourcePaths": ["."], + "targetType": "library", + "importPaths": ["."], + "sourceFiles": ["package.d"], "description": "A container of various subpackages that do lots of different things. You should use one of the subpackages instead of the main package in most cases, but you can try the complete package if you get duplicated dependency issues.", "license":"BSL-1.0", + "dependencies": { + ":cgi": "*", + ":http": "*", + ":terminal": "*" + }, "subPackages": [ { "name": "simpledisplay", @@ -87,8 +93,10 @@ { "name": "cgi", "description": "web server library with cgi, fastcgi, scgi, and embedded http server support", - "targetType": "sourceLibrary", - "sourceFiles": ["cgi.d"] + "targetType": "library", + "sourceFiles": ["cgi.d"], + "importPaths": ["."], + "dflags": ["-mv=arsd.cgi=cgi.d"] }, { "name": "mysql", @@ -132,8 +140,10 @@ "description": "HTTP client library. Depends on OpenSSL right now on all platforms. On 32 bit Windows, you may need to get OMF openssl lib and dlls (ask me if you can't find it)", "libs": ["crypto", "ssl"], "versions": ["with_openssl"], - "targetType": "sourceLibrary", - "sourceFiles": ["http2.d"] + "targetType": "library", + "sourceFiles": ["http2.d"], + "importPaths": ["."], + "dflags": ["-mv=arsd.http2=http2.d"] }, { "name": "jsvar", @@ -151,8 +161,10 @@ { "name": "terminal", "description": "Cross-platform Terminal I/O with color, mouse support, real time input, etc.", - "targetType": "sourceLibrary", - "sourceFiles": ["terminal.d"] + "targetType": "library", + "sourceFiles": ["terminal.d"], + "importPaths": ["."], + "dflags": ["-mv=arsd.terminal=terminal.d"] }, { "name": "ttf", diff --git a/package.d b/package.d new file mode 100644 index 0000000..f9223ed --- /dev/null +++ b/package.d @@ -0,0 +1 @@ +module arsd; \ No newline at end of file From 7629782830966ffd29382925160becd305753e3a Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Fri, 14 Jun 2019 10:10:58 -0400 Subject: [PATCH 6/8] dox --- package.d | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 package.d diff --git a/package.d b/package.d new file mode 100644 index 0000000..f95353a --- /dev/null +++ b/package.d @@ -0,0 +1,8 @@ +/++ + This package contains a variety of independent modules that I have + written over my years of using D. + + You can usually use them independently, with few or no dependencies, + so it is easy to use raw, or you can use dub packages as well. ++/ +module arsd; From 3fa87f08c4240723565d1b5ac108cf89c1a3a155 Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Fri, 14 Jun 2019 10:34:43 -0400 Subject: [PATCH 7/8] add some configurations for cgi, make embedded_httpd first and thus default --- dub.json | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/dub.json b/dub.json index 7441070..b49a8bd 100644 --- a/dub.json +++ b/dub.json @@ -96,7 +96,26 @@ "targetType": "library", "sourceFiles": ["cgi.d"], "importPaths": ["."], - "dflags": ["-mv=arsd.cgi=cgi.d"] + "dflags": ["-mv=arsd.cgi=cgi.d"], + "configurations": [ + { + "name": "embedded_httpd", + "versions": ["embedded_httpd"] + }, + { + "name": "cgi", + "versions": [""] + }, + { + "name": "fastcgi", + "versions": ["fastcgi"], + "libs": ["fcgi"] + }, + { + "name": "scgi", + "versions": ["scgi"] + } + ] }, { "name": "mysql", From 57c995f4bf7c5e599a9bf21397c9236f2acacab9 Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Sat, 15 Jun 2019 18:50:32 -0400 Subject: [PATCH 8/8] new stuff im working on --- cgi.d | 114 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 37 deletions(-) diff --git a/cgi.d b/cgi.d index d05c100..6b979b6 100644 --- a/cgi.d +++ b/cgi.d @@ -3770,11 +3770,15 @@ class ListeningConnectionManager { } semaphore.notify(); + bool hasAnyRunning; foreach(thread; threads) { if(!thread.isRunning) { thread.join(); - } + } else hasAnyRunning = true; } + + if(!hasAnyRunning) + break; } // FIXME: i typically stop this with ctrl+c which never @@ -3876,7 +3880,7 @@ class ConnectionThread : Thread { } try dg(socket); - catch(Exception e) + catch(Throwable e) socket.close(); } } @@ -5950,6 +5954,8 @@ private string beautify(string name, char space = ' ', bool allLowerCase = false } lastWasCap = true; + } else { + lastWasCap = false; } if(shouldSpace) { @@ -6260,9 +6266,11 @@ auto callFromCgi(alias method, T)(T dg, Cgi cgi) { --- class MyPresenter : WebPresenter!(MyPresenter) { + @Override void presentSuccessfulReturnAsHtml(T : CustomType)(Cgi cgi, T ret) { // present the CustomType } + @Override void presentSuccessfulReturnAsHtml(T)(Cgi cgi, T ret) { // handle everything else via the super class, which will call // back to your class when appropriate @@ -6273,6 +6281,11 @@ auto callFromCgi(alias method, T)(T dg, Cgi cgi) { +/ class WebPresenter(CRTP) { + + /// A UDA version of the built-in `override`, to be used for static template polymorphism + /// If you override a plain method, use `override`. If a template, use `@Override`. + enum Override; + string script() { return ` `; @@ -6290,7 +6303,8 @@ class WebPresenter(CRTP) { } string genericFormStyling() { - return ` + return +q"css table.automatic-data-display { border-collapse: collapse; border: solid 1px var(--mild-border); @@ -6332,28 +6346,29 @@ class WebPresenter(CRTP) { .add-array-button { } - `; +css"; } string genericSiteStyling() { - return ` + return +q"css * { box-sizing: border-box; } html, body { margin: 0px; } body { font-family: sans-serif; } - #header { + header { background: var(--accent-color); height: 64px; } - #footer { + footer { background: var(--accent-color); height: 64px; } - #main-site { + #site-container { display: flex; } - #container { + main { flex: 1 1 auto; order: 2; min-height: calc(100vh - 64px - 64px); @@ -6365,29 +6380,31 @@ class WebPresenter(CRTP) { order: 1; background: var(--sidebar-color); } - `; +css"; } import arsd.dom; Element htmlContainer() { - auto document = new Document(` + auto document = new Document(q"html + D Application - -
-
+
+
+
- +
-`, true, true); + +html", true, true); - return document.requireElementById("container"); + return document.requireSelector("main"); } /// typeof(null) (which is also used to represent functions returning `void`) do nothing @@ -6452,10 +6469,9 @@ class WebPresenter(CRTP) { } /++ - returns an arsd.dom.Element + Returns an element for a particular type +/ - auto elementFor(T)(string displayName, string name) { - import arsd.dom; + Element elementFor(T)(string displayName, string name) { import std.traits; auto div = Element.make("div"); @@ -6498,6 +6514,7 @@ class WebPresenter(CRTP) { } auto i = lbl.addChild("input", name); i.attrs.type = "checkbox"; + i.attrs.value = "true"; i.attrs.name = name; } else static if(is(T == K[], K)) { auto templ = div.addChild("template"); @@ -6522,9 +6539,8 @@ class WebPresenter(CRTP) { return div; } - /// actually returns an arsd.dom.Form - auto createAutomaticFormForFunction(alias method, T)(T dg) { - import arsd.dom; + /// creates a form for gathering the function's arguments + Form createAutomaticFormForFunction(alias method, T)(T dg) { auto form = cast(Form) Element.make("form"); @@ -6555,10 +6571,8 @@ class WebPresenter(CRTP) { return form; } - /// actually returns an arsd.dom.Form - auto createAutomaticFormForObject(T)(T obj) { - import arsd.dom; - + /// creates a form for gathering object members (for the REST object thing right now) + Form createAutomaticFormForObject(T)(T obj) { auto form = cast(Form) Element.make("form"); form.addClass("automatic-form"); @@ -6588,8 +6602,7 @@ class WebPresenter(CRTP) { } /// - auto formatReturnValueAsHtml(T)(T t) { - import arsd.dom; + Element formatReturnValueAsHtml(T)(T t) { import std.traits; static if(is(T == typeof(null))) { @@ -6826,11 +6839,23 @@ auto serveApi(T)(string urlPrefix) { auto obj = new T(); obj.initialize(cgi); - switch(cgi.pathInfo[urlPrefix.length .. $]) { - static foreach(methodName; __traits(derivedMembers, T)){{ - static if(is(typeof(__traits(getMember, T, methodName)) P == __parameters)) + /+ + Overload rules: + Any unique combination of HTTP verb and url path can be dispatched to function overloads + statically. + + Moreover, some args vs no args can be overloaded dynamically. + +/ + + string hack = to!string(cgi.requestMethod) ~ " " ~ cgi.pathInfo[urlPrefix.length .. $]; + + switch(hack) { + static foreach(methodName; __traits(derivedMembers, T)) + static foreach(idx, overload; __traits(getOverloads, T, methodName)) {{ + static if(is(typeof(overload) P == __parameters)) { - case urlNameForMethod!(__traits(getMember, T, methodName))(urlify(methodName)): + case urlNameForMethod!(overload)(urlify(methodName)): + /+ int zeroArgOverload = -1; int overloadCount = cast(int) __traits(getOverloads, T, methodName).length; bool calledWithZeroArgs = true; @@ -6902,6 +6927,7 @@ auto serveApi(T)(string urlPrefix) { so the method UDAs are irrelevant. +/ if(callFunction) + +/ switch(cgi.request("format", "html")) { case "html": try { @@ -6934,7 +6960,7 @@ auto serveApi(T)(string urlPrefix) { cgi.setResponseStatus("406 Not Acceptable"); // not exactly but sort of. return true; } - }} + //}} cgi.header("Accept: POST"); // FIXME list the real thing cgi.setResponseStatus("405 Method Not Allowed"); // again, not exactly, but sort of. no overload matched our args, almost certainly due to http verb filtering. return true; @@ -6960,11 +6986,25 @@ auto serveApi(T)(string urlPrefix) { } string urlNameForMethod(alias method)(string def) { + auto verb = Cgi.RequestMethod.GET; + bool foundVerb = false; + bool foundNoun = false; static foreach(attr; __traits(getAttributes, method)) { - static if(is(typeof(attr) == UrlName)) - return attr.name; + static if(is(typeof(attr) == Cgi.RequestMethod)) { + verb = attr; + if(foundVerb) + assert(0, "Multiple http verbs on one function is not currently supported"); + foundVerb = true; + } + static if(is(typeof(attr) == UrlName)) { + if(foundNoun) + assert(0, "Multiple url names on one function is not currently supported"); + foundNoun = true; + def = attr.name; + } } - return def; + + return to!string(verb) ~ " " ~ def; }