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

323
LINES

< > BotCompany Repo | #1003081 // RoboChat (Simple Chat Room)

JavaX source code [tags: use-pretranspiled] - run with: x30.jar

Libraryless. Click here for Pure Java version (4925L/33K/113K).

!752

static long minPostDelay = 1000; // 1 second per program
static long presenceTimeout = 1000*60; // 1 minute
static S defaultUser = "anon";
static bool showAds;

static S myURL;
static S image = "http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_1003097&contentType=image/png";
static S image2 = "http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_1003101&contentType=image/png";

sclass Msg {
  long timestamp;
  S user, text;
  long id;
  
  S programID; // which program posted this
  
  *() {}
  *(long *timestamp, S *user, S *text) {}
}

sclass Presence {
  long timestamp;

  *() {}
  *(long *timestamp) {}
}

sclass Suggest {
  long id, onMsgID;
  S text, user, _if, byUser, ip;
  bool likeNow;
}

static PersistentLog<Msg> messages;
static new Map<S, Presence> presences;
static Map<S, L<S>> permanentPresences = new TreeMap;
static PersistentLog<Suggest> suggests;
static new MultiMap<Long, Suggest> suggestsByOnMsg;
static Q feeder;
static new L<S> listeners; // bot IDs

p {
  showAds = amIProgram("#1003081");
  myURL = rawBotLink();
  messages = new PersistentLog("messages");
  load("presences");
  load("permanentPresences");
  clearPresences();
  feeder = new Q("Simple Chat Room Feeder", true);
  load("listeners");
  suggests = new PersistentLog("suggests");
  for (Suggest s : suggests) index(s);
}

static void index(Suggest s) {
  suggestsByOnMsg.put(s.onMsgID, s);
}

ssynchronized bool clearPresences() {
  long expire = now()-presenceTimeout;
  bool anyChange = false;
  for (S name : cloneList(keys(presences))) {
    Presence p = presences.get(name);
    
    // presences expired or program gone away => drop presence
    if (p.timestamp < expire) {
      anyChange = true;
      presences.remove(name);
    }
  }
  if (anyChange)
    save("presences");
  ret anyChange;
}

ssynchronized bool clearPermanentPresences() {
  bool anyChange = false;
  for (S programID : cloneList(keys(permanentPresences))) {
    if (getBot(programID) == null) {
      anyChange = true;
      permanentPresences.remove(programID);
    }
  }
  if (anyChange)
    save("permanentPresences");
  ret anyChange;
}

ssynchronized S post(S user, S text) {
  ret post(user, text, programID());
}

ssynchronized S post(S user, S text, S programID) {
  addPresence(user);
  Msg last = last(messages);
  if (last != null) {
    if (eq(last.text, text) && eq(last.user, user))
      ret "don't repost"; // don't re-post
    if (!sameSnippetID(programID, programID())
      && sameSnippetID(last.programID, programID)
      && last.timestamp >= now()-minPostDelay)
      ret "don't hammer"; // anti hammering
  }
  Msg msg = new Msg(now(), user, text);
  msg.programID = programID;
  msg.id = l(messages)+1;
  messages.add(msg);
  feeder.add(runnable { feedThem(); });
  ret "ok";
}

ssynchronized int size() {
  ret l(messages);
}

ssynchronized L<Msg> getMessages(int startIndex, int endIndex) {
  ret newSubList(messages, startIndex, endIndex);
}

