chromium/chrome/test/ext_auto/auto_provider/server.js

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var socket = chrome.experimental.socket || chrome.socket;

// Stream encapsulates read/write operations over socket.
function Stream(delegate, socketId) {
  this.socketId_ = socketId;
  this.delegate_ = delegate;
}

Stream.prototype = {
  stringToUint8Array_: function(string) {
    var utf8string = unescape(encodeURIComponent(string));
    var buffer = new ArrayBuffer(utf8string.length);
    var view = new Uint8Array(buffer);
    for(var i = 0; i < utf8string.length; i++) {
      view[i] = utf8string.charCodeAt(i);
    }
    return view;
  },

  read: function(callback) {
    socket.read(this.socketId_, function(readInfo) {
      callback(this, readInfo);
    }.bind(this));
  },

  write: function(output) {
    var header = this.stringToUint8Array_(output + '\n\n');
    var outputBuffer = new ArrayBuffer(header.byteLength);
    var view = new Uint8Array(outputBuffer);
    view.set(header, 0);
    socket.write(this.socketId_, outputBuffer, function(writeInfo) {
      if (writeInfo.bytesWritten < 0)
        this.delegate_.onStreamError(this);
    }.bind(this));
  },

  writeError: function(errorCode, description) {
    var content = JSON.stringify({'type': 'error',
                                  'code': errorCode,
                                  'description': description});
    var buffer = this.stringToUint8Array_(content + "\n\n");
    var outputBuffer = new ArrayBuffer(buffer.byteLength);
    var view = new Uint8Array(outputBuffer);
    view.set(buffer, 0);
    socket.write(this.socketId_, outputBuffer, function(writeInfo) {
      this.terminateConnection_();
    }.bind(this));
  },

  terminateConnection_: function() {
    this.delegate_.onStreamTerminated(this);
    socket.destroy(this.socketId_);
  }
};

// Automation server listens socket and passed its processing to
// |connectionHandler|.
function AutomationServer(connectionHandler) {
  this.socketInfo = null;
  this.handler_ = connectionHandler;
}

AutomationServer.instance_ = null;

AutomationServer.getInstance = function() {
  if (!AutomationServer.instance_)
    AutomationServer.instance_ = new AutomationServer(new ConnectionHandler());

  return AutomationServer.instance_;
}

AutomationServer.prototype = {
  onAccept_: function(acceptInfo) {
    console.log("Accepting socket " + acceptInfo.socketId);
    socket.setNoDelay(acceptInfo.socketId, true, function(result) {
      this.handler_.readRequest_(new Stream(this.handler_,
                                            acceptInfo.socketId));
      socket.accept(this.socketInfo.socketId, this.onAccept_.bind(this));
    }.bind(this));
  },

  start: function() {
    socket.create("tcp", {}, function(_socketInfo) {
      this.socketInfo = _socketInfo;
      socket.listen(this.socketInfo.socketId, "127.0.0.1", 8666, 20,
        function(result) {
          console.log("LISTENING:", result);
          socket.accept(this.socketInfo.socketId, this.onAccept_.bind(this));
        }.bind(this));
    }.bind(this));
  }
};