Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

400
LINES

< > BotCompany Repo | #1029953 // Eleu Web Serving (transpilation test)

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (5060L/35K).

1  
static Set<S> blockedIPs = synchroHashSet(); // important: cleaned regularly in #1009210
2  
static Set<S> whiteListedIPs = synchroHashSet();
3  
4  
//static int blockedIPDelay = -1; // forever
5  
static int blockedIPDelay = 60; // seconds
6  
7  
//static int spamInterval = 60000;
8  
//static double spamPerSecondThreshold = 2.0; // per IP + URI
9  
10  
// for sub-bots to call through reflection
11  
please include function serveRedirect.
12  
please include function serve403.
13  
meta-comment {
14  
please include function serve404.
15  
please include function serve500.
16  
please include function serveFile.
17  
18  
please include function serveFileWithName.
19  
please include function serveFile_maxCache.
20  
please include function serveByteArray.
21  
please include function serveByteArray_maxCache.
22  
23  
static volatile int hitCount;
24  
25  
// These are speaking URLs like "/images/"
26  
static new SS botNames; // see e.g. #1013896
27  
28  
static S anonymousDialogID = "web-anon";
29  
30  
static S webLogProgramID = "#1002576";
31  
static S webLog = "webLog";
32  
33  
static int recentWebLogMax = 1000;
34  
static new LinkedList<Map> recentWebLog;
35  
36  
static S homePageBotID = "#1002771";
37  
38  
static void webInit() {
39  
  readLocally("hitCount");
40  
  readLocally("homePageBotID");
41  
  //readLocally("blockedIPs");
42  
  //set NanoHTTPD_debug;
43  
}
44  
45  
static new Object webLock;
46  
47  
static NanoHTTPD.Response serve(S uri, NanoHTTPD.Method method,
48  
  Map<S,S> header, Map<S,S> params, Map<S,S> files) {
49  
  
50  
  final long startTime = sysNow();
51  
  temp tempAfterwards(r { print(formatDateAndTime() + " | " + (sysNow()-startTime) + " ms") });
52  
  
53  
  SS headers = getSession().getHeaders();
54  
  S clientIP = headers.get("remote-addr");
55  
  
56  
  Pair<Int, Bool> pair = simpleSpamClientDetect2(clientIP, uri);
57  
  //Pair<S> pair = pair(clientIP, uri);
58  
  //int ipCount = toInt(ipsAndUris.get(pair));
59  
  //ipsAndUris.put(pair, ipCount+1);
60  
61  
  bool whiteListed = whiteListedIPs.contains(clientIP);
62  
  if (whiteListed) pair.b = false;
63  
  
64  
  bool bad = eq(uri, "/simulate-bad-client");
65  
  //int spamMax = iround(spamPerSecondThreshold*spamInterval/1000);
66  
  int ipCount = pair.a;
67  
  
68  
  if (!bad && pair.b) {
69  
    print("Blocking IP " + clientIP + ", count reached: " + ipCount);
70  
    addBlockedIP(clientIP);
71  
    bad = true;
72  
  }
73  
  
74  
  if (blockedIPs.contains(clientIP)) {
75  
    bad = true;
76  
    if (blockedIPDelay < 0)
77  
      print(formatDateAndTime() + " | Blocked IP!! " + clientIP + " " + l(nanoHttpd_badClients()));
78  
    else {
79  
      print(formatDateAndTime() + " | Blocked IP!! " + clientIP + (blockedIPDelay != 0 ? " Delaying " + blockedIPDelay + "s" : ""));
80  
      //sleepSeconds(blockedIPDelay);
81  
    }
82  
    //ret serveHTML("No");
83  
  }
84  
  
85  
  if (bad) {
86  
    NanoHTTPD.IHTTPSession httpSession = NanoHTTPD.currentSession!;
87  
    if (httpSession == null || blockedIPDelay >= 0) {
88  
      if (httpSession == null) print("No HTML session?");
89  
      sleepSeconds(blockedIPDelay);
90  
      ret serve500("go away");
91  
    }
92  
    httpSession.badClient(true);
93  
    null;
94  
  }
95  
  
96  
  S host = dropFrom(header.get("host"), ":");
97  
  
98  
  print(gmtWithSeconds() + ": Serving HTTP " + quote(headers.get("host") + /*colonPortUnless80(subBot_currentPort())*/ + uri) + " to " + clientIP + " (anti-spam count: " + ipCount + "/" + simpleSpamClientDetect2_spamMax + (whiteListed ? ", white-listed" : "") + ")");
99  
  
100  
  int hitID;
101  
  
102  
  synchronized(webLock) {
103  
    ++hitCount;
104  
    hitID = hitCount;
105  
    if ((hitCount % 1000) == 1) {
106  
      hitCount = (hitCount+999)/1000*1000;
107  
      saveLocally("hitCount");
108  
      hitCount = hitID;
109  
    }
110  
  }
111  
  
112  
  pcall { webLog(litmap("time", now(), "request", hitID, "uri", uri, "method", str(method), "header", header, "params", params, "files", files)); }
113  
  
114  
  try {
115  
    NanoHTTPD.Response response = serveNoLog(uri, method, header, params, files);
116  
    
117  
    // log that we responded
118  
    pcall { webLog(litmap("time", now(), "response", hitID)); }
119  
    
120  
    ret response;
121  
  } catch (Throwable e) {
122  
    // log that there was an error
123  
    pcall { webLog(litmap("time", now(), "response-error", hitID, getStackTrace(e))); }
124  
    throw asRuntimeException(e);
125  
  }
126  
}
127  
  
128  
static NanoHTTPD.Response serveNoLog(S uri, NanoHTTPD.Method method,
129  
  Map<S,S> header, Map<S,S> params, Map<S,S> files) {
130  
  
131  
  actualURI.set(uri);
132  
  if (nempty(files))
133  
    print("URI: " + uri + ", files: " + files);
134  
  uploadFiles.set(files);
135  
  if (!startsWith(uri, "/")) ret serve404("Bad URI");
136  
  uri = dropPrefixMandatory("/", uri);
137  
  
138  
  if (!loaded) {
139  
    int numLoaded = l(bots), total = l(botIDs);
140  
    
141  
    // query dispatcher for number of loaded sub-bots
142  
    
143  
    S lbi = loadingBotID;
144  
    if (sameSnippetID(lbi, "#1002317")) {
145  
      int[] x = (int[]) callOpt(loadingBot, "numLoaded");
146  
      if (x != null) {
147  
        numLoaded += x[0];
148  
        total += x[1];
149  
      }
150  
      
151  
      lbi = or((S) getOpt(loadingBot, "loadingBotID"), lbi);
152  
    }
153  
    
154  
    S s = "LOADING, PLEASE TRY AGAIN. " + numLoaded + "/" + total + " bots loaded ";
155  
    if (lbi != null) 
156  
      s +=  " (loading bot " + formatSnippetID(lbi) /*+ " - " + getSnippetTitle_overBot(lbi)*/ + ")";
157  
    
158  
    ret serve500(s);
159  
  }
160  
  
161  
  // count and set cookie
162  
  O visitorsBot = getBot("#1002157");
163  
  if (visitorsBot != null)
164  
    callHtmlMethod(visitorsBot, "/");
165  
166  
  setDialogIDForWeb();
167  
  
168  
  if (eq(uri, "") || eq(uri, "raw"))
169  
    ret serveHomePage("/", params);
170  
    
171  
  S host = dropFrom(header.get("host"), ":");
172  
  
173  
  if (domainIsUnderOneOf(host, "code.botcompany.de", "tomii.me"))
174  
    ret serveHomePage(uri, params); // Blog Bot handles it
175  
    
176  
  if (eq(uri, "favicon.ico"))
177  
    ret serveFile(loadLibrary(or2(trimLoadTextFile(javaxDataDir("eleu-favicon.txt")), #1101146)), "image/x-icon");
178  
179  
  int i = uri.indexOf('/');
180  
  if (i < 0) { uri += "/"; i = l(uri)-1; }
181  
  S firstPart = uri.substring(0, i);
182  
  
183  
  //print("uri: " + uri + ", i: " + i + ", firstPart: " + firstPart);
184  
  if (botNames.containsKey(firstPart)) {
185  
    uri = dropPrefix("#", botNames.get(firstPart))
186  
      + addPrefix("/", substring(uri, i));
187  
    i = uri.indexOf('/');
188  
    firstPart = i >= 0 ? uri.substring(0, i) : uri;
189  
    //print("now firstPart: " + firstPart + ", uri: " + uri + ", i: " + i);
190  
  }
191  
  
192  
  S rest = i >= 0 ? substr(uri, i) : "/"; // rest always starts with "/"
193  
  
194  
  if (possibleGlobalID(toLower(firstPart))) {
195  
    ret serveBot(#1007510, "/raw/" + uri, params);
196  
    /*AIConcept c = aiConceptsMap_cached().get(toLower(firstPart));
197  
    if (c != null)
198  
      ret serveHTML("Concept found: " + c.globalID + " - " + c.name);
199  
    else
200  
      ret serveHTML("Concept not found: " + toLower(firstPart));*/
201  
  }
202  
203  
  if (!isInteger(firstPart))
204  
    ret serveHomePage("/" + uri, params);
205  
    
206  
  ret serveBot(firstPart, rest, params);
207  
}
208  
209  
static NanoHTTPD.Response serveBot(S botID, S subUri, Map<S, S> params) {
210  
  sleepWhile(() -> isTrue_callOpt(getDispatcher(), 'isReloading, botID));
211  
  
212  
  Class bot = getBot(botID);
213  
  boolean raw = subUri.equals("/raw") || subUri.startsWith("/raw/");
214  
  if (raw) {
215  
    subUri = substr(subUri, "/raw".length());
216  
    if (subUri.length() == 0) subUri = "/";
217  
  }
218  
  if (bot != null) {
219  
    //print("Bot " + botID + " methods: " + structure(allMethodNames(bot)));
220  
    O botOut;
221  
    try {
222  
      botOut = callExtendedHtmlMethod(bot, subUri, params);
223  
    } catch e {
224  
      callOpt(bot, 'print, "Error while serving " + subUri + ": " + stackTraceToString(e));
225  
      throw rethrow(e);
226  
    }
227  
    
228  
    if (botOut instanceof NanoHTTPD.Response)
229  
      ret (NanoHTTPD.Response) botOut;
230  
    if (eq(getClassName(botOut), NanoHTTPD.Response.class.getName()))
231  
      fail("Wrong realm");
232  
      
233  
    S botHtml = str(botOut);
234  
    S html;
235  
    if (raw) html = unnull(botHtml);
236  
    else {
237  
      if (botHtml == null)
238  
        botHtml = "Bot has no HTML output.";
239  
      S name = getSnippetTitle(botID);
240  
      S title = htmlencode(name) + " [" + formatSnippetID(botID) + "]";
241  
      
242  
      html = botHtml;
243  
      Pair<S> pTitle = hextracttag(html, 'title);
244  
      if (pairBNotNull(pTitle)) title = join(contentsOfContainerTag(htmlTok(pTitle.b)));
245  
      html = pTitle.a;
246  
      html = "<html><head><title>" + title + "</title></head>" +
247  
        "<body><h3>Bot <a href=\"http://tinybrain.de/" + parseSnippetID(botID) + "\">" + formatSnippetID(botID) + "</a> - " + htmlencode(name) + "</h3>\n" + botHtml +
248  
        "\n</body></html>";
249  
    }
250  
    ret serveHTMLNoCache(html);
251  
  }
252  
  
253  
  ret serve404();
254  
}
255  
256  
static NanoHTTPD.Response serveHomePage(S uri, Map<S, S> params) {
257  
  if (nempty(homePageBotID)) {
258  
    O bot = getBot(homePageBotID);
259  
    if (bot != null) /*pcall*/ {
260  
      ret serveHTMLNoCache(callHtmlMethod2(bot, uri, params));
261  
    }
262  
  }
263  
264  
  ret serveHTML(botsListCache!);
265  
}
266  
267  
static TimedCache<S> botsListCache = new(f serveBotsList, 10.0);
268  
269  
static S serveBotsList() {
270  
  new StringBuilder buf;
271  
  buf.append("<html>");
272  
  buf.append("<head><title>TinyBrain Chat Bots</title></head>");
273  
  buf.append("<body>");
274  
  buf.append("<h3><a href=" + htmlQuote("http://tinybrain.de") + ">TinyBrain</a> Bots</h3>");
275  
  buf.append("<ul>");
276  
  
277  
  L<S> botsToList = litlist(getProgramID());
278  
  O dispatcher = getDispatcher();
279  
  if (dispatcher != null)
280  
    botsToList.addAll((L) call(dispatcher, "getSubBotIDs"));
281  
  botsToList.addAll(activeBots);
282  
  
283  
  for (S botID : botsToList) {
284  
    botID = formatSnippetID(botID);
285  
    S parsedID = "" + parseSnippetID(botID);
286  
    S title = "?";
287  
    pcall { title = getSnippetTitle_overBot(botID); }
288  
    S name = botID + " - " + htmlencode(title);
289  
    buf.append("<li><a href=" + htmlQuote(parsedID) + ">" + name + "</a> (");
290  
    buf.append("<a href=" + htmlQuote("http://tinybrain.de/" + parsedID) + ">source</a>)</li>");
291  
  }
292  
  buf.append("</ul>");
293  
  buf.append("<p>Hit count: " + hitCount + "</p>");
294  
  
295  
  buf.append("<p>Last interactions:</p>");
296  
  
297  
  int maxInteractionsToPrint = 10;
298  
  
299  
  for (int i = l(history)-1; i >= 0 && i >= l(history)-maxInteractionsToPrint; i--) {
300  
    Map m = history.get(i);
301  
    buf.append("<p>" + htmlencode(m.get("question")) + "<br>&nbsp; &nbsp; " + htmlencode(m.get("answer")) + "</p>");
302  
  }
303  
  
304  
  buf.append("</body>");
305  
  buf.append("</html>");
306  
  ret str(buf);
307  
}
308  
309  
// for sub-bots to call
310  
static NanoHTTPD.IHTTPSession getSession() {
311  
  ret NanoHTTPD.currentSession.get();
312  
}
313  
314  
// for sub-bots to call
315  
static O getCookies() {
316  
  NanoHTTPD.IHTTPSession session = NanoHTTPD.currentSession.get();
317  
  NanoHTTPD.CookieHandler cookies = session.getCookies();
318  
  ret cookies;
319  
}
320  
321  
static void setDialogIDForWeb() {
322  
  O session = getSession();
323  
  O cookieHandler = getCookies();
324  
  S cookie = cast call(cookieHandler, "read", "cookie");
325  
  //print("Web answer cookie: " + cookie);
326  
  //print("Web answer question: " + quote(s));
327  
  S dialogID = nempty(cookie) ? "web-" + hashCookie(cookie) : anonymousDialogID;
328  
  main.dialogID.set(dialogID);
329  
}
330  
331  
static S webAnswer(S s) {
332  
  ret webAnswer(s, true);
333  
}
334  
335  
static S webAnswer(S s, boolean log) {
336  
  setDialogIDForWeb();
337  
  
338  
  originalLine.set(s);
339  
  
340  
  // drop the attn prefix ("!")
341  
  s = dropPrefix("!", s).trim();
342  
  
343  
  attn.set(true);
344  
  dedicated.set(true);
345  
  // user name is empty for now
346  
        
347  
  S a = null;
348  
  pcall {
349  
    a = answer(s, false); // generalRelease = false, all bots
350  
    print("Web answer: " + quote(a));
351  
    if (empty(a))
352  
      a = "Hello :)";
353  
  }
354  
  if (empty(a)) a = "(no response)";
355  
  
356  
  if (log) {
357  
    S user = getDialogID();
358  
    Map logEntry = litmap("question", s, "user", user, "answer", a);
359  
    historyAdd(logEntry);
360  
  }
361  
  
362  
  ret a;
363  
}
364  
365  
static S hashCookie(S cookie) {
366  
  ret md5(cookie).substring(0, 10);
367  
}
368  
369  
static void webLog(Map data) {
370  
  synchronized(webLock) {
371  
    logStructure(getProgramFile(webLogProgramID, webLog), data);
372  
    if (recentWebLogMax > 0) {
373  
      if (l(recentWebLog) >= recentWebLogMax)
374  
        recentWebLog.remove(0);
375  
      recentWebLog.add(data);
376  
    }
377  
  }
378  
}
379  
380  
static L<Map> getRecentWebLog() {
381  
  synchronized(webLock) {
382  
    ret cloneList(recentWebLog);
383  
  }
384  
}
385  
386  
static synchronized void addBlockedIP(S ip) {
387  
  blockedIPs.add(ip);
388  
  //save("blockedIPs");
389  
}
390  
391  
static synchronized void removeBlockedIP(S ip) {
392  
  blockedIPs.remove(ip);
393  
  //save("blockedIPs");
394  
}
395  
396  
static synchronized void clearBlockedIPs() {
397  
  blockedIPs.clear();
398  
}
399  
400  
} // end of comment

Author comment

Began life as a copy of #1002576

download  show line numbers  debug dex  old transpilations   

Travelled to 4 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt

No comments. add comment

Snippet ID: #1029953
Snippet name: Eleu Web Serving (transpilation test)
Eternal ID of this version: #1029953/8
Text MD5: a9ad973a1955d2df71541e9a71cc620f
Transpilation MD5: bd54f3ce43f95c2f528bdd2185b6e029
Author: stefan
Category: eleu
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2020-10-14 16:33:32
Source code size: 12363 bytes / 400 lines
Pitched / IR pitched: No / No
Views / Downloads: 239 / 309
Version history: 7 change(s)
Referenced in: [show references]