Warning: session_start(): open(/var/lib/php/sessions/sess_6eafvm83hgd8ekfqm383k22e5l, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
sO thoughtBot;
static int longPollTick = 100;
static int longPollMaxWait = 1000*60;
sS defaultUserName = "You";
sS botImageID = #1102802;
sS userImageID = #1102803;
sS baseLink;
sclass Msg {
long time;
bool fromUser;
S text;
L buttons;
*() {}
*(bool *fromUser, S *text) { time = now(); }
}
concept Conversation {
bool authed;
S cookie;
new LL oldDialogs;
new L msgs;
void add(Msg m) {
msgs.add(m);
change();
}
int allCount() { ret lengthLevel2(oldDialogs) + l(msgs); }
int archiveSize() { ret lengthLevel2(oldDialogs); }
}
svoid pWebChatBot {
db();
thoughtBot = runDependent(thoughtBotID);
Class envType = fieldType(thoughtBot, "env");
if (envType != null)
setOpt(thoughtBot, "env", proxy(envType, (O) mc()));
}
static void sayAsync(S session, S text) {
lock dbLock();
Conversation conv = getConv(session);
conv.add(new Msg(false, text));
print("sayAsync " + session + ", new size=" + conv.allCount());
}
html {
temp tempRegisterThread();
S cookie = params.get('cookie);
if (empty(cookie)) {
registerVisitor();
cookie = cookieSent();
}
Conversation conv = nempty(cookie) ? getConv(cookie) : null;
print("Cookie: " + cookie + ", msgs: " + l(conv.msgs));
S pw = trim(params.get('pw));
if (nempty(pw)) {
S realPW = trim(loadSecretTextFile("password.txt"));
if (empty(realPW)) ret errorMsg("Administrator has not set a password");
if (neq(pw, realPW))
ret errorMsg("Bad password, please try again");
cset(conv, authed := true);
if (nempty(params.get('redirect)))
ret hrefresh(params.get('redirect));
}
if (eq(uri, "/stats")) {
if (!conv.authed) ret serveAuthForm(rawLink(uri));
ret "Threads: " + ul_htmlEncode(getThreadNames(registeredThreads()));
}
if (eq(uri, "/logs")) {
if (!conv.authed) ret serveAuthForm(rawLink(uri));
ret webChatBotLogsHTML2(rawLink(uri), params);
}
if (eq(uri, "/auth-only")) {
if (!conv.authed) ret serveAuthForm(params.get('uri));
ret "";
}
{
lock dbLock();
S message = trim(params.get("btn"));
if (empty(message)) message = trim(params.get("message"));
if (match("new dialog", message)) {
conv.oldDialogs.add(conv.msgs);
cset(conv, msgs := new L);
conv.change();
callOpt(thoughtBot, "clearSession", conv.cookie);
message = null;
}
call(thoughtBot, "setSession", cookieSent());
if (empty(conv.msgs))
conv.add(new Msg(false, initialMessage()));
if (nempty(message) && !lastUserMessageWas(conv, message)) {
print("Adding message: " + message);
conv.add(new Msg(true, message));
}
if (nempty(conv.msgs) && last(conv.msgs).fromUser) {
S reply = "I'm sorry, I don't understand";
L buttons = null;
pcall {
reply = or2(makeReply(last(conv.msgs).text), reply);
buttons = (L) getThreadLocal(thoughtBot, "buttons");
}
Msg msg = new Msg(false, reply);
msg.buttons = buttons;
conv.add(msg);
}
} // locked
if (eq(uri, "/msg")) ret withHeader("OK");
if (eq(uri, "/incremental")) {
int a = parseInt(params.get("a")), origA = a;
//int b = parseInt(params.get("b"));
int as = conv.archiveSize();
a -= as;
//b -= as;
long start = sysNow();
L msgs;
bool first = true;
while (licensed() && sysNow() < start+longPollMaxWait) {
msgs = subList(conv.msgs, a);
if (empty(msgs)) {
if (first) {
print("Long poll starting on " + cookie + ", " + origA + "/" + a);
first = false;
}
sleep(longPollTick);
} else {
if (first) print("Long poll ended.");
new StringBuilder buf;
renderMessages(buf, msgs);
ret withHeader("\n" + buf);
}
}
ret withHeader("");
}
{
lock dbLock();
processParams(params);
S html = loadSnippet(templateID); // TODO: cache
new StringBuilder buf;
// incremental only
//renderMessages(buf, conv.msgs);
S langlinks = "";
if (html.contains(langlinks))
html = html.replace(langlinks,
ahref(rawLink("eng"), "English") + " | " + ahref(rawLink("deu"), "German"));
html = html.replace("#BOTIMG#", imageSnippetURL(#1102802));
html = html.replace("#N#", "0" /*str(conv.allCount())*/);
html = html.replace("#INCREMENTALURL#", baseLink + "/incremental?a=");
html = html.replace("#MSGURL#", baseLink + "/msg?message=");
if (nempty(params.get("debug")))
html = html.replace("var showActions = false;", "var showActions = true;");
html = html.replace("$HEADING", heading);
html = html.replace("", str(buf));
html = hreplaceTitle(html, heading);
ret withHeader(html);
}
}
sO withHeader(S html) {
O response = subBot_serveHTML(html);
call(response, 'addHeader, "Access-Control-Allow-Origin", "*");
ret response;
}
svoid renderMessages(StringBuilder buf, L msgs) {
for (Msg m : msgs)
if (m.fromUser || neq(m.text, "-"))
appendMsg(buf, m.fromUser ? defaultUserName : botName, formatTime(m.time), htmlEncode2_nlToBr(trim(m.text)), !m.fromUser);
L buttons = last(msgs).buttons;
if (nempty(buttons))
appendButtons(buf, buttons);
}
svoid appendMsg(StringBuilder buf, S name, S time, S text, bool bot) {
S imgLink = snippetImgLink(bot ? botImageID : userImageID);
buf.append([[
$NAME
$TEXT
$TIME
]].replace("$LR", bot ? "left" : "right")
.replace("$IMG", imgLink)
.replace("$NAME", name)
.replace("$TIME", time)
.replace("$TEXT", text));
}
svoid appendButtons(StringBuilder buf, L buttons) {
// TODO: don't refresh page on button press
S buttonsHtml = lines(map(buttons, func(S text) {
hsubmit(text, name := "btn")
}));
buf.append([[
]].replace("$BUTTONS", buttonsHtml);
}
svoid appendDate(StringBuilder buf, S date) {
buf.append([[
]].replace("DATE", date));
}
sS initialMessage() {
ret (S) call(thoughtBot, "initialMessage");
}
static bool lastUserMessageWas(Conversation conv, S message) {
Msg m = last(conv.msgs);
ret m != null && m.fromUser && eq(m.text, message);
}
sS makeReply(S message) {
ret callStaticAnswerMethod(thoughtBot, message);
}
sS formatTime(long time) {
ret formatGMT_24(time);
}
sS formatDialog(S id, L msgs) {
new L lc;
for (Msg m : msgs)
lc.add(htmlencode((m.fromUser ? "> " : "< ") + m.text));
ret id + ul(lc);
}
static Conversation getConv(fS cookie) {
ret withDBLock(func -> Conversation {
uniq(Conversation, +cookie)
});
}
sS serveAuthForm(S redirect) {
ret hhtml(hhead(htitle("Authorization required")) + hbody(hfullcenter(
h3_htmlEncode(heading)
+ hpostform(
hhidden(+redirect)
+ "Password: " + hpassword('pw) + "
" + hsubmit()))));
}
sS errorMsg(S msg) {
ret hhtml(hhead_title("Error") + hbody(hfullcenter(msg + "
" + ahref(jsBackLink(), "Back"))));
}