1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 var socket = chrome.experimental.socket || chrome.socket; 6 7 // Stream encapsulates read/write operations over socket. 8 function Stream(delegate, socketId) { 9 this.socketId_ = socketId; 10 this.delegate_ = delegate; 11 } 12 13 Stream.prototype = { 14 stringToUint8Array_: function(string) { 15 var utf8string = unescape(encodeURIComponent(string)); 16 var buffer = new ArrayBuffer(utf8string.length); 17 var view = new Uint8Array(buffer); 18 for(var i = 0; i < utf8string.length; i++) { 19 view[i] = utf8string.charCodeAt(i); 20 } 21 return view; 22 }, 23 24 read: function(callback) { 25 socket.read(this.socketId_, function(readInfo) { 26 callback(this, readInfo); 27 }.bind(this)); 28 }, 29 30 write: function(output) { 31 var header = this.stringToUint8Array_(output + '\n\n'); 32 var outputBuffer = new ArrayBuffer(header.byteLength); 33 var view = new Uint8Array(outputBuffer); 34 view.set(header, 0); 35 socket.write(this.socketId_, outputBuffer, function(writeInfo) { 36 if (writeInfo.bytesWritten < 0) 37 this.delegate_.onStreamError(this); 38 }.bind(this)); 39 }, 40 41 writeError: function(errorCode, description) { 42 var content = JSON.stringify({'type': 'error', 43 'code': errorCode, 44 'description': description}); 45 var buffer = this.stringToUint8Array_(content + "\n\n"); 46 var outputBuffer = new ArrayBuffer(buffer.byteLength); 47 var view = new Uint8Array(outputBuffer); 48 view.set(buffer, 0); 49 socket.write(this.socketId_, outputBuffer, function(writeInfo) { 50 this.terminateConnection_(); 51 }.bind(this)); 52 }, 53 54 terminateConnection_: function() { 55 this.delegate_.onStreamTerminated(this); 56 socket.destroy(this.socketId_); 57 } 58 }; 59 60 // Automation server listens socket and passed its processing to 61 // |connectionHandler|. 62 function AutomationServer(connectionHandler) { 63 this.socketInfo = null; 64 this.handler_ = connectionHandler; 65 } 66 67 AutomationServer.instance_ = null; 68 69 AutomationServer.getInstance = function() { 70 if (!AutomationServer.instance_) 71 AutomationServer.instance_ = new AutomationServer(new ConnectionHandler()); 72 73 return AutomationServer.instance_; 74 } 75 76 AutomationServer.prototype = { 77 onAccept_: function(acceptInfo) { 78 console.log("Accepting socket " + acceptInfo.socketId); 79 socket.setNoDelay(acceptInfo.socketId, true, function(result) { 80 this.handler_.readRequest_(new Stream(this.handler_, 81 acceptInfo.socketId)); 82 socket.accept(this.socketInfo.socketId, this.onAccept_.bind(this)); 83 }.bind(this)); 84 }, 85 86 start: function() { 87 socket.create("tcp", {}, function(_socketInfo) { 88 this.socketInfo = _socketInfo; 89 socket.listen(this.socketInfo.socketId, "127.0.0.1", 8666, 20, 90 function(result) { 91 console.log("LISTENING:", result); 92 socket.accept(this.socketInfo.socketId, this.onAccept_.bind(this)); 93 }.bind(this)); 94 }.bind(this)); 95 } 96 }; 97