Permalink
Browse files

first commit

  • Loading branch information...
0 parents commit 96da3b3c133b792292f3c64eeef05bd7a56b3b6d @kriszyp committed Jul 5, 2010
Showing with 1,154 additions and 0 deletions.
  1. +14 −0 README.md
  2. +88 −0 engines/node/lib/jsgi-client.js
  3. +7 −0 engines/rhino/lib/fs.js
  4. +64 −0 engines/rhino/lib/jsgi-client.js
  5. +110 −0 lib/fs.js
  6. +51 −0 lib/jsgi-client.js
  7. +151 −0 lib/lazy-array.js
  8. +94 −0 lib/observe.js
  9. +546 −0 lib/promise.js
  10. +15 −0 lib/sys.js
  11. +14 −0 package.json
@@ -0,0 +1,14 @@
+Promised-IO is a cross-platform package for asynchronous promise-based IO. Promises
+provide a simple robust mechanism asynchronicity with separation of concerns by encapsulating
+eventual completion of an operation with side effect free callback registration
+separate from call invocation. Promised-IO provides cross-platform
+file, HTTP, and system interaction with promises for asynchronous operations.
+
+Promised-IO also utilizes "lazy arrays" for progressively completed
+actions. Lazy arrays provide all the standard iterative Array methods for
+receiving callbacks as actions are completed. Lazy arrays are utilized
+for progressive loading of files and HTTP responses.
+
+Promised-IO is part of the Persevere project, and therefore is licensed under the
+AFL or BSD license. The Persevere project is administered under the Dojo foundation,
+and all contributions require a Dojo CLA.
@@ -0,0 +1,88 @@
+/**
+* HTTP Client using the JSGI standard objects
+*/
+var defer = require("./promise").defer,
+ when = require("./promise").when,
+ LazyArray = require("./lazy-array").LazyArray,
+ http = require("http"),
+ parse = require("url").parse;
+
+// configurable proxy server setting, defaults to http_proxy env var
+exports.proxyServer = require("./system").env.http_proxy;
+
+exports.request = function(request){
+ if(request.url){
+ var parsed = parse(request.url);
+ for(var i in parsed){
+ request[i] = parsed[i];
+ }
+ }
+ var deferred = defer();
+ if(exports.proxyServer){
+ request.pathname = request.url;
+ var proxySettings = parse(exports.proxyServer);
+ request.port = proxySettings.port;
+ request.host = proxySettings.hostname;
+ }
+
+ var client = http.createClient(request.port || 80, request.host);
+
+ var req = client.request(request.method || "GET", request.pathname || request.pathInfo, request.headers || {host: request.hostname});
+ var timedOut;
+ req.addListener("response", function (response){
+ if(timedOut){
+ return;
+ }
+ response.status = response.statusCode;
+ var sendData = function(block){
+ buffer.push(block);
+ };
+ var buffer = [];
+ var bodyDeferred = defer();
+ var body = response.body = LazyArray({
+ some: function(callback){
+ buffer.forEach(callback);
+ sendData = callback;
+ return bodyDeferred.promise;
+ }
+ });
+ if(request.encoding){
+ response.setEncoding(request.encoding);
+ }
+
+ response.addListener("data", function (chunk) {
+ sendData(chunk);
+ });
+ response.addListener("end", function(){
+ bodyDeferred.resolve();
+ });
+ response.addListener("error", function(error){
+ bodyDeferred.reject(error);
+ });
+ deferred.resolve(response);
+ clearTimeout(timeout);
+ });
+ var timeout = setTimeout(function(){
+ timedOut = true;
+ deferred.reject(new Error("Timeout"));
+ }, 20000);
+ req.addListener("error", function(error){
+ deferred.reject(error);
+ });
+ req.addListener("timeout", function(error){
+ deferred.reject(error);
+ });
+ req.addListener("close", function(error){
+ deferred.reject(error);
+ });
+ if(request.body){
+ return when(request.body.forEach(function(block){
+ req.write(block);
+ }), function(){
+ req.end();
+ return deferred.promise;
+ });
+ }
+ req.end();
+ return deferred.promise;
+};
@@ -0,0 +1,7 @@
+var File = require("file");
+exports.readFileSync = exports.read = File.read;
+exports.writeFileSync = exports.write = File.write;
+exports.statSync = File.stat;
+
+exports.makeTree = File.mkdirs;
+exports.makeDirectory = File.mkdir;
@@ -0,0 +1,64 @@
+/**
+* HTTP Client using the JSGI standard objects
+*/
+// configurable proxy server setting, defaults to http_proxy env var
+exports.proxyServer = require("./system").env.http_proxy;
+
+exports.request = function(request){
+ var url = new java.net.URL(request.url),
+ connection = url.openConnection();
+ connection.setDoInput(true);
+ connection.setRequestMethod(request.method);
+
+ for (var header in this.headers) {
+ var value = this.headers[header];
+ connection.addRequestProperty(String(header), String(value));
+ }
+
+ var input = null;
+ try {
+ if (request.body) {
+ connection.setDoOutput(true);
+ var os = connection.getOutputStream();
+ request.body.forEach(function(part){
+ os.write(java.lang.String(part).toBytes("UTF-8"));
+ });
+ os.close();
+ }
+
+ connection.connect();
+ var input = new java.io.InputStreamReader(connection.getInputStream(), "UTF-8");
+ } catch (e) {
+ // HttpUrlConnection will throw FileNotFoundException on 404 errors. FIXME: others?
+ if (e.javaException instanceof java.io.FileNotFoundException)
+ is = connection.getErrorStream();
+ else
+ throw e;
+ }
+
+ var status = Number(connection.getResponseCode());
+ var headers = {};
+ for (var i = 0;; i++) {
+ var key = connection.getHeaderFieldKey(i),
+ value = connection.getHeaderField(i);
+ if (!key && !value)
+ break;
+ // returns the HTTP status code with no key, ignore it.
+ if (key)
+ headers[String(key).toLowerCase()] = String(value);
+ }
+ var body = [];
+ var cbuf = new java.lang["char"](1024);
+ var read = 0;
+ while(read > -1){
+ read = reader.read(cbuf,0,1024);
+ if(read > -1){
+ body.push(new java.lang.String(cbuf));
+ }
+ }
+ return {
+ status: status,
+ headers: headers,
+ body: body
+ };
+};
@@ -0,0 +1,110 @@
+/**
+* Node fs module that returns promises
+*/
+
+var fs = require("fs"),
+ LazyArray = require("./lazy-array").LazyArray,
+ Buffer = require("buffer").Buffer,
+ defer = require("./promise").defer;
+ convertNodeAsyncFunction = require("./promise").convertNodeAsyncFunction;
+
+// convert all the non-sync functions
+for (var i in fs) {
+ if (i.match(/Sync$/) || i.match(/watch/)) {
+ exports[i] = fs[i];
+ }
+ else{
+ exports[i] = convertNodeAsyncFunction(fs[i]);
+ }
+}
+function File(fd){
+ var file = new LazyArray({
+ some: function(callback){
+ var deferred = defer();
+ function readAndSend(){
+ var buffer = new Buffer(4096);
+ fs.read(fd, buffer, 0, 4096, null, function(err, bytesRead){
+ if(err){
+ deferred.reject(err);
+ return;
+ }
+ if (bytesRead === 0){
+ fs.close(fd);
+ deferred.resolve();
+ }
+ else {
+ var result;
+ if(bytesRead < 4096){
+ result = callback(buffer.slice(0, bytesRead));
+ }else{
+ result = callback(buffer);
+ }
+ if(result){
+ deferred.resolve();
+ }else{
+ readAndSend(fd);
+ }
+ }
+ });
+ }
+ readAndSend();
+ return deferred.promise;
+ },
+ length: 0
+ });
+ file.fd = fd;
+ file.write = function(contents){
+
+ }
+ return file;
+}
+File.prototype = LazyArray.prototype;
+
+var nodeRead = exports.read;
+exports.read = function(path, options){
+ if(path instanceof File){
+ arguments[0] = path.fd;
+ return nodeRead.apply(this, arguments);
+ }else{
+ return exports.readFileSync(path, options).toString((options && options.charset) || "utf8");
+ }
+};
+
+var nodeWrite = exports.write;
+exports.write = function(path, contents, options){
+ if(path instanceof File){
+ arguments[0] = path.fd;
+ return nodeWrite.apply(this, arguments);
+ }else{
+ return exports.writeFileSync(path, contents, options);
+ }
+};
+var nodeClose = exports.close;
+exports.close = function(path, contents, options){
+ if(path instanceof File){
+ arguments[0] = path.fd;
+ }
+ return nodeClose.apply(this, arguments);
+};
+
+
+nodeOpen = exports.open;
+exports.open = function(){
+ return nodeOpen.apply(this, arguments).then(File);
+};
+
+exports.makeDirectory = exports.mkdirSync;
+
+exports.makeTree = function(path){
+ var index = path.lastIndexOf('/');
+ if(index === -1){
+ return;
+ }
+ var path = path.substring(0, index);
+ try{
+ fs.statSync(path);
+ }catch(e){
+ exports.makeTree(path);
+ fs.mkdirSync(path, 0777);
+ }
+};
@@ -0,0 +1,51 @@
+/**
+* HTTP Client using the JSGI standard objects
+*/
+var defer = require("promised-io/promise").defer;
+
+exports.request = function(request){
+ var xhr = new XMLHttpRequest();
+ xhr.open(request.method || "GET",
+ request.uri || // allow request.uri to shortcut creating a URL from all the various parts
+ (request.scheme + "://" + request.serverName + ":" + request.serverPort + request.pathInfo + (request.queryString ? '?' + request.queryString : '')), true);
+ for(var i in request.headers){
+ xhr.setRequestHeader(i, request.headers[i]);
+ }
+ var deferred = defer();
+ var response;
+ var lastUpdate;
+ xhr.onreadystatechange = function(){
+ if(xhr.readyState == 4 || xhr.readyState == 3){
+ if(!response){
+ response = {
+ body: [xhr.responseText],
+ status: xhr.status,
+ headers: {}
+ };
+ lastUpdate = xhr.responseText.length;
+ var headers = xhr.getAllResponseHeaders();
+ headers = headers.split(/\n/);
+ for(var i = 0; i < headers.length; i++){
+ var nameValue = headers[i].split(": ", 2);
+ if(nameValue){
+ var name = nameValue[0];
+ response.headers[name.toLowerCase()] = xhr.getResponseHeader(name);
+ }
+ }
+ }
+ else{
+ response.body = [xhr.responseText];
+ lastUpdate = xhr.responseText.length;
+ }
+ if(xhr.readyState == 4){
+ deferred.resolve(response);
+ }
+ else{
+ deferred.progress(response);
+ }
+ }
+ }
+ xhr.send(request.body && request.body.toString());
+ return deferred.promise;
+}
+
Oops, something went wrong.

0 comments on commit 96da3b3

Please sign in to comment.