From 126d343dea6b416b110543c0f0a60e5fa3302e19 Mon Sep 17 00:00:00 2001
From: Ruben Daniels <ruben@c9.io>
Date: Tue, 21 May 2013 18:33:42 +0200
Subject: [PATCH 01/12] * Added PTY support

---
 consumer.js  | 32 ++++++++++++++++++++++++++------
 package.json |  2 +-
 2 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/consumer.js b/consumer.js
index 6d84985..0c0e984 100644
--- a/consumer.js
+++ b/consumer.js
@@ -1,6 +1,6 @@
 ( // Module boilerplate to support browser globals, node.js and AMD.
   (typeof module !== "undefined" && function (m) { module.exports = m(require('stream'), require('events'), require('smith')); }) ||
-  (typeof define === "function" && function (m) { define("vfs-socket/consumer", ["./stream-amd", "./events-amd", "smith"], m); }) ||
+  (typeof define === "function" && function (m) { define(["./stream-amd", "./events-amd", "smith"], m); }) ||
   (function (m) { window.consumer = m(window.stream, window.events, window.smith); })
 )(function (stream, events, smith) {
 "use strict";
@@ -74,6 +74,7 @@ function Consumer() {
         watch:    route("watch"),
         connect:  route("connect"),
         spawn:    route("spawn"),
+        pty:      route("pty"),
         execFile: route("execFile"),
         extend:   route("extend"),
         unextend: route("unextend"),
@@ -124,6 +125,10 @@ function Consumer() {
             proxyApi.emit("error", err);
         });
     });
+    
+    this.on("error", function(err){
+        this.emit("error", err);
+    })
 
     var nextStreamID = 1;
     function storeStream(stream) {
@@ -137,9 +142,9 @@ function Consumer() {
                     stream.pause && stream.pause();
                 }
             });
-            stream.on("end", function () {
+            stream.on("end", function (chunk) {
                 delete streams[id];
-                remote.onEnd(id);
+                remote.onEnd(id, chunk);
                 nextStreamID = id;
             });
         }
@@ -194,6 +199,19 @@ function Consumer() {
         };
         return process;
     }