ssynchronized S html(S uri, Map<S, S> params) {
  registerVisitor();
  S user = or2(params.get("user"), defaultUser);
  if (params.get("user") != null) {
    setCookie("chatuser", user);
    //print("Setting user cookie: " + "chatuser" + " = " + user);
  } else {
    user = or2(getCookie("chatuser"), defaultUser);
    //print("Read user cookie: " + user);
  }
  S text = params.get("text");
  bool all = eq("1", params.get("all"));
  bool reveal = false; // eq("1", params.get("reveal"));
  bool ad = eq("1", params.get("ad"));
  if (params.get("ad") != null)
    setCookie("chatad", ad ? "1" : "0");
  else
    ad = eq("1", getCookie("chatad"));
  int lines = parseInt(or2(params.get("n"), "15"));
  //printAllCookies();
  
  addPresence(user);
  
  if (eq(uri, "/n"))
    ret str(l(messages));
    
  bool robo = eq("1", params.get("robo"));
    
  if (eq(uri, "/incremental")) {
    int a = parseInt(params.get("a"));
    int b = parseInt(params.get("b"));
    if (b == 0) b = l(messages);
    L msgs = subList(messages, a, b);
    if (robo)
      ret htmlencode(structure(msgs));
    if (empty(msgs)) ret "";
    ret "<!-- " + l(messages) + "-->\n" 
      + renderMessages(msgs, reveal, false, ad);
  }
  
  if (eq(uri, "/presences"))
    ret htmlencode(structure(allPresences()));
  
  S suggest = params.get("suggest");
  if (nempty(suggest)) {
    new Suggest s;
    s.text = suggest;
    s.user = params.get("user");
    s._if = params.get("if");
    s.onMsgID = parseLong(params.get("id"));
    s.id = l(suggests)+1;
    s.byUser = user;
    s.likeNow = params.get("likenow") != null;
    suggests.add(s);
    index(s);
    ret hrefresh(rawLink());
  }

  if (nempty(text)) {
    post(user, text);
    ret robo ? "ok" : hrefresh(rawLink());
  }
  
  if (robo) ret "ok";

  S formContents = "";
  
  formContents += "Your nick: " + htag("input", "", "type", "text", "name", "user", "value", user);
  formContents += " Your line: " + htag("input", "", "type", "text", "name", "text", "value", "", "autofocus", "1");
  formContents += " " + htag("input", "", "type", "submit", "value", "Send");
  //formContents += hiddenFields(params, keepFields);
  
  L msgs = messages;
  if (!all) msgs = takeLast(msgs, lines);
  
  ret /*h3("Computer Chat Room - where nobody knows you're a \"bot\"")*/
      mobileFontFixer()
    + loadJQuery()
    + javaScript()
    + htitle("RoboChat")
    + body(
        p(ahref(myURL, himg(image)) + " &nbsp; " + ahref(myURL, himg(image2)))
      + div(renderMessages(msgs, reveal, l(messages) > l(msgs), ad), "id", "maindiv", "style", "height: 400px; overflow-x: scroll")
      //+ htmlTable(objectToMap(msgs))
      + p("Present: " + structure(allPresences()))
      + p(htag("form", formContents, "method", "POST", "action", myURL))
      + p(targetBlankLink("http://ai1.lol/wiki/", "Other Homepage")
      + p(targetBlankLink("https://medium.com/@stefanreich", "Read Stefan on medium.com") + "<br>" + targetBlankLink(rawBotLink("#1002213"), "Talk to Eleu"))
      + (showAds ? p(ads()) : ""),
      "onLoad", [[ $("#maindiv").scrollTop(1E10); start(); ]]);
}

ssynchronized void addPresence(S user) {
  if (empty(user)) ret;
  if (permanentPresences.containsKey(user)) ret;
  Presence p = new Presence(now());
  presences.put(user, p);
  save("presences");
}

ssynchronized S postForeign(Class mainClass, S programID, S user, S text) {
  ret post(user, text, programID);
}

ssynchronized void addListener(S botID) {
  if (setAdd(listeners, formatSnippetID(botID))) {
    print("Chat: Added listener " + botID + ", now: " + structure(listeners));
    save("listeners");
  }
}

ssynchronized void removeListener(S botID) {
  listeners.remove(formatSnippetID(botID));
  print("Chat: Removing listener " + botID + ", remaining: " + structure(listeners));
  save("listeners");
}

ssynchronized L<S> getListeners() {
  ret cloneList(listeners);
}

static void feedThem() {
  L<S> listeners = getListeners();
  print("Feeding: " + structure(listeners));
  for (S botID : listeners) pcall {
    O bot = getBot(botID);
    if (bot != null)
      callOpt(bot, "simpleChatUpdated");
    else
      removeListener(botID);
  }
}

static S renderMessages(L<Msg> msgs, bool reveal, bool moreAbove,
  bool ad) {
  new StringBuilder buf;
  if (moreAbove)
    buf.append(ahref(rawLink() + "?all=1", "[...]") + "<br>\n");
  for (Msg m : msgs) {
    buf.append(b(htmlencode(m.user) + ":") + " " + htmlencode(m.text));
    if (ad) {
      S suggestLink = "#"; // rawLink("/suggest?id=" + m.id);
      S formContents = "Suggest saying " + hinputfield("suggest")
        + " as " + hinputfield("user", "someone") + " if (optional) " + hinputfield("if") + hhidden("id", m.id) + ", like now "
        + hcheckbox("likenow", true) + " . "
        + hsubmit("OK");
      S popupHtml = tag("form", formContents, "action", rawLink("suggest"), "method", "POST", "style", "display: inline-block;");
      S extra = "$('#extra" + m.id + "')";
      S onClick = extra + ".html(" + extra + ".html() == '' ? " + javascriptQuote(popupHtml) + " : ''); return false;";
      buf.append(" " + ahref(suggestLink, "&gt;", "onClick", onClick));
      L<Suggest> suggests = suggestsByOnMsg.get(m.id);
      if (nempty(suggests))
        buf.append(" [" + n(l(suggests), "suggest") + "]");
    }
    /*buf.append(" " + tag("div", "", "id", "extra" + m.id,
      "style", "display: inline"));*/
    buf.append(" " + tag("span", "", "id", "extra" + m.id));
    buf.append("<br>\n");
  }
  ret str(buf);
}

static S mobileFontFixer() {
  ret [[<meta name="viewport" content="width=device-width, initial-scale=1">]];
}

// called from other bots - sets a permanent presence
ssynchronized void setPermanentPresence(S programID, L<S> names) {
  permanentPresences.put(formatSnippetID(programID), names);
  clearPermanentPresences();
  save("permanentPresences");
}

ssynchronized L<S> allPresences() {
  clearPresences();
  clearPermanentPresences();
  ret asList(joinSets(
    asSet(concatLists(values(permanentPresences))),
    asSet(keys(presences))));
}

static S ads() {
  ret [[<a href="//www.interserver.net/r/251595"><img src="https://www.interserver.net/logos/interserver125by125.gif" alt="InterServer Web Hosting and VPS"></a>]];
}

static S javaScript() {
  S link = rawLink("incremental?a=");
  ret hjavascript([[
    var n = $N;
    function start() {
      $.get(LINK + n, function(src) {
        var match = src.match(/\d+/);
        if (match != null) {
          n = parseInt(match[0]);
          $("#maindiv").append(src);
          $("#maindiv").scrollTop(1E10);
        }
      }, 'text');
      setTimeout(start, 10000);
    }
  ]]).replace("LINK", jsQuote(link)).replace("$N", lstr(messages));
}

download  show line numbers  debug dex  old transpilations   

Travelled to 17 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, jtubtzbbkimh, lhdilzshxjzv, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt, vzpxdoxhqfnw

No comments. add comment

Snippet ID: #1003081
Snippet name: RoboChat (Simple Chat Room)
Eternal ID of this version: #1003081/3
Text MD5: 63564fd0dfb66484d73bd078211871b8
Transpilation MD5: b0f79a08f73f6fd78d67ad76fd285a8b
Author: stefan
Category: javax
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2017-06-22 11:56:01
Source code size: 10027 bytes / 323 lines
Pitched / IR pitched: No / No
Views / Downloads: 1530 / 2852
Version history: 2 change(s)
Referenced in: [show references]