js: Get files from input and send them to mattr.

Change-Id: Idd121f8ac8cf1cbe0dad972d878d44c9aabd9762
diff --git a/js/Makefile b/js/Makefile
index 03ecad2..89375cd 100644
--- a/js/Makefile
+++ b/js/Makefile
@@ -40,12 +40,11 @@
 src/gen-vdl: $(shell find ../go/src/ -name "*.vdl")
 	v23 run vdl generate --lang=javascript --js-out-dir=src/gen-vdl v.io/x/media_sharing
 
-build/bundle.js: src/index.js $(shell find src/ -name "*.js") src/gen-vdl node_modules
-	mkdir -p build
-ifndef NOMINIFY
-	$(call BROWSERIFY,$<,$@)
-else
+build/bundle.js: src/index.js $(shell find src/ -name "*.js") src/gen-vdl lint node_modules
+ifdef MINIFY
 	$(call BROWSERIFY-MIN,$<,$@)
+else
+	$(call BROWSERIFY,$<,$@)
 endif
 
 build/index.html: public/index.html
diff --git a/js/package.json b/js/package.json
index 1f95d9a..2f579a7 100644
--- a/js/package.json
+++ b/js/package.json
@@ -6,7 +6,9 @@
   "main": "src/index.js",
   "license": "ISC",
   "dependencies": {
-    "domready": "~1.0.8"
+    "domready": "~1.0.8",
+    "format": "~0.2.1",
+    "inherits": "~2.0.1"
   },
   "devDependencies": {
     "browserify": "~10.2.0",
diff --git a/js/public/index.html b/js/public/index.html
index 2a0efc7..3dc8ff3 100644
--- a/js/public/index.html
+++ b/js/public/index.html
@@ -5,6 +5,10 @@
 	<script src="bundle.js"></script>
 </head>
 <body>
-	<div id="content"></div>
+	<div id="content">
+		<input type="file" id="file-input">
+		<br>
+		<div id="status"></div>
+	</div>
 </body>
 </html>
diff --git a/js/src/file-emitter.js b/js/src/file-emitter.js
new file mode 100644
index 0000000..b31d522
--- /dev/null
+++ b/js/src/file-emitter.js
@@ -0,0 +1,72 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var EE = require('events').EventEmitter;
+var format = require('format');
+var inherits = require('inherits');
+
+module.exports = FileEmitter;
+
+function FileEmitter(input) {
+  EE.call(this);
+
+  // TODO(nlacasse): Consider making these an argument to FileEmitter;
+  this._allowedTypes = ['audio', 'image', 'video'];
+  this._maxSize = 10 * 1000 * 1000; // 10MB
+
+  input.addEventListener('change', this._onFileChange.bind(this), false);
+}
+
+inherits(FileEmitter, EE);
+
+FileEmitter.prototype._isAllowedType = function(type) {
+  for (var i = 0; i < this._allowedTypes.length; i++) {
+    if (type.indexOf(this._allowedTypes[i]) === 0) {
+      return true;
+    }
+  }
+  return false;
+};
+
+FileEmitter.prototype._onFileChange = function(ev) {
+  var files = ev.target.files;
+  if (files.length === 0) {
+    this.emit('error', 'No files selected.');
+    return;
+  }
+
+  // TODO(nlacasse): Consider handling multiple files?  For now we just take
+  // the first.  Perhaps if multiple files are selected, we send each to a
+  // different media server?
+  var file = files[0];
+
+  if (!this._isAllowedType(file.type)) {
+    this.emit('error', format('Filetype %s is not supported.', file.type));
+    return;
+  }
+
+  // TODO(nlacasse): Consider removing the file size limit.
+  if (file.size > this._maxSize) {
+    this.emit('error', format('File too large.'));
+    return;
+  }
+
+  var reader = new FileReader();
+
+  var self = this;
+  reader.addEventListener('error', function(ev) {
+    self.emit('error', ev);
+  });
+
+  reader.addEventListener('load', function() {
+    self.emit('file', {
+      name: file.name,
+      type: file.type,
+      size: file.size,
+      bytes: new Uint8Array(reader.result)
+    });
+  });
+
+  reader.readAsArrayBuffer(file);
+};
diff --git a/js/src/index.js b/js/src/index.js
index 7571ce0..61c3f44 100644
--- a/js/src/index.js
+++ b/js/src/index.js
@@ -3,7 +3,64 @@
 // license that can be found in the LICENSE file.
 
 var domready = require('domready');
+var format = require('format');
+var vanadium = require('vanadium');
 
-domready(function() {
-  document.querySelector('#content').innerText = 'Hello Vanadium World';
-});
+var FileEmitter = require('./file-emitter');
+
+domready(onDomReady);
+
+// Entry point of the app.
+function onDomReady() {
+  vanadium.init(function(err, rt) {
+    if (err) {
+      appendStatus('ERROR: ' + err);
+      return;
+    }
+
+    // Connect the file input to a FileEmitter.
+    var fileInput = document.getElementById('file-input');
+    var fileEmitter = new FileEmitter(fileInput);
+
+    fileEmitter.on('error', function(text) {
+      appendStatus('ERROR: ' + text);
+    });
+
+    fileEmitter.on('file', function(file) {
+      appendStatus(format('Sending file %s of type %s and %d bytes.',
+                          file.name, file.type, file.size));
+      sendToDisplay(rt, file, function(err) {
+        if (err) {
+          appendStatus('ERROR: ' + err);
+          return;
+        }
+        appendStatus('Success.');
+      });
+    });
+  });
+}
+
+// Append text to the status div.
+function appendStatus(text) {
+  var status = document.getElementById('status');
+  status.innerHTML += text + '<br>';
+}
+
+function sendToDisplay(rt, file, cb) {
+  var ctx = rt.getContext();
+  var client = rt.newClient();
+  client.bindTo(ctx, 'users/mattr@google.com/media', function(err, s) {
+    if (err) {
+      return cb(err);
+    }
+
+    var promise = s.displayBytes(ctx, file.type);
+    promise.catch(cb);
+    promise.stream.on('error', cb);
+    promise.stream.on('finish', function() { cb(null); });
+
+    // TODO(nlacasse): Chunk these bytes! Currently we send the file in one big
+    // chunk.
+    promise.stream.end(file.bytes);
+  });
+}