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).

1  
!752
2  
3  
static long minPostDelay = 1000; // 1 second per program
4  
static long presenceTimeout = 1000*60; // 1 minute
5  
static S defaultUser = "anon";
6  
static bool showAds;
7  
8  
static S myURL;
9  
static S image = "http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_1003097&contentType=image/png";
10  
static S image2 = "http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_1003101&contentType=image/png";
11  
12  
sclass Msg {
13  
  long timestamp;
14  
  S user, text;
15  
  long id;
16  
  
17  
  S programID; // which program posted this
18  
  
19  
  *() {}
20  
  *(long *timestamp, S *user, S *text) {}
21  
}
22  
23  
sclass Presence {
24  
  long timestamp;
25  
26  
  *() {}
27  
  *(long *timestamp) {}
28  
}
29  
30  
sclass Suggest {
31  
  long id, onMsgID;
32  
  S text, user, _if, byUser, ip;
33  
  bool likeNow;
34  
}
35  
36  
static PersistentLog<Msg> messages;
37  
static new Map<S, Presence> presences;
38  
static Map<S, L<S>> permanentPresences = new TreeMap;
39  
static PersistentLog<Suggest> suggests;
40  
static new MultiMap<Long, Suggest> suggestsByOnMsg;
41  
static Q feeder;
42  
static new L<S> listeners; // bot IDs
43  
44  
p {
45  
  showAds = amIProgram("#1003081");
46  
  myURL = rawBotLink();
47  
  messages = new PersistentLog("messages");
48  
  load("presences");
49  
  load("permanentPresences");
50  
  clearPresences();
51  
  feeder = new Q("Simple Chat Room Feeder", true);
52  
  load("listeners");
53  
  suggests = new PersistentLog("suggests");
54  
  for (Suggest s : suggests) index(s);
55  
}
56  
57  
static void index(Suggest s) {
58  
  suggestsByOnMsg.put(s.onMsgID, s);
59  
}
60  
61  
ssynchronized bool clearPresences() {
62  
  long expire = now()-presenceTimeout;
63  
  bool anyChange = false;
64  
  for (S name : cloneList(keys(presences))) {
65  
    Presence p = presences.get(name);
66  
    
67  
    // presences expired or program gone away => drop presence
68  
    if (p.timestamp < expire) {
69  
      anyChange = true;
70  
      presences.remove(name);
71  
    }
72  
  }
73  
  if (anyChange)
74  
    save("presences");
75  
  ret anyChange;
76  
}
77  
78  
ssynchronized bool clearPermanentPresences() {
79  
  bool anyChange = false;
80  
  for (S programID : cloneList(keys(permanentPresences))) {
81  
    if (getBot(programID) == null) {
82  
      anyChange = true;
83  
      permanentPresences.remove(programID);
84  
    }
85  
  }
86  
  if (anyChange)
87  
    save("permanentPresences");
88  
  ret anyChange;
89  
}
90  
91  
ssynchronized S post(S user, S text) {
92  
  ret post(user, text, programID());
93  
}
94  
95  
ssynchronized S post(S user, S text, S programID) {
96  
  addPresence(user);
97  
  Msg last = last(messages);
98  
  if (last != null) {
99  
    if (eq(last.text, text) && eq(last.user, user))
100  
      ret "don't repost"; // don't re-post
101  
    if (!sameSnippetID(programID, programID())
102  
      && sameSnippetID(last.programID, programID)
103  
      && last.timestamp >= now()-minPostDelay)
104  
      ret "don't hammer"; // anti hammering
105  
  }
106  
  Msg msg = new Msg(now(), user, text);
107  
  msg.programID = programID;
108  
  msg.id = l(messages)+1;
109  
  messages.add(msg);
110  
  feeder.add(runnable { feedThem(); });
111  
  ret "ok";
112  
}
113  
114  
ssynchronized int size() {
115  
  ret l(messages);
116  
}
117  
118  
ssynchronized L<Msg> getMessages(int startIndex, int endIndex) {
119  
  ret newSubList(messages, startIndex, endIndex);
120  
}
121  
122  
ssynchronized S html(S uri, Map<S, S> params) {
123  
  registerVisitor();
124  
  S user = or2(params.get("user"), defaultUser);
125  
  if (params.get("user") != null) {
126  
    setCookie("chatuser", user);
127  
    //print("Setting user cookie: " + "chatuser" + " = " + user);
128  
  } else {
129  
    user = or2(getCookie("chatuser"), defaultUser);
130  
    //print("Read user cookie: " + user);
131  
  }
132  
  S text = params.get("text");
133  
  bool all = eq("1", params.get("all"));
134  
  bool reveal = false; // eq("1", params.get("reveal"));
135  
  bool ad = eq("1", params.get("ad"));
136  
  if (params.get("ad") != null)
137  
    setCookie("chatad", ad ? "1" : "0");
138  
  else
139  
    ad = eq("1", getCookie("chatad"));
140  
  int lines = parseInt(or2(params.get("n"), "15"));
141  
  //printAllCookies();
142  
  
143  
  addPresence(user);
144  
  
145  
  if (eq(uri, "/n"))
146  
    ret str(l(messages));
147  
    
148  
  bool robo = eq("1", params.get("robo"));
149  
    
150  
  if (eq(uri, "/incremental")) {
151  
    int a = parseInt(params.get("a"));
152  
    int b = parseInt(params.get("b"));
153  
    if (b == 0) b = l(messages);
154  
    L msgs = subList(messages, a, b);
155  
    if (robo)
156  
      ret htmlencode(structure(msgs));
157  
    if (empty(msgs)) ret "";
158  
    ret "<!-- " + l(messages) + "-->\n" 
159  
      + renderMessages(msgs, reveal, false, ad);
160  
  }
161  
  
162  
  if (eq(uri, "/presences"))
163  
    ret htmlencode(structure(allPresences()));
164  
  
165  
  S suggest = params.get("suggest");
166  
  if (nempty(suggest)) {
167  
    new Suggest s;
168  
    s.text = suggest;
169  
    s.user = params.get("user");
170  
    s._if = params.get("if");
171  
    s.onMsgID = parseLong(params.get("id"));
172  
    s.id = l(suggests)+1;
173  
    s.byUser = user;
174  
    s.likeNow = params.get("likenow") != null;
175  
    suggests.add(s);
176  
    index(s);
177  
    ret hrefresh(rawLink());
178  
  }
179  
180  
  if (nempty(text)) {
181  
    post(user, text);
182  
    ret robo ? "ok" : hrefresh(rawLink());
183  
  }
184  
  
185  
  if (robo) ret "ok";
186  
187  
  S formContents = "";
188  
  
189  
  formContents += "Your nick: " + htag("input", "", "type", "text", "name", "user", "value", user);
190  
  formContents += " Your line: " + htag("input", "", "type", "text", "name", "text", "value", "", "autofocus", "1");
191  
  formContents += " " + htag("input", "", "type", "submit", "value", "Send");
192  
  //formContents += hiddenFields(params, keepFields);
193  
  
194  
  L msgs = messages;
195  
  if (!all) msgs = takeLast(msgs, lines);
196  
  
197  
  ret /*h3("Computer Chat Room - where nobody knows you're a \"bot\"")*/
198  
      mobileFontFixer()
199  
    + loadJQuery()
200  
    + javaScript()
201  
    + htitle("RoboChat")
202  
    + body(
203  
        p(ahref(myURL, himg(image)) + " &nbsp; " + ahref(myURL, himg(image2)))
204  
      + div(renderMessages(msgs, reveal, l(messages) > l(msgs), ad), "id", "maindiv", "style", "height: 400px; overflow-x: scroll")
205  
      //+ htmlTable(objectToMap(msgs))
206  
      + p("Present: " + structure(allPresences()))
207  
      + p(htag("form", formContents, "method", "POST", "action", myURL))
208  
      + p(targetBlankLink("http://ai1.lol/wiki/", "Other Homepage")
209  
      + p(targetBlankLink("https://medium.com/@stefanreich", "Read Stefan on medium.com") + "<br>" + targetBlankLink(rawBotLink("#1002213"), "Talk to Eleu"))
210  
      + (showAds ? p(ads()) : ""),
211  
      "onLoad", [[ $("#maindiv").scrollTop(1E10); start(); ]]);
212  
}
213  
214  
ssynchronized void addPresence(S user) {
215  
  if (empty(user)) ret;
216  
  if (permanentPresences.containsKey(user)) ret;
217  
  Presence p = new Presence(now());
218  
  presences.put(user, p);
219  
  save("presences");
220  
}
221  
222  
ssynchronized S postForeign(Class mainClass, S programID, S user, S text) {
223  
  ret post(user, text, programID);
224  
}
225  
226  
ssynchronized void addListener(S botID) {
227  
  if (setAdd(listeners, formatSnippetID(botID))) {
228  
    print("Chat: Added listener " + botID + ", now: " + structure(listeners));
229  
    save("listeners");
230  
  }
231  
}
232  
233  
ssynchronized void removeListener(S botID) {
234  
  listeners.remove(formatSnippetID(botID));
235  
  print("Chat: Removing listener " + botID + ", remaining: " + structure(listeners));
236  
  save("listeners");
237  
}
238  
239  
ssynchronized L<S> getListeners() {
240  
  ret cloneList(listeners);
241  
}
242  
243  
static void feedThem() {
244  
  L<S> listeners = getListeners();
245  
  print("Feeding: " + structure(listeners));
246  
  for (S botID : listeners) pcall {
247  
    O bot = getBot(botID);
248  
    if (bot != null)
249  
      callOpt(bot, "simpleChatUpdated");
250  
    else
251  
      removeListener(botID);
252  
  }
253  
}
254  
255  
static S renderMessages(L<Msg> msgs, bool reveal, bool moreAbove,
256  
  bool ad) {
257  
  new StringBuilder buf;
258  
  if (moreAbove)
259  
    buf.append(ahref(rawLink() + "?all=1", "[...]") + "<br>\n");
260  
  for (Msg m : msgs) {
261  
    buf.append(b(htmlencode(m.user) + ":") + " " + htmlencode(m.text));
262  
    if (ad) {
263  
      S suggestLink = "#"; // rawLink("/suggest?id=" + m.id);
264  
      S formContents = "Suggest saying " + hinputfield("suggest")
265  
        + " as " + hinputfield("user", "someone") + " if (optional) " + hinputfield("if") + hhidden("id", m.id) + ", like now "
266  
        + hcheckbox("likenow", true) + " . "
267  
        + hsubmit("OK");
268  
      S popupHtml = tag("form", formContents, "action", rawLink("suggest"), "method", "POST", "style", "display: inline-block;");
269  
      S extra = "$('#extra" + m.id + "')";
270  
      S onClick = extra + ".html(" + extra + ".html() == '' ? " + javascriptQuote(popupHtml) + " : ''); return false;";
271  
      buf.append(" " + ahref(suggestLink, "&gt;", "onClick", onClick));
272  
      L<Suggest> suggests = suggestsByOnMsg.get(m.id);
273  
      if (nempty(suggests))
274  
        buf.append(" [" + n(l(suggests), "suggest") + "]");
275  
    }
276  
    /*buf.append(" " + tag("div", "", "id", "extra" + m.id,
277  
      "style", "display: inline"));*/
278  
    buf.append(" " + tag("span", "", "id", "extra" + m.id));
279  
    buf.append("<br>\n");
280  
  }
281  
  ret str(buf);
282  
}
283  
284  
static S mobileFontFixer() {
285  
  ret [[<meta name="viewport" content="width=device-width, initial-scale=1">]];
286  
}
287  
288  
// called from other bots - sets a permanent presence
289  
ssynchronized void setPermanentPresence(S programID, L<S> names) {
290  
  permanentPresences.put(formatSnippetID(programID), names);
291  
  clearPermanentPresences();
292  
  save("permanentPresences");
293  
}
294  
295  
ssynchronized L<S> allPresences() {
296  
  clearPresences();
297  
  clearPermanentPresences();
298  
  ret asList(joinSets(
299  
    asSet(concatLists(values(permanentPresences))),
300  
    asSet(keys(presences))));
301  
}
302  
303  
static S ads() {
304  
  ret [[<a href="//www.interserver.net/r/251595"><img src="https://www.interserver.net/logos/interserver125by125.gif" alt="InterServer Web Hosting and VPS"></a>]];
305  
}
306  
307  
static S javaScript() {
308  
  S link = rawLink("incremental?a=");
309  
  ret hjavascript([[
310  
    var n = $N;
311  
    function start() {
312  
      $.get(LINK + n, function(src) {
313  
        var match = src.match(/\d+/);
314  
        if (match != null) {
315  
          n = parseInt(match[0]);
316  
          $("#maindiv").append(src);
317  
          $("#maindiv").scrollTop(1E10);
318  
        }
319  
      }, 'text');
320  
      setTimeout(start, 10000);
321  
    }
322  
  ]]).replace("LINK", jsQuote(link)).replace("$N", lstr(messages));
323  
}

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: 1633 / 2969
Version history: 2 change(s)
Referenced in: [show references]