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

116
LINES

< > BotCompany Repo | #1013904 // Eleu WebSocket Include

JavaX fragment (include)

static long webSocketTimeOut = 60000; // can be changed per WebSocket

static O eleu_webSocket_onMessage, eleu_webSocket_new;
static O eleu_webSocket_handler;

static Set<MyWebSocket> webSockets = synchroHashSet();
static new AtomicLong webSocketPings;
static new AtomicLong webSocketPongs;

svoid eleu_webSocket_init {
  if (nempty(webServerPorts)) pcall {
    //serveHttp(webServerPort);
    //serveHttpWithWebsockets(webServerPort, eleu_webSocket_handler());
    //serveHttpWithWebsockets_server.printServes = false;
    serveHttpWithWebsockets_multiplePorts(eleu_webSocket_handler(), webServerPorts);
  }
  doEvery_daemon(5000, r cleanWebSockets);
}

sclass MyWebSocket extends WebSocket {
  L<S> msgs = synchroList();
  volatile long lastMessage = sysNow();
  S botID;
  WeakReference bot;
  long timeout = webSocketTimeOut;

  *(NanoHTTPD.IHTTPSession handshake) { super(handshake); }
  
  public void sendFrame(WebSocketFrame frame) throws IOException {
    frame.write(out);
    // assume write worked?
    lastMessage = sysNow();
  }

  protected void onPong(WebSocketFrame pongFrame) {
    // don't use WebSocket ping/pong - it doesn't work
  }
  
  protected void onMessage(WebSocketFrame messageFrame) {
    //print("websocket msg: " + messageFrame.getTextPayload());
    lastMessage = sysNow();
    S s = messageFrame.getTextPayload();
    if (eq(s, "ping")) incAtomicLong(webSocketPongs);
    pcall {
      if (botID != null)
        call(getBot(botID), 'onWebSocketMessage, this, s);
      else {
        msgs.add(s);
        callF(eleu_webSocket_onMessage, this, s);
      }
    }
  }
  
  protected void onClose(WebSocketFrame.CloseCode code, String reason, boolean initiatedByRemote) {
    //print("websocket close");
    _removeMe();
  }
  protected void onException(IOException e) { printStackTrace(e); }
  
  void _removeMe() {
    webSockets.remove(this);
    if (botID != null)
      pcall(getBot(botID), 'onWebSocketClosed, this);
  }
  
  void closeMe() ctex {
    _removeMe();
    close(WebSocketFrame.CloseCode.NormalClosure, "");
  }
  
  void clean() {
    if (timeout > 0 && sysNow() >= lastMessage + timeout) {
      print("Timing out web socket for bot " + botID);
      _removeMe();
      pcall { close(WebSocketFrame.CloseCode.NormalClosure, "timeout"); }
    }
  }
}

static O eleu_webSocket_handler() {
  if (eleu_webSocket_handler == null)
    eleu_webSocket_handler = func(final NanoHTTPD.IHTTPSession handshake) {
      MyWebSocket ws = new(handshake);
      S uri = handshake.getUri();
      print("WebSocket URI: " + uri);
      webSockets.add(ws);
      bool dispatched = false;
      try {
        uri = dropPrefix("/", uri);
        int i = smartIndexOf(uri, '/');
        S botID = takeFirst(i, uri);
        if (isInteger(botID)) {
          botID = fsI(botID);
          dispatched = true;
          O bot = getBot(botID);
          if (bot == null) fail("Bot not found: " + botID);
          ws.bot = new WeakReference(bot);
          call(bot, 'onNewWebSocket, ws, or2(substring(uri, i), "/"));
          print("WebSocket dispatched to " + botID);
          ws.botID = botID;
        }
      } catch e {
        printException(e);
        ws.closeMe();
        null;
      }
      if (!dispatched)
        pcallF(eleu_webSocket_new, ws);
      ret ws;
    };
  ret eleu_webSocket_handler;
}

static void cleanWebSockets() {
  for (MyWebSocket ws : cloneList(webSockets)) ws.clean();
}

download  show line numbers  debug dex  old transpilations   

Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1013904
Snippet name: Eleu WebSocket Include
Eternal ID of this version: #1013904/34
Text MD5: 7cd2fdb0677ccb55ffe34c195a8d2c54
Author: stefan
Category: javax / web
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-03-30 18:46:32
Source code size: 3548 bytes / 116 lines
Pitched / IR pitched: No / No
Views / Downloads: 443 / 1207
Version history: 33 change(s)
Referenced in: #1002017 - Eleutheria Main, including Slack Bot (LIVE)
#1013896 - Eleutheria Main for butter.botcompany.de + Stefan's OS (LIVE)
#1022823 - Eleutheria Main for butter.botcompany.de as Dyn Module [dev.]
#1023951 - agi.blue Standalone with GUI [OK]
#1024026 - Eleutheria Main for butter.botcompany.de (backup without Stefan's OS)