+    function makePtyProxy(token){
+        var pty = makeStreamProxy(token);
+        var pid = token.pid;
+        pty.pid = pid;
+        proxyProcesses[pid] = pty;
+        pty.kill = function (signal) {
+            remote.kill(pid, signal);
+        };
+        pty.resize = function (cols, rows) {
+            remote.resize(pid, cols, rows);
+        };
+        return pty;
+    }
 
     function makeWatcherProxy(token) {
         var watcher = new EventEmitter();
@@ -249,13 +267,13 @@ function Consumer() {
         if (!stream) return;
         stream.emit("data", chunk);
     }
-    function onEnd(id) {
+    function onEnd(id, chunk) {
         var stream = proxyStreams[id];
         if (!stream) return;
         // TODO: not delete proxy if close is going to be called later.
         // but somehow do delete proxy if close won't be called later.
         delete proxyStreams[id];
-        stream.emit("end");
+        stream.emit("end", chunk);
     }
     function onClose(id) {
         var stream = proxyStreams[id];
@@ -361,6 +379,9 @@ function Consumer() {
         if (meta.process) {
             meta.process = makeProcessProxy(meta.process);
         }
+        if (meta.pty) {
+            meta.pty = makePtyProxy(meta.pty);
+        }
         if (meta.watcher) {
             meta.watcher = makeWatcherProxy(meta.watcher);
         }
@@ -393,7 +414,6 @@ inherits(Consumer, Agent);
 
 // Emit the wrapped API, not the raw one
 Consumer.prototype._emitConnect = function () {
-    this.vfs.env = this.remoteEnv;
     this.emit("connect", this.vfs);
 };
 
diff --git a/package.json b/package.json
index 384626b..3bb77d2 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
     ],
     "name": "vfs-socket",
     "description": "A vfs helper library that communicates through a serialized socket",
-    "version": "0.3.12",
+    "version": "0.3.13",
     "repository": {
         "type": "git",
         "url": "git://github.com/c9/vfs-socket.git"

From 0829ad714d128f3603d6b0a000e5d04e67e60188 Mon Sep 17 00:00:00 2001
From: Ruben Daniels <ruben@c9.io>
Date: Tue, 21 May 2013 18:33:59 +0200
Subject: [PATCH 02/12] * including the worker

---
 worker.js | 43 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/worker.js b/worker.js
index 04811d2..8a4895a 100644
--- a/worker.js
+++ b/worker.js
@@ -30,6 +30,9 @@ function Worker(vfs) {
         // Endpoints for processes at meta.process
         kill: kill,
 
+        // Endpoints for processes at meta.pty
+        resize: resize,
+
         // Endpoint for watchers at meta.watcher
         close: closeWatcher,
 
@@ -59,6 +62,7 @@ function Worker(vfs) {
         watch:    route("watch"),
         connect:  route("connect"),
         spawn:    route("spawn"),
+        pty:      route("pty"),
         execFile: route("execFile"),
         extend:   route("extend"),
         unextend: route("unextend"),
@@ -162,9 +166,9 @@ function Worker(vfs) {
                     stream.pause && stream.pause();
                 }
             });
-            stream.on("end", function () {
+            stream.on("end", function (chunk) {
                 delete streams[id];
-                remote.onEnd(id);
+                remote.onEnd(id, chunk);
                 nextStreamID = id;
             });
         }
@@ -179,7 +183,7 @@ function Worker(vfs) {
         return token;
     }
 
-    function storeProcess(process) {
+    function storeProcess(process, onlyPid) {
         var pid = process.pid;
         processes[pid] = process;
         process.on("exit", function (code, signal) {
@@ -188,15 +192,20 @@ function Worker(vfs) {
         });
         process.on("close", function () {
             delete processes[pid];
-            delete streams[process.stdout.id];
-            delete streams[process.stderr.id];
-            delete streams[process.stdin.id];
+            if (!onlyPid) {
+                delete streams[process.stdout.id];
+                delete streams[process.stderr.id];
+                delete streams[process.stdin.id];
+            }
             remote.onProcessClose(pid);
         });
 
         process.kill = function(code) {
             killtree(pid, code);
         };
+        
+        if (onlyPid)
+            return pid;
 
         var token = {pid: pid};
         token.stdin = storeStream(process.stdin);
@@ -204,6 +213,14 @@ function Worker(vfs) {
         token.stderr = storeStream(process.stderr);
         return token;
     }
+    
+    function storePty(pty) {
+        var pid = storeProcess(pty, true);
+        var token = storeStream(pty);
+        token.pid = pid;
+        
+        return token;
+    }
 
     function killtree(pid, code) {
         childrenOfPid(pid, function(err, pidlist){
@@ -293,6 +310,15 @@ function Worker(vfs) {
         process.kill(code);
     }
 
+    function resize(pid, cols, rows) {
+        var process = processes[pid];
+        if (!process) return;
+        
+        // Resize can throw
+        try { process.resize(cols, rows); }
+        catch(e) {};
+    }
+
     function closeWatcher(id) {
         var watcher = watchers[id];
         if (!watcher) return;
@@ -324,13 +350,13 @@ function Worker(vfs) {
         if (!stream) return;
         stream.emit("data", chunk);
     }
-    function onEnd(id) {
+    function onEnd(id, chunk) {
         var stream = proxyStreams[id];
         if (!stream) return;
         // TODO: not delete proxy if close is going to be called later.
         // but somehow do delete proxy if close won't be called later.
         delete proxyStreams[id];
-        stream.emit("end");
+        stream.emit("end", chunk);
     }
     function onClose(id) {
         var stream = proxyStreams[id];
@@ -361,6 +387,7 @@ function Worker(vfs) {
             switch (key) {
                 case "stream": token.stream = storeStream(meta.stream); break;
                 case "process": token.process = storeProcess(meta.process); break;
+                case "pty": token.pty = storePty(meta.pty); break;
                 case "watcher": token.watcher = storeWatcher(meta.watcher); break;
                 case "api": token.api = storeApi(meta.api); break;
                 default: token[key] = meta[key]; break;

From 0f62efc560b9558881dd835cf1a997f54ec1ca4a Mon Sep 17 00:00:00 2001
From: Ruben Daniels <ruben@c9.io>
Date: Tue, 21 May 2013 18:38:23 +0200
Subject: [PATCH 03/12] * Reverted accidental change

---
 consumer.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/consumer.js b/consumer.js
index 0c0e984..55dc12c 100644
--- a/consumer.js
+++ b/consumer.js
@@ -414,6 +414,7 @@ inherits(Consumer, Agent);
 
 // Emit the wrapped API, not the raw one
 Consumer.prototype._emitConnect = function () {
+    this.vfs.env = this.remoteEnv;
     this.emit("connect", this.vfs);
 };
 

From 30ce5f320705ae84b9a8517b9bb975f47fbb1b0c Mon Sep 17 00:00:00 2001
From: Ruben Daniels <ruben@c9.io>
Date: Fri, 24 May 2013 22:08:35 +0000
Subject: [PATCH 04/12] Basic deploy workflow

---
 events-amd.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/events-amd.js b/events-amd.js
index ca8b051..4b787e1 100644
--- a/events-amd.js
+++ b/events-amd.js
@@ -261,6 +261,7 @@ EventEmitter.prototype.removeListener = function(type, listener) {
 
   return this;
 };
+EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
 
 /**
  * Removes all listeners, or those of the specified event.

From 5555e88847ea09d1132009cade9eb36da2aaa0ce Mon Sep 17 00:00:00 2001
From: nightwing <amirjanyan@gmail.com>
Date: Fri, 14 Jun 2013 21:07:20 +0400
Subject: [PATCH 05/12] do not crash chrome intentionally

---
 consumer.js | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/consumer.js b/consumer.js
index 55dc12c..c09a761 100644
--- a/consumer.js
+++ b/consumer.js
@@ -127,8 +127,9 @@ function Consumer() {
     });
     
     this.on("error", function(err){
-        this.emit("error", err);
-    })
+        // just adding an empty listener so that events-amd doesn't throw
+        console.error(err);
+    });
 
     var nextStreamID = 1;
     function storeStream(stream) {

From 1fd048d480d95891f7c633428bb86eabbe3aa140 Mon Sep 17 00:00:00 2001
From: Ruben Daniels <ruben@c9.io>
Date: Wed, 26 Jun 2013 16:49:48 +0000
Subject: [PATCH 06/12] * Nak should run out of process * Why is findinfiles in
 the Find menu disabled when ace is not opened? * Watchers shouldn't have
 multiple watchers for the same path * Watchers should ignore .c9config

---
 consumer.js | 3 +--
 worker.js   | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/consumer.js b/consumer.js
index c09a761..4dcf5dd 100644
--- a/consumer.js
+++ b/consumer.js
@@ -133,6 +133,7 @@ function Consumer() {
 
     var nextStreamID = 1;
     function storeStream(stream) {
+        nextStreamID = nextStreamID++ % 10000;
         while (streams.hasOwnProperty(nextStreamID)) { nextStreamID++; }
         var id = nextStreamID;
         streams[id] = stream;
@@ -146,13 +147,11 @@ function Consumer() {
             stream.on("end", function (chunk) {
                 delete streams[id];
                 remote.onEnd(id, chunk);
-                nextStreamID = id;
             });
         }
         stream.on("close", function () {
             delete streams[id];
             remote.onClose(id);
-            nextStreamID = id;
         });
         var token = {id: id};
         if (stream.hasOwnProperty("readable")) token.readable = stream.readable;
diff --git a/worker.js b/worker.js
index 8a4895a..9ff1bb3 100644
--- a/worker.js
+++ b/worker.js
@@ -156,6 +156,7 @@ function Worker(vfs) {
 
     var nextStreamID = 1;
     function storeStream(stream) {
+        nextStreamID = nextStreamID++ % 10000;
         while (streams.hasOwnProperty(nextStreamID)) { nextStreamID++; }
         var id = nextStreamID;
         streams[id] = stream;
@@ -169,13 +170,11 @@ function Worker(vfs) {
             stream.on("end", function (chunk) {
                 delete streams[id];
                 remote.onEnd(id, chunk);
-                nextStreamID = id;
             });
         }
         stream.on("close", function () {
             delete streams[id];
             remote.onClose(id);
-            nextStreamID = id;
         });
         var token = {id: id};
         if (stream.hasOwnProperty("readable")) token.readable = stream.readable;

From 9192ac6ddc499cf4e1df33b86b5b7baca52d9ab1 Mon Sep 17 00:00:00 2001
From: Ruben Daniels <ruben@c9.io>
Date: Thu, 27 Jun 2013 08:56:43 +0000
Subject: [PATCH 07/12] * Improved VFS fix * Files now open in changed state?

---
 consumer.js | 2 +-
 worker.js   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/consumer.js b/consumer.js
index 4dcf5dd..2493e24 100644
--- a/consumer.js
+++ b/consumer.js
@@ -134,7 +134,7 @@ function Consumer() {
     var nextStreamID = 1;
     function storeStream(stream) {
         nextStreamID = nextStreamID++ % 10000;
-        while (streams.hasOwnProperty(nextStreamID)) { nextStreamID++; }
+        while (streams.hasOwnProperty(nextStreamID)) { nextStreamID++ % 10000; }
         var id = nextStreamID;
         streams[id] = stream;
         stream.id = id;
diff --git a/worker.js b/worker.js
index 9ff1bb3..0fbe329 100644
--- a/worker.js
+++ b/worker.js
@@ -157,7 +157,7 @@ function Worker(vfs) {
     var nextStreamID = 1;
     function storeStream(stream) {
         nextStreamID = nextStreamID++ % 10000;
-        while (streams.hasOwnProperty(nextStreamID)) { nextStreamID++; }
+        while (streams.hasOwnProperty(nextStreamID)) { nextStreamID++ % 10000; }
         var id = nextStreamID;
         streams[id] = stream;
         stream.id = id;

From f213f3e13b1e2dc8d77af6d931631a4993e6a12e Mon Sep 17 00:00:00 2001
From: Ruben Daniels <ruben@c9.io>
Date: Tue, 2 Jul 2013 11:09:58 +0000
Subject: [PATCH 08/12] Merged from master while working on metadata

---
 consumer.js | 1 +
 worker.js   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/consumer.js b/consumer.js
index 2493e24..f4d129f 100644
--- a/consumer.js
+++ b/consumer.js
@@ -62,6 +62,7 @@ function Consumer() {
         ping: ping, // Send a simple ping request to the worker
         resolve:  route("resolve"),
         stat:     route("stat"),
+        metadata: route("metadata"),
         readfile: route("readfile"),
         readdir:  route("readdir"),
         mkfile:   route("mkfile"),
diff --git a/worker.js b/worker.js
index 0fbe329..b2e62a5 100644
--- a/worker.js
+++ b/worker.js
@@ -50,6 +50,7 @@ function Worker(vfs) {
         // Route other calls to the local vfs instance
         resolve:  route("resolve"),
         stat:     route("stat"),
+        metadata: route("metadata"),
         readfile: route("readfile"),
         readdir:  route("readdir"),
         mkfile:   route("mkfile"),

From a07377293942ef2572c36c43016cb51818d821b0 Mon Sep 17 00:00:00 2001
From: Ruben Daniels <ruben@c9.io>
Date: Wed, 3 Jul 2013 18:29:47 +0000
Subject: [PATCH 09/12] working on vfs improvements

---
 consumer.js | 4 ++--
 worker.js   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/consumer.js b/consumer.js
index f4d129f..fbee748 100644
--- a/consumer.js
+++ b/consumer.js
@@ -309,7 +309,7 @@ function Consumer() {
         if (!stream) return;
         stream.destroy();
         delete streams[id];
-        nextStreamID = id;
+        // nextStreamID = id;
     }
     function pause(id) {
         var stream = streams[id];
@@ -327,7 +327,7 @@ function Consumer() {
         delete streams[id];
         if (chunk) stream.end(chunk);
         else stream.end();
-        nextStreamID = id;
+        // nextStreamID = id;
     }
 
     function on(name, handler, callback) {
diff --git a/worker.js b/worker.js
index b2e62a5..6e3938a 100644
--- a/worker.js
+++ b/worker.js
@@ -293,7 +293,7 @@ function Worker(vfs) {
         if (!stream) return;
         delete streams[id];
         stream.destroy();
-        nextStreamID = id;
+        // nextStreamID = id;
     }
     function end(id, chunk) {
         var stream = streams[id];
@@ -301,7 +301,7 @@ function Worker(vfs) {
         delete streams[id];
         if (chunk) stream.end(chunk);
         else stream.end();
-        nextStreamID = id;
+        // nextStreamID = id;
     }
 
     function kill(pid, code) {

From f4dcedae04a08412832cf0d38278b52705861848 Mon Sep 17 00:00:00 2001
From: Ruben Daniels <ruben@c9.io>
Date: Mon, 8 Jul 2013 09:16:04 +0000
Subject: [PATCH 10/12] Fix for processes not being terminated during
 disconnect

---
 worker.js | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/worker.js b/worker.js
index 6e3938a..3420230 100644
--- a/worker.js
+++ b/worker.js
@@ -112,16 +112,18 @@ function Worker(vfs) {
             err = new Error("EDISCONNECT: vfs socket disconnected");
             err.code = "EDISCONNECT";
         }
-        Object.keys(streams).forEach(function (id) {
-            var stream = streams[id];
-            stream.emit("close", err);
-        });
-        Object.keys(proxyStreams).forEach(onClose);
         Object.keys(processes).forEach(function (pid) {
             var process = processes[pid];
+            console.log("PROCESS", process)
             process.kill();
             delete processes[pid];
         });
+        Object.keys(streams).forEach(function (id) {
+            var stream = streams[id];
+            console.log("STREAM", stream)
+            stream.emit("close", err);
+        });
+        Object.keys(proxyStreams).forEach(onClose);
         Object.keys(watchers).forEach(function (id) {
             var watcher = watchers[id];
             delete watchers[id];

From cf68f34066bb8d16f808d9b7172b7662f235d1ae Mon Sep 17 00:00:00 2001
From: Ruben Daniels <ruben@c9.io>
Date: Mon, 8 Jul 2013 09:16:40 +0000
Subject: [PATCH 11/12] added the fix to consumer as well

---
 consumer.js | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/consumer.js b/consumer.js
index fbee748..58cca19 100644
--- a/consumer.js
+++ b/consumer.js
@@ -105,16 +105,16 @@ function Consumer() {
             err = new Error("EDISCONNECT: vfs socket disconnected");
             err.code = "EDISCONNECT";
         }
-        Object.keys(streams).forEach(function (id) {
-            var stream = streams[id];
-            stream.emit("close");
-        });
-        Object.keys(proxyStreams).forEach(onClose);
         Object.keys(proxyProcesses).forEach(function (pid) {
             var proxyProcess = proxyProcesses[pid];
             delete proxyProcesses[pid];
             proxyProcess.emit("exit", 1);
         });
+        Object.keys(streams).forEach(function (id) {
+            var stream = streams[id];
+            stream.emit("close");
+        });
+        Object.keys(proxyStreams).forEach(onClose);
         Object.keys(proxyWatchers).forEach(function (id) {
             var proxyWatcher = proxyWatchers[id];
             delete proxyWatchers[id];

From e1183d2f073e05f95c060dcb6241ad6a76e46637 Mon Sep 17 00:00:00 2001
From: Ruben Daniels <ruben@c9.io>
Date: Mon, 8 Jul 2013 09:31:23 +0000
Subject: [PATCH 12/12] Removed console.log and commented out code

---
 consumer.js | 2 --
 worker.js   | 4 ----
 2 files changed, 6 deletions(-)

diff --git a/consumer.js b/consumer.js
index 58cca19..fe18be3 100644
--- a/consumer.js
+++ b/consumer.js
@@ -309,7 +309,6 @@ function Consumer() {
         if (!stream) return;
         stream.destroy();
         delete streams[id];
-        // nextStreamID = id;
     }
     function pause(id) {
         var stream = streams[id];
@@ -327,7 +326,6 @@ function Consumer() {
         delete streams[id];
         if (chunk) stream.end(chunk);
         else stream.end();
-        // nextStreamID = id;
     }
 
     function on(name, handler, callback) {
diff --git a/worker.js b/worker.js
index 3420230..c37adb0 100644
--- a/worker.js
+++ b/worker.js
@@ -114,13 +114,11 @@ function Worker(vfs) {
         }
         Object.keys(processes).forEach(function (pid) {
             var process = processes[pid];
-            console.log("PROCESS", process)
             process.kill();
             delete processes[pid];
         });
         Object.keys(streams).forEach(function (id) {
             var stream = streams[id];
-            console.log("STREAM", stream)
             stream.emit("close", err);
         });
         Object.keys(proxyStreams).forEach(onClose);
@@ -295,7 +293,6 @@ function Worker(vfs) {
         if (!stream) return;
         delete streams[id];
         stream.destroy();
-        // nextStreamID = id;
     }
     function end(id, chunk) {
         var stream = streams[id];
@@ -303,7 +300,6 @@ function Worker(vfs) {
         delete streams[id];
         if (chunk) stream.end(chunk);
         else stream.end();
-        // nextStreamID = id;
     }
 
     function kill(pid, code) {