• Jump To … +
    index.js server.js socket.js transport-base-transport.js transport-http-base-transport.js transport-http-longpoll-transport.js transport-http-server.js transport-http-stream-transport.js transport-websocket-server.js transport-websocket-transport.js
  • transport-http-base-transport.js

  • ¶
    /*
     * Cettia
     * http://cettia.io/projects/cettia-protocol/
     * 
     * Copyright 2017 the original author or authors.
     * Licensed under the Apache License, Version 2.0
     * http://www.apache.org/licenses/LICENSE-2.0
     */
    var events = require("events");
    var url = require("url");
    var http = require("http");
    var createBaseTransport = require("./transport-base-transport");
  • ¶

    It creates a base transport which provides common functionalities of HTTP transport.

    module.exports = function(uri, options) {
  • ¶

    A transport object.

      var self = createBaseTransport(uri, options);
  • ¶

    A flag to mark the transport is sending data now.

      var sending = false;
  • ¶

    A waiting queue for messages to be sent to the server.

      var queue = [];
  • ¶

    The above sending and queue are required to guarantee messages the client sends to the serve is sent in order.

      self.write = function(data) {
  • ¶

    If sending is false, sets sending to true and sends data immediately without going through the queue.

        if (!sending) {
          sending = true;
          send(data);
  • ¶

    If not, adds data to the waiting queue. Then it will be sent through the queue later.

        } else {
          queue.push(data);
        }
    
        function send(data) {
          var reqOpts = url.parse(uri);
  • ¶

    Somehow it’s turned out that KeepAlive Agent is required on Node 4+.

          reqOpts.agent = new http.Agent({keepAlive: true});
  • ¶

    Prepares for the request headers.

          reqOpts.headers = {};
  • ¶

    cettia-transport-id param should be added to query. As the URI has already cettia-transport-name param, & can be preceded safely.

          reqOpts.path += "&cettia-transport-id=" + encodeURIComponent(self.id);
  • ¶

    The request’s method should be POST.

          reqOpts.method = "POST";
  • ¶

    Any error occurred when performing a request should propagate to transport.

          function onerror(error) {
            self.emit("error", error);
          }
  • ¶

    If the underlying connection of request-response was closed, closes the connection this transport established if it is opened.

          function onclose() {
            if (self.opened) {
  • ¶

    It will fire close event finally.

              self.close();
            }
          }
  • ¶

    The server is supposed to send the response after reading the request body.

          function onresponse() {
  • ¶

    If there are pending data in the queue, removes the first one from the queue and sends it one-by-one.

            if (queue.length) {
  • ¶

    FYI, [1,2,3].shift() returns in 1 and results in [2,3].

              send(queue.shift());
  • ¶

    If not, set false to sending as all data in the waiting queue are sent.

            } else {
              sending = false;
            }
          }
  • ¶

    data should be either a Buffer or a string.

          if (typeof data === "string") {
  • ¶

    The content type header should be text/plain; charset=utf-8 for text message.

            reqOpts.headers["content-type"] = "text/plain; charset=utf-8";
  • ¶

    The final body should be prefixed with data= and encoded in utf-8.

            http.request(reqOpts).on("error", onerror).on("close", onclose).on("response", onresponse)
            .end("data=" + data, "utf-8");
          } else {
  • ¶

    The content type header should be application/octet-stream for binary message.

            reqOpts.headers["content-type"] = "application/octet-stream";
            http.request(reqOpts).on("error", onerror).on("close", onclose).on("response", onresponse)
            .end(data);
          }
        }
      };
      self.close = function() {
  • ¶

    Aborts the real connection. abort should be implemented by others and ensure that close event is fired.

        self.abort();
  • ¶

    Server may not detect disconnection for some reason. Notifies the server of disconnection of this connection to make sure. In this request, cettia-transport-id param should be added to query and cettia-transport-when param should be set to abort.

        var reqOpts = url.parse(uri + "&cettia-transport-when=abort&cettia-transport-id=" + encodeURIComponent(self.id));
  • ¶

    Somehow it’s turned out that KeepAlive Agent is required on Node 4+.

        reqOpts.agent = new http.Agent({keepAlive: true});
        http.request(reqOpts)
  • ¶

    Node.js kills the process by default when an error event is fired if there is no listener for it. However, a user doesn’t need to be notified of an error from this request as it is just for the server.

        .on("error", function() {
        }).end();
        return this;
      };
      return self;
    };