pike.git / lib / modules / Protocols.pmod / EngineIO.pmod

version» Context lines:

pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:44:      constant protocol = 3; // EIO Protocol version      private enum {    // 0 1 2 3 4 5 6    BASE64='b', OPEN='0', CLOSE, PING, PONG, MESSAGE, UPGRADE, NOOP,    SENDQEMPTY, FORCECLOSE   };      // All EngineIO sessions indexed on sid. - private mapping(string:Server) clients = ([]); + private mapping(string:Socket) clients = ([]);      private Regexp acceptgzip = Regexp("(^|,)gzip(,|$)");   private Regexp xxsua = Regexp(";MSIE|Trident/");      final void setoptions(mapping(string:mixed) _options) {    options += _options;   }      //! @example   //! Sample minimal implementation of an EngineIO server farm:
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:67:   //! id->write(msg);   //!}   //!   //!void wsrequest(array(string) protocols, object req) {   //! httprequest(req);   //!}   //!   //!void httprequest(object req)   //!{ switch (req.not_query)   //! { case "/engine.io/": - //! Protocols.EngineIO.Server server = Protocols.EngineIO.farm(req); - //! if (server) { - //! server.set_callbacks(echo); - //! server.write("Hello world!"); + //! Protocols.EngineIO.Socket client = Protocols.EngineIO.farm(req); + //! if (client) { + //! client.set_callbacks(echo); + //! client.write("Hello world!");   //! }   //! break;   //! }   //!}   //!   //!int main(int argc, array(string) argv)   //!{ Protocols.WebSocket.Port(httprequest, wsrequest, 80);   //! return -1;   //!} - final Server farm(Protocols.WebSocket.Request req) { + final Socket farm(Protocols.WebSocket.Request req) {    string sid;    PD("Request %O\n", req.query);    if (sid = req.variables.sid) { -  Server client; +  Socket client;    if (!(client = clients[sid]))    req.response_and_finish((["data":"Unknown sid",    "error":Protocols.HTTP.HTTP_GONE]));    else    client.onrequest(req);    } else -  return Server(req); +  return Socket(req);    return 0;   }      class Transport {    final function(int, void|string|Stdio.Buffer:void) read_cb;    final Thread.Queue sendq;    final protected int pingtimeout;       protected void create(Protocols.WebSocket.Request req) {    pingtimeout = options->pingTimeout/1000+1;
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:428:    string s = sb.get();    read_cb(s[0], s[1..]);    } else {    int type = bb->read_int8();    read_cb(type, bb->read_buffer(sizeof(bb)));    }    }   }      //! Runs a single Engine.IO session. - class Server { -  private Stdio.Buffer ci = Stdio.Buffer(); -  private function(mixed, string|Stdio.Buffer:void) read_cb; -  private function(mixed:void) close_cb; + class Socket {    //! Contains the last request seen on this connection.    //! Can be used to obtain cookies etc. -  final Protocols.WebSocket.Request lastrequest; -  private mixed id; -  //! The unique session identifier. +  final Protocols.WebSocket.Request request; +  //! The unique session identifier (in the Engine.IO docs referred +  //! to as simply id).    final string sid; -  +  private mixed id; // This is the callback parameter +  private Stdio.Buffer ci = Stdio.Buffer(); +  private function(mixed, string|Stdio.Buffer:void) read_cb; +  private function(mixed:void) close_cb;    private Thread.Queue sendq = Thread.Queue();    private ADT.Queue recvq = ADT.Queue();    private string curtransport; -  private Transport transport; +  private Transport conn;    private Transport upgtransport;    private enum {RUNNING = 0, PAUSED, SCLOSING, RCLOSING};    private int state = RUNNING;       //! Set initial argument on callbacks.    final void set_id(mixed _id) {    id = _id;    }    -  //! Retrieve initial argument on callbacks. Defaults to the Server +  //! Retrieve initial argument on callbacks. Defaults to the Socket    //! object itself.    final mixed query_id() {    return id || this;    }       //! As long as the read callback has not been set, all received messages    //! will be buffered.    final void set_callbacks(    void|function(mixed, string|Stdio.Buffer:void) _read_cb,    void|function(mixed:void) _close_cb) {
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:490:    PD("Queue %s %c:%O\n", sid, type, (string)(msg || ""));    sendq.write(({type, msg || ""}));    switch (state) {    case RUNNING:    case SCLOSING:    flush();    }    }       private void flush() { -  if(catch(transport.flush())) -  transport.close(); +  if(catch(conn.flush())) +  conn.close();    }       private void flushrecvq() {    while (read_cb && !recvq.is_empty())    read_cb(query_id(), recvq.read());    }       //! Close the socket signalling the other side.    final void close() {    if (state < SCLOSING) {
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:519:       private void rclose() {    close();    state = RCLOSING;    m_delete(clients, sid);    }       private void clearcallback() {    close_cb = 0;    read_cb = 0; // Sort of a race, if multithreading -  id = 0; // Delete all references to this Server -  transport = 0; +  id = 0; // Delete all references to this Socket +  conn = 0;    }       private void recv(int type, void|string|Stdio.Buffer msg) {   #ifndef EIO_DEBUGMORE    if (type!=SENDQEMPTY)   #endif    PD("Received %s %c:%O\n", sid, type, (string)msg);    switch (type) {    default: // Protocol error or CLOSE    close();
pike.git/lib/modules/Protocols.pmod/EngineIO.pmod:565:    break;    }    }       private void upgrecv(int type, string|Stdio.Buffer msg) {    switch (type) {    default: // Protocol error or CLOSE    upgtransport = 0;    if (state == PAUSED)    state = RUNNING; -  if(transport) +  if(conn)    flush();    break;    case PING:    state = PAUSED;    if (!sendq.size())    send(NOOP);    flush();    upgtransport.flush(PONG, msg);    break;    case UPGRADE: {    upgtransport.read_cb = recv; -  transport = upgtransport; +  conn = upgtransport;    curtransport = "websocket";    if (state == PAUSED)    state = RUNNING;    upgtransport = 0;    flush();    break;    }    }    }       protected void destroy() {    close();    }       protected void create(Protocols.WebSocket.Request req) { -  lastrequest = req; -  switch (curtransport = req.variables.transport) { +  request = req; +  switch (curtransport = req.variables->transport) {    default:    req.response_and_finish((["data":"Unsupported transport",    "error":Protocols.HTTP.HTTP_UNSUPP_MEDIA]));    return;    case "websocket": -  transport = WebSocket(req, req.websocket_accept(0)); +  conn = WebSocket(req, req.websocket_accept(0));    break;    case "polling": -  transport = req.variables.j ? JSONP(req) : XHR(req); +  conn = req.variables.j ? JSONP(req) : XHR(req);    break;    } -  transport.read_cb = recv; -  transport.sendq = sendq; +  conn.read_cb = recv; +  conn.sendq = sendq;    ci->add(Crypto.Random.random_string(SIDBYTES-TIMEBYTES));    ci->add_hint(gethrtime(), TIMEBYTES);    sid = MIME.encode_base64(ci->read());    clients[sid] = this;    send(OPEN, Standards.JSON.encode(    (["sid":sid,    "upgrades":    options->allowUpgrades ? ({"websocket"}) : ({}),    "pingInterval":options->pingInterval,    "pingTimeout":options->pingTimeout    ])));    PD("New EngineIO sid: %O\n", sid);    }    -  //! Handle request, and returns a new Server object if it's a new +  //! Handle request, and returns a new Socket object if it's a new    //! connection.    final void onrequest(Protocols.WebSocket.Request req) {    string s; -  lastrequest = req; +  request = req;    if ((s = req.variables->transport) == curtransport) -  transport.onrequest(req); +  conn.onrequest(req);    else    switch (s) {    default:    req.response_and_finish((["data":"Invalid transport",    "error":Protocols.HTTP.HTTP_UNSUPP_MEDIA]));    return 0;    case "websocket":    upgtransport = WebSocket(req, req.websocket_accept(0));    upgtransport.read_cb = upgrecv;    upgtransport.sendq = sendq;