mirror of https://github.com/adamdruppe/arsd.git
lots of compatibility
This commit is contained in:
parent
03315adfa6
commit
acb833d724
211
cgi.d
211
cgi.d
|
@ -6076,21 +6076,24 @@ void runAddonServer(EIS)(string localListenerName, EIS eis) if(is(EIS : EventIoS
|
|||
if(listen(sock, 128) == -1)
|
||||
throw new Exception("listen " ~ to!string(errno));
|
||||
|
||||
makeNonBlocking(sock);
|
||||
|
||||
version(linux) {
|
||||
|
||||
makeNonBlocking(sock);
|
||||
|
||||
import core.sys.linux.epoll;
|
||||
auto epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if(epoll_fd == -1)
|
||||
throw new Exception("epoll_create1 " ~ to!string(errno));
|
||||
scope(failure)
|
||||
close(epoll_fd);
|
||||
} else {
|
||||
import core.sys.posix.poll;
|
||||
}
|
||||
|
||||
auto acceptOp = allocateIoOp(sock, IoOp.Read, 0, null);
|
||||
scope(exit)
|
||||
freeIoOp(acceptOp);
|
||||
auto acceptOp = allocateIoOp(sock, IoOp.Read, 0, null);
|
||||
scope(exit)
|
||||
freeIoOp(acceptOp);
|
||||
|
||||
version(linux) {
|
||||
epoll_event ev;
|
||||
ev.events = EPOLLIN | EPOLLET;
|
||||
ev.data.ptr = acceptOp;
|
||||
|
@ -6098,111 +6101,153 @@ void runAddonServer(EIS)(string localListenerName, EIS eis) if(is(EIS : EventIoS
|
|||
throw new Exception("epoll_ctl " ~ to!string(errno));
|
||||
|
||||
epoll_event[64] events;
|
||||
} else {
|
||||
pollfd[] pollfds;
|
||||
pollfds ~= pollfd(sock, POLLIN);
|
||||
IoOp*[int] ioops;
|
||||
}
|
||||
|
||||
while(true) {
|
||||
while(true) {
|
||||
|
||||
// FIXME: it should actually do a timerfd that runs on any thing that hasn't been run recently
|
||||
// FIXME: it should actually do a timerfd that runs on any thing that hasn't been run recently
|
||||
|
||||
int timeout_milliseconds = 15000; // -1; // infinite
|
||||
//writeln("waiting for ", name);
|
||||
int timeout_milliseconds = 15000; // -1; // infinite
|
||||
//writeln("waiting for ", name);
|
||||
|
||||
version(linux) {
|
||||
auto nfds = epoll_wait(epoll_fd, events.ptr, events.length, timeout_milliseconds);
|
||||
if(nfds == -1) {
|
||||
if(errno == EINTR)
|
||||
continue;
|
||||
throw new Exception("epoll_wait " ~ to!string(errno));
|
||||
}
|
||||
} else {
|
||||
int nfds = poll(pollfds.ptr, pollfds.length, timeout_milliseconds);
|
||||
}
|
||||
|
||||
if(nfds == 0) {
|
||||
eis.wait_timeout();
|
||||
}
|
||||
if(nfds == 0) {
|
||||
eis.wait_timeout();
|
||||
}
|
||||
|
||||
foreach(idx; 0 .. nfds) {
|
||||
foreach(idx; 0 .. nfds) {
|
||||
version(linux) {
|
||||
auto flags = events[idx].events;
|
||||
auto ioop = cast(IoOp*) events[idx].data.ptr;
|
||||
} else {
|
||||
auto ioop = ioops[pollfds[idx].fd];
|
||||
}
|
||||
|
||||
//writeln(flags, " ", ioop.fd);
|
||||
//writeln(flags, " ", ioop.fd);
|
||||
|
||||
if(ioop.fd == sock && (flags & EPOLLIN)) {
|
||||
// on edge triggering, it is important that we get it all
|
||||
while(true) {
|
||||
auto size = cast(uint) addr.sizeof;
|
||||
auto ns = accept(sock, cast(sockaddr*) &addr, &size);
|
||||
if(ns == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
// all done, got it all
|
||||
break;
|
||||
}
|
||||
throw new Exception("accept " ~ to!string(errno));
|
||||
void newConnection() {
|
||||
// on edge triggering, it is important that we get it all
|
||||
while(true) {
|
||||
auto size = cast(uint) addr.sizeof;
|
||||
auto ns = accept(sock, cast(sockaddr*) &addr, &size);
|
||||
if(ns == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
// all done, got it all
|
||||
break;
|
||||
}
|
||||
throw new Exception("accept " ~ to!string(errno));
|
||||
}
|
||||
|
||||
makeNonBlocking(ns);
|
||||
makeNonBlocking(ns);
|
||||
auto niop = allocateIoOp(ns, IoOp.ReadSocketHandle, 4096, &eis.handleLocalConnectionData);
|
||||
niop.closeHandler = &eis.handleLocalConnectionClose;
|
||||
niop.completeHandler = &eis.handleLocalConnectionComplete;
|
||||
scope(failure) freeIoOp(niop);
|
||||
|
||||
version(linux) {
|
||||
epoll_event nev;
|
||||
nev.events = EPOLLIN | EPOLLET;
|
||||
auto niop = allocateIoOp(ns, IoOp.ReadSocketHandle, 4096, &eis.handleLocalConnectionData);
|
||||
niop.closeHandler = &eis.handleLocalConnectionClose;
|
||||
niop.completeHandler = &eis.handleLocalConnectionComplete;
|
||||
scope(failure) freeIoOp(niop);
|
||||
nev.data.ptr = niop;
|
||||
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ns, &nev) == -1)
|
||||
throw new Exception("epoll_ctl " ~ to!string(errno));
|
||||
}
|
||||
} else if(ioop.operation == IoOp.ReadSocketHandle) {
|
||||
while(true) {
|
||||
int in_fd;
|
||||
auto got = read_fd(ioop.fd, ioop.allocatedBuffer.ptr, ioop.allocatedBuffer.length, &in_fd);
|
||||
if(got == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
// all done, got it all
|
||||
if(ioop.completeHandler)
|
||||
ioop.completeHandler(ioop);
|
||||
break;
|
||||
} else {
|
||||
bool found = false;
|
||||
foreach(ref pfd; pollfds) {
|
||||
if(pfd.fd < 0) {
|
||||
pfd.fd = ns;
|
||||
found = true;
|
||||
}
|
||||
throw new Exception("recv " ~ to!string(errno));
|
||||
}
|
||||
|
||||
if(got == 0) {
|
||||
if(ioop.closeHandler)
|
||||
ioop.closeHandler(ioop);
|
||||
close(ioop.fd);
|
||||
freeIoOp(ioop);
|
||||
break;
|
||||
}
|
||||
|
||||
ioop.bufferLengthUsed = cast(int) got;
|
||||
ioop.handler(ioop, in_fd);
|
||||
}
|
||||
} else if(ioop.operation == IoOp.Read) {
|
||||
while(true) {
|
||||
auto got = recv(ioop.fd, ioop.allocatedBuffer.ptr, ioop.allocatedBuffer.length, 0);
|
||||
if(got == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
// all done, got it all
|
||||
if(ioop.completeHandler)
|
||||
ioop.completeHandler(ioop);
|
||||
break;
|
||||
}
|
||||
throw new Exception("recv " ~ to!string(errno));
|
||||
}
|
||||
|
||||
if(got == 0) {
|
||||
if(ioop.closeHandler)
|
||||
ioop.closeHandler(ioop);
|
||||
close(ioop.fd);
|
||||
freeIoOp(ioop);
|
||||
break;
|
||||
}
|
||||
|
||||
ioop.bufferLengthUsed = cast(int) got;
|
||||
ioop.handler(ioop, -1);
|
||||
if(!found)
|
||||
pollfds ~= pollfd(ns, POLLIN);
|
||||
}
|
||||
}
|
||||
|
||||
// EPOLLHUP?
|
||||
}
|
||||
|
||||
bool newConnectionCondition() {
|
||||
version(linux)
|
||||
return ioop.fd == sock && (flags & EPOLLIN);
|
||||
else
|
||||
return pollfds[idx].fd == sock && (pollfds[idx].revents & POLLIN);
|
||||
}
|
||||
|
||||
if(newConnectionCondition()) {
|
||||
newConnection();
|
||||
} else if(ioop.operation == IoOp.ReadSocketHandle) {
|
||||
while(true) {
|
||||
int in_fd;
|
||||
auto got = read_fd(ioop.fd, ioop.allocatedBuffer.ptr, ioop.allocatedBuffer.length, &in_fd);
|
||||
if(got == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
// all done, got it all
|
||||
if(ioop.completeHandler)
|
||||
ioop.completeHandler(ioop);
|
||||
break;
|
||||
}
|
||||
throw new Exception("recv " ~ to!string(errno));
|
||||
}
|
||||
|
||||
if(got == 0) {
|
||||
if(ioop.closeHandler) {
|
||||
ioop.closeHandler(ioop);
|
||||
version(linux) {} // nothing needed
|
||||
else {
|
||||
foreach(ref pfd; pollfds) {
|
||||
if(pfd.fd == ioop.fd)
|
||||
pfd.fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(ioop.fd);
|
||||
freeIoOp(ioop);
|
||||
break;
|
||||
}
|
||||
|
||||
ioop.bufferLengthUsed = cast(int) got;
|
||||
ioop.handler(ioop, in_fd);
|
||||
}
|
||||
} else if(ioop.operation == IoOp.Read) {
|
||||
while(true) {
|
||||
auto got = recv(ioop.fd, ioop.allocatedBuffer.ptr, ioop.allocatedBuffer.length, 0);
|
||||
if(got == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
// all done, got it all
|
||||
if(ioop.completeHandler)
|
||||
ioop.completeHandler(ioop);
|
||||
break;
|
||||
}
|
||||
throw new Exception("recv " ~ to!string(errno));
|
||||
}
|
||||
|
||||
if(got == 0) {
|
||||
if(ioop.closeHandler)
|
||||
ioop.closeHandler(ioop);
|
||||
close(ioop.fd);
|
||||
freeIoOp(ioop);
|
||||
break;
|
||||
}
|
||||
|
||||
ioop.bufferLengthUsed = cast(int) got;
|
||||
ioop.handler(ioop, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// EPOLLHUP?
|
||||
}
|
||||
} else {
|
||||
// this isn't seriously implemented.
|
||||
static assert(0);
|
||||
}
|
||||
} else version(Windows) {
|
||||
|
||||
|
|
|
@ -376,8 +376,8 @@ string toSql(Database db, Variant a) {
|
|||
|
||||
// just for convenience; "str".toSql(db);
|
||||
string toSql(string s, Database db) {
|
||||
if(s is null)
|
||||
return "NULL";
|
||||
//if(s is null)
|
||||
//return "NULL";
|
||||
return '\'' ~ db.escape(s) ~ '\'';
|
||||
}
|
||||
|
||||
|
|
|
@ -112,6 +112,7 @@ string generateCreateTableFor(alias O)() {
|
|||
static foreach(memberName; __traits(allMembers, O)) {{
|
||||
alias member = __traits(getMember, O, memberName);
|
||||
static if(is(typeof(member) == Constraint!constraintSql, string constraintSql)) {
|
||||
version(dbgenerate_sqlite) {} else { // FIXME: make it work here too, it is the specifics of the constraint strings
|
||||
if(outputted) {
|
||||
sql ~= ",";
|
||||
}
|
||||
|
@ -120,6 +121,7 @@ string generateCreateTableFor(alias O)() {
|
|||
sql ~= " ";
|
||||
sql ~= constraintSql;
|
||||
outputted = true;
|
||||
}
|
||||
} else static if(is(typeof(member) == Index!Fields, Fields...)) {
|
||||
string fields = "";
|
||||
static foreach(field; Fields) {
|
||||
|
@ -155,27 +157,42 @@ string generateCreateTableFor(alias O)() {
|
|||
else static assert(0, P.stringof);
|
||||
} else static if(is(T == int))
|
||||
sql ~= " INTEGER NOT NULL";
|
||||
else static if(is(T == Serial))
|
||||
sql ~= " SERIAL"; // FIXME postgresism
|
||||
else static if(is(T == string))
|
||||
else static if(is(T == Serial)) {
|
||||
version(dbgenerate_sqlite)
|
||||
sql ~= " INTEGER PRIMARY KEY AUTOINCREMENT";
|
||||
else
|
||||
sql ~= " SERIAL"; // FIXME postgresism
|
||||
} else static if(is(T == string))
|
||||
sql ~= " TEXT NOT NULL";
|
||||
else static if(is(T == double))
|
||||
sql ~= " FLOAT NOT NULL";
|
||||
else static if(is(T == bool))
|
||||
sql ~= " BOOLEAN NOT NULL";
|
||||
else static if(is(T == Timestamp))
|
||||
sql ~= " TIMESTAMPTZ NOT NULL"; // FIXME: postgresism
|
||||
else static if(is(T == enum))
|
||||
else static if(is(T == Timestamp)) {
|
||||
version(dbgenerate_sqlite)
|
||||
sql ~= " TEXT NOT NULL";
|
||||
else
|
||||
sql ~= " TIMESTAMPTZ NOT NULL"; // FIXME: postgresism
|
||||
} else static if(is(T == enum))
|
||||
sql ~= " INTEGER NOT NULL"; // potentially crap but meh
|
||||
|
||||
static foreach(attr; __traits(getAttributes, member)) {
|
||||
static if(is(typeof(attr) == Default)) {
|
||||
// FIXME: postgresism there, try current_timestamp in sqlite
|
||||
sql ~= " DEFAULT " ~ attr.sql;
|
||||
version(dbgenerate_sqlite) {
|
||||
import std.string;
|
||||
sql ~= " DEFAULT " ~ std.string.replace(attr.sql, "now()", "current_timestamp");
|
||||
} else
|
||||
sql ~= " DEFAULT " ~ attr.sql;
|
||||
} else static if(is(attr == Unique)) {
|
||||
sql ~= " UNIQUE";
|
||||
} else static if(is(attr == PrimaryKey)) {
|
||||
addPostSql("PRIMARY KEY(" ~ memberName ~ ")");
|
||||
version(dbgenerate_sqlite) {
|
||||
static if(is(T == Serial)) {} // skip, it is done above
|
||||
else
|
||||
addPostSql("PRIMARY KEY(" ~ memberName ~ ")");
|
||||
} else
|
||||
addPostSql("PRIMARY KEY(" ~ memberName ~ ")");
|
||||
} else static if(is(attr == ForeignKey!(to, sqlPolicy), alias to, string sqlPolicy)) {
|
||||
string refTable = toTableName(__traits(parent, to).stringof);
|
||||
string refField = to.stringof;
|
||||
|
@ -299,9 +316,9 @@ void insert(O)(ref O t, Database db) {
|
|||
} else {
|
||||
// skip and let it auto-fill
|
||||
}
|
||||
} else static if(is(T == string))
|
||||
} else static if(is(T == string)) {
|
||||
builder.addVariable(memberName, __traits(getMember, t, memberName));
|
||||
else static if(is(T == double))
|
||||
} else static if(is(T == double))
|
||||
builder.addVariable(memberName, __traits(getMember, t, memberName));
|
||||
else static if(is(T == bool))
|
||||
builder.addVariable(memberName, __traits(getMember, t, memberName));
|
||||
|
@ -315,8 +332,14 @@ void insert(O)(ref O t, Database db) {
|
|||
}}
|
||||
|
||||
import std.conv;
|
||||
foreach(row; builder.execute(db, "RETURNING id")) // FIXME: postgres-ism
|
||||
t.id.value = to!int(row[0]);
|
||||
version(dbgenerate_sqlite) {
|
||||
builder.execute(db);
|
||||
foreach(row; db.query("SELECT max(id) FROM " ~ toTableName(O.stringof)))
|
||||
t.id.value = to!int(row[0]);
|
||||
} else {
|
||||
foreach(row; builder.execute(db, "RETURNING id")) // FIXME: postgres-ism
|
||||
t.id.value = to!int(row[0]);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -370,7 +393,7 @@ private void populateFromDbVal(V)(ref V val, string value) {
|
|||
|
||||
} else static if(is(V == Nullable!P, P)) {
|
||||
// FIXME
|
||||
if(value.length) {
|
||||
if(value.length && value != "null") {
|
||||
val.isNull = false;
|
||||
val.value = to!P(value);
|
||||
}
|
||||
|
|
43
sqlite.d
43
sqlite.d
|
@ -121,7 +121,6 @@ class Sqlite : Database {
|
|||
foreach(i, arg; args) {
|
||||
s.bind(cast(int) i + 1, arg);
|
||||
}
|
||||
|
||||
return s.execute();
|
||||
}
|
||||
|
||||
|
@ -263,6 +262,12 @@ struct Statement {
|
|||
Sqlite db;
|
||||
|
||||
this(Sqlite db, string sql) {
|
||||
// the arsd convention is zero based ?, but sqlite insists on one based. so this is stupid but still
|
||||
if(sql.indexOf("?0") != -1) {
|
||||
foreach_reverse(i; 0 .. 10)
|
||||
sql = sql.replace("?" ~ to!string(i), "?" ~ to!string(i + 1));
|
||||
}
|
||||
|
||||
this.db = db;
|
||||
if(sqlite3_prepare_v2(db.db, toStringz(sql), cast(int) sql.length, &s, null) != SQLITE_OK)
|
||||
throw new DatabaseException(db.error());
|
||||
|
@ -487,14 +492,13 @@ template extract(A, T, R...){
|
|||
void bind (const char[] name, float value){ bind(bindNameLookUp(name), value); }
|
||||
void bind (const char[] name, const byte[] value){ bind(bindNameLookUp(name), value); }
|
||||
|
||||
void bind(int col, typeof(null) value){
|
||||
if(sqlite3_bind_null(s, col) != SQLITE_OK)
|
||||
throw new DatabaseException("bind " ~ db.error());
|
||||
}
|
||||
void bind(int col, const char[] value){
|
||||
if(value is null) {
|
||||
if(sqlite3_bind_null(s, col) != SQLITE_OK)
|
||||
throw new DatabaseException("bind " ~ db.error());
|
||||
} else {
|
||||
if(sqlite3_bind_text(s, col, value.ptr, cast(int) value.length, cast(void*)-1) != SQLITE_OK)
|
||||
throw new DatabaseException("bind " ~ db.error());
|
||||
}
|
||||
if(sqlite3_bind_text(s, col, value.ptr is null ? "" : value.ptr, cast(int) value.length, cast(void*)-1) != SQLITE_OK)
|
||||
throw new DatabaseException("bind " ~ db.error());
|
||||
}
|
||||
|
||||
void bind(int col, float value){
|
||||
|
@ -525,18 +529,27 @@ template extract(A, T, R...){
|
|||
void bind(int col, Variant v) {
|
||||
if(v.peek!long)
|
||||
bind(col, v.get!long);
|
||||
if(v.peek!ulong)
|
||||
else if(v.peek!ulong)
|
||||
bind(col, v.get!ulong);
|
||||
if(v.peek!int)
|
||||
else if(v.peek!int)
|
||||
bind(col, v.get!int);
|
||||
if(v.peek!string)
|
||||
else if(v.peek!(const(int)))
|
||||
bind(col, v.get!(const(int)));
|
||||
else if(v.peek!bool)
|
||||
bind(col, v.get!bool ? 1 : 0);
|
||||
else if(v.peek!DateTime)
|
||||
bind(col, v.get!DateTime.toISOExtString());
|
||||
else if(v.peek!string)
|
||||
bind(col, v.get!string);
|
||||
if(v.peek!float)
|
||||
else if(v.peek!float)
|
||||
bind(col, v.get!float);
|
||||
if(v.peek!(byte[]))
|
||||
else if(v.peek!(byte[]))
|
||||
bind(col, v.get!(byte[]));
|
||||
if(v.peek!(void*) && v.get!(void*) is null)
|
||||
bind(col, cast(string) null);
|
||||
else if(v.peek!(void*) && v.get!(void*) is null)
|
||||
bind(col, null);
|
||||
else
|
||||
bind(col, v.coerce!string);
|
||||
//assert(0, v.type.toString ~ " " ~ v.coerce!string);
|
||||
}
|
||||
|
||||
~this(){
|
||||
|
|
Loading…
Reference in New Issue