!7 // TODO: use concepts DB static S cookieName = "cookie"; static int cookieDays = 32, cookieLength = 20; static int cookieCounter = 1; static long countingForUnixDay; static new L ips; static new L cookies; static long cookieLess; static new L uaips; static new MultiSet referers; sbool saveReferers = false; static Lock lock = lock(); static new ThreadLocal cookieFromUser; static new ThreadLocal cookieSent; static class Uaip { S ua, ip; bool hasCookie; *() {} *(S *ua, S *ip, bool *hasCookie) {} } static class Data { long day, ips, cookies, cookieLess; new L uaips; *(long *day, long *ips, long *cookies, long *cookieLess) {} *() {} } //static PersistentLog stats; static ReliableSingleThread_Multi rstSaveVars = new(60000, lambda1 save); p { //stats = new PersistentLog("stats.log"); load("cookieCounter"); load("countingForUnixDay"); load("ips"); load("cookies"); load("cookieLess"); load("uaips"); if (saveReferers) load("referers"); } set flag NoNanoHTTPD. html { lock lock; if (eq(uri, "/referers")) ret hmobilefix() + h3("Referers!") + htable( renderMapForTable(orderMapByDescendingValue(referers.asMap()), "Referer", "Count", true)); if (eq(uri, "/requests")) ret str(getOpt(getOpt(mainBot(), 'serveHttp_server), 'requests)); if (eq(uri, "/requests-plus-serving")) { O server = getOpt(mainBot(), 'serveHttp_server); int serving = l(getOpt(server, 'currentlyServing)); ret getOpt(server, 'requests) + (serving != 0 ? " [" + serving + "]" : ""); } /*if (eq(uri, "/stats")) { ret htag("p", "IPs in the day: " + l(ips) + ", cookies in the day: " + l(cookies) + ", cookieless today: " + cookieLess + ". Total cookies given out since all time: " + cookieCounter) + htag("pre", fromLines(reversedList(toLines(stats.fileContents())))); }*/ if (eq(uri, "/uaips")) { int n = toInt(params.get("n")); L lines = map sfu(dropFirst(n, cloneList(uaips))); S after = params.get('after); if (nempty(after)) lines = subList(lines, indexOf(lines, after)+1); ret serveText(lines(lines)); } O session = call(getMainBot(), "getSession"); O cookieHandler = call(getMainBot(), "getCookies"); S cookie = cast call(cookieHandler, "read", cookieName); cookieFromUser.set(cookie); // rotate if day changed long day = unixDay(); if (day != countingForUnixDay) { if (countingForUnixDay != 0) { // archive print("Archiving stats for unix day " + countingForUnixDay + "!"); //stats.add(today()); appendToTextFile("stats.log", structure(today()); } // rotate countingForUnixDay = day; saveLater("countingForUnixDay"); ips.clear(); saveLater("ips"); cookies.clear(); saveLater("cookies"); cookieLess = 0; saveLater("cookieLess"); uaips = new L; saveLater("uaips"); } // save only cookies returned by user if (!cookies.contains(cookie)) { cookies.add(cookie); saveLater("cookies"); } else { ++cookieLess; saveLater("cookieLess"); } // record IP Map headers = cast call(session, "getHeaders"); S remoteAddr = cast headers.get("remote-addr"); S client = cast headers.get("x-forwarded-for"); if (nempty(client)) remoteAddr += "," + client; if (!empty(remoteAddr) && !ips.contains(remoteAddr)) { ips.add(remoteAddr); saveLater("ips"); } // add uaip S ua = cast headers.get("user-agent"); addUAIP(ua, remoteAddr, nempty(cookie)); // referer if (saveReferers) { S referer = cast headers.get("referer"); if (nempty(referer)) { referers.add(referer); saveLater("referers"); // TODO: rotate etc. } } boolean isNew = false; if (cookie == null) { isNew = true; //cookie = "Cookie " + (cookieCounter++); if (empty((S) headers.get("x-no-cookies"))) cookie = randomID(cookieLength); //saveLater("cookieCounter"); } if (cookie != null) { cookieSent.set(cookie); O cookieObject = call(cookieHandler, "set", cookieName, cookie, cookieDays); // hopefully this refreshes the expiration? S domain = domain(); if (isAGIBlueDomain(domain)) setOpt(cookieObject, domain := theAGIBlueDomain()); setOpt(cookieObject, path := "/"); print("Setting path for cookie object " + cookieObject + ": " + getOpt(cookieObject, 'path)); } S s = cookie == null ? "" : "Your " + (isNew ? "new " : "recurring ") + "cookie is: " + cookie; s += "
"; /*Data y = yesterday(); S yesterday = y == null ? "" : " (" + y.cookies + "/" + y.ips + " yesterday)"; s += l(cookies) + " cookies, " + l(ips) + " IPs" + yesterday + " seen today. " + cookieLess + " requests.";*/ ret s; } synchronized answer { if (subBot_master()) if "clear referers" { lock lock; referers.clear(); saveLater("referers"); ret "OK"; } if "visitors today" { ret structure(today()); } /*if "visitors yesterday" { Data data = yesterday(); if (data == null) ret "There was no yesterday."; ret structure(data); }*/ /*if "visitors last * days" { int i = max(0, l(stats)-parseInt(m.unq(0))+1); new L stats_; for (Map map : objectToMap(concatLists( subList(stats, i), litlist(today()) ))) stats_.add(mapWithoutKey(map, "uaips")); // drop the long stuff ret "```" + structureLines(stats_) + "```"; }*/ if "uaips today" ret sfu(cloneList(uaips)); } static Data today() { Data d = new Data(countingForUnixDay, l(ips), l(cookies), cookieLess); d.uaips = cloneList(uaips); ret d; } /*static synchronized Data yesterday() { ret last(stats); }*/ static void addUAIP(S ua, S ip, bool hasCookie) { for (Uaip x : uaips) if (eq(x.ua, ua) && eq(x.ip, ip) && hasCookie == x.hasCookie) ret; uaips.add(new Uaip(ua, ip, hasCookie)); saveLater("uaips"); } sS cookieFromUser() { ret cookieFromUser!; } sS cookieSent() { ret cookieSent!; } svoid saveLater(S var) { rstSaveVars.add(var); }