new stuff im working on

This commit is contained in:
Adam D. Ruppe 2019-06-15 18:50:32 -04:00
parent 3fa87f08c4
commit 57c995f4bf
1 changed files with 77 additions and 37 deletions

114
cgi.d
View File

@ -3770,11 +3770,15 @@ class ListeningConnectionManager {
} }
semaphore.notify(); semaphore.notify();
bool hasAnyRunning;
foreach(thread; threads) { foreach(thread; threads) {
if(!thread.isRunning) { if(!thread.isRunning) {
thread.join(); thread.join();
} else hasAnyRunning = true;
} }
}
if(!hasAnyRunning)
break;
} }
// FIXME: i typically stop this with ctrl+c which never // FIXME: i typically stop this with ctrl+c which never
@ -3876,7 +3880,7 @@ class ConnectionThread : Thread {
} }
try try
dg(socket); dg(socket);
catch(Exception e) catch(Throwable e)
socket.close(); socket.close();
} }
} }
@ -5950,6 +5954,8 @@ private string beautify(string name, char space = ' ', bool allLowerCase = false
} }
lastWasCap = true; lastWasCap = true;
} else {
lastWasCap = false;
} }
if(shouldSpace) { if(shouldSpace) {
@ -6260,9 +6266,11 @@ auto callFromCgi(alias method, T)(T dg, Cgi cgi) {
--- ---
class MyPresenter : WebPresenter!(MyPresenter) { class MyPresenter : WebPresenter!(MyPresenter) {
@Override
void presentSuccessfulReturnAsHtml(T : CustomType)(Cgi cgi, T ret) { void presentSuccessfulReturnAsHtml(T : CustomType)(Cgi cgi, T ret) {
// present the CustomType // present the CustomType
} }
@Override
void presentSuccessfulReturnAsHtml(T)(Cgi cgi, T ret) { void presentSuccessfulReturnAsHtml(T)(Cgi cgi, T ret) {
// handle everything else via the super class, which will call // handle everything else via the super class, which will call
// back to your class when appropriate // back to your class when appropriate
@ -6273,6 +6281,11 @@ auto callFromCgi(alias method, T)(T dg, Cgi cgi) {
+/ +/
class WebPresenter(CRTP) { 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() { string script() {
return ` return `
`; `;
@ -6290,7 +6303,8 @@ class WebPresenter(CRTP) {
} }
string genericFormStyling() { string genericFormStyling() {
return ` return
q"css
table.automatic-data-display { table.automatic-data-display {
border-collapse: collapse; border-collapse: collapse;
border: solid 1px var(--mild-border); border: solid 1px var(--mild-border);
@ -6332,28 +6346,29 @@ class WebPresenter(CRTP) {
.add-array-button { .add-array-button {
} }
`; css";
} }
string genericSiteStyling() { string genericSiteStyling() {
return ` return
q"css
* { box-sizing: border-box; } * { box-sizing: border-box; }
html, body { margin: 0px; } html, body { margin: 0px; }
body { body {
font-family: sans-serif; font-family: sans-serif;
} }
#header { header {
background: var(--accent-color); background: var(--accent-color);
height: 64px; height: 64px;
} }
#footer { footer {
background: var(--accent-color); background: var(--accent-color);
height: 64px; height: 64px;
} }
#main-site { #site-container {
display: flex; display: flex;
} }
#container { main {
flex: 1 1 auto; flex: 1 1 auto;
order: 2; order: 2;
min-height: calc(100vh - 64px - 64px); min-height: calc(100vh - 64px - 64px);
@ -6365,29 +6380,31 @@ class WebPresenter(CRTP) {
order: 1; order: 1;
background: var(--sidebar-color); background: var(--sidebar-color);
} }
`; css";
} }
import arsd.dom; import arsd.dom;
Element htmlContainer() { Element htmlContainer() {
auto document = new Document(`<!DOCTYPE html> auto document = new Document(q"html
<!DOCTYPE html>
<html> <html>
<head> <head>
<title>D Application</title> <title>D Application</title>
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css" />
</head> </head>
<body> <body>
<div id="header"></div> <header></header>
<div id="main-site"> <div id="site-container">
<div id="container"></div> <main></main>
<div id="sidebar"></div> <div id="sidebar"></div>
</div> </div>
<div id="footer"></div> <footer></footer>
<script src="script.js"></script> <script src="script.js"></script>
</body> </body>
</html>`, true, true); </html>
html", true, true);
return document.requireElementById("container"); return document.requireSelector("main");
} }
/// typeof(null) (which is also used to represent functions returning `void`) do nothing /// 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) { Element elementFor(T)(string displayName, string name) {
import arsd.dom;
import std.traits; import std.traits;
auto div = Element.make("div"); auto div = Element.make("div");
@ -6498,6 +6514,7 @@ class WebPresenter(CRTP) {
} }
auto i = lbl.addChild("input", name); auto i = lbl.addChild("input", name);
i.attrs.type = "checkbox"; i.attrs.type = "checkbox";
i.attrs.value = "true";
i.attrs.name = name; i.attrs.name = name;
} else static if(is(T == K[], K)) { } else static if(is(T == K[], K)) {
auto templ = div.addChild("template"); auto templ = div.addChild("template");
@ -6522,9 +6539,8 @@ class WebPresenter(CRTP) {
return div; return div;
} }
/// actually returns an arsd.dom.Form /// creates a form for gathering the function's arguments
auto createAutomaticFormForFunction(alias method, T)(T dg) { Form createAutomaticFormForFunction(alias method, T)(T dg) {
import arsd.dom;
auto form = cast(Form) Element.make("form"); auto form = cast(Form) Element.make("form");
@ -6555,10 +6571,8 @@ class WebPresenter(CRTP) {
return form; return form;
} }
/// actually returns an arsd.dom.Form /// creates a form for gathering object members (for the REST object thing right now)
auto createAutomaticFormForObject(T)(T obj) { Form createAutomaticFormForObject(T)(T obj) {
import arsd.dom;
auto form = cast(Form) Element.make("form"); auto form = cast(Form) Element.make("form");
form.addClass("automatic-form"); form.addClass("automatic-form");
@ -6588,8 +6602,7 @@ class WebPresenter(CRTP) {
} }
/// ///
auto formatReturnValueAsHtml(T)(T t) { Element formatReturnValueAsHtml(T)(T t) {
import arsd.dom;
import std.traits; import std.traits;
static if(is(T == typeof(null))) { static if(is(T == typeof(null))) {
@ -6826,11 +6839,23 @@ auto serveApi(T)(string urlPrefix) {
auto obj = new T(); auto obj = new T();
obj.initialize(cgi); obj.initialize(cgi);
switch(cgi.pathInfo[urlPrefix.length .. $]) { /+
static foreach(methodName; __traits(derivedMembers, T)){{ Overload rules:
static if(is(typeof(__traits(getMember, T, methodName)) P == __parameters)) 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 zeroArgOverload = -1;
int overloadCount = cast(int) __traits(getOverloads, T, methodName).length; int overloadCount = cast(int) __traits(getOverloads, T, methodName).length;
bool calledWithZeroArgs = true; bool calledWithZeroArgs = true;
@ -6902,6 +6927,7 @@ auto serveApi(T)(string urlPrefix) {
so the method UDAs are irrelevant. so the method UDAs are irrelevant.
+/ +/
if(callFunction) if(callFunction)
+/
switch(cgi.request("format", "html")) { switch(cgi.request("format", "html")) {
case "html": case "html":
try { try {
@ -6934,7 +6960,7 @@ auto serveApi(T)(string urlPrefix) {
cgi.setResponseStatus("406 Not Acceptable"); // not exactly but sort of. cgi.setResponseStatus("406 Not Acceptable"); // not exactly but sort of.
return true; return true;
} }
}} //}}
cgi.header("Accept: POST"); // FIXME list the real thing 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. 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; return true;
@ -6960,11 +6986,25 @@ auto serveApi(T)(string urlPrefix) {
} }
string urlNameForMethod(alias method)(string def) { string urlNameForMethod(alias method)(string def) {
auto verb = Cgi.RequestMethod.GET;
bool foundVerb = false;
bool foundNoun = false;
static foreach(attr; __traits(getAttributes, method)) { static foreach(attr; __traits(getAttributes, method)) {
static if(is(typeof(attr) == UrlName)) static if(is(typeof(attr) == Cgi.RequestMethod)) {
return attr.name; verb = attr;
if(foundVerb)
assert(0, "Multiple http verbs on one function is not currently supported");
foundVerb = true;
} }
return def; 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 to!string(verb) ~ " " ~ def;
} }