diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..018eaf3
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,26 @@
+{
+ "node":true,
+ "sub":true,
+ "laxbreak":true,
+ "laxcomma":true,
+ "regexp":true,
+ "asi": true,
+ "browser": true,
+ "loopfunc":true,
+ "expr":true,
+ "es3": true,
+ "esnext": true,
+ "curly": true,
+ "immed": true,
+ "latedef": false,
+ "expr": true,
+ "eqeqeq": false,
+ "eqnull": false,
+ "newcap": true,
+ "noarg": true,
+ "undef": true,
+ "unused": true,
+ "proto": true,
+ "strict": false,
+ "smarttabs": true
+}
diff --git a/LICENSE.md b/LICENSE.md
index 5a1390e..70a0e7b 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2008-2015 http://hprose.com
+Copyright (c) 2008-2018 http://hprose.com
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/README.md b/README.md
index cd2e19a..de20967 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,9 @@
+

+
-
-
-
-
+
+
# Hprose for Node.js
[](https://gitter.im/hprose/hprose-nodejs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -57,6 +56,8 @@ Through *Hprose*, You can conveniently and efficiently intercommunicate between
This project is the implementation of Hprose for Node.js.
+Hprose 2.0 for Node.js Documents(中文版): https://github.com/hprose/hprose-nodejs/wiki
+
## Usage
### Http Server
diff --git a/README_zh_CN.md b/README_zh_CN.md
index 5ba9662..ba57de0 100644
--- a/README_zh_CN.md
+++ b/README_zh_CN.md
@@ -1,10 +1,9 @@
+
+
-
-
-
-
+
+
# Hprose for Node.js
[](https://gitter.im/hprose/hprose-nodejs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -57,6 +56,8 @@
本项目是 Hprose 的 Node.js 语言版本实现。
+更多 Hprose 2.0 for Node.js 文档: https://github.com/hprose/hprose-nodejs/wiki
+
## 使用
### Http 服务器
diff --git a/example/client.js b/example/client.js
index 345bcea..c5cafe8 100644
--- a/example/client.js
+++ b/example/client.js
@@ -27,6 +27,11 @@ for (var i = 0; i < max; i++) {
}
var end = new Date().getTime();
console.log(end - start);
+
+(async function() {
+ console.log(await proxy.hello2("async world"));
+})();
+
client.batch.begin();
proxy.getMaps('name', 'age', 'age', function(result) {
console.log(result);
diff --git a/example/co/awaitexam2.js b/example/co/awaitexam2.js
new file mode 100644
index 0000000..9a4bec8
--- /dev/null
+++ b/example/co/awaitexam2.js
@@ -0,0 +1,14 @@
+(async function() {
+ try {
+ console.log(await Promise.resolve("promise"));
+ console.log(await function *() { return "generator" });
+ console.log(await new Date());
+ console.log(await 123);
+ console.log(await 3.14);
+ console.log(await "hello");
+ console.log(await true);
+ }
+ catch (e) {
+ console.error(e);
+ }
+})();
diff --git a/example/co/awaitexam3.js b/example/co/awaitexam3.js
new file mode 100644
index 0000000..2890d80
--- /dev/null
+++ b/example/co/awaitexam3.js
@@ -0,0 +1,37 @@
+(async function() {
+ try {
+ var a = [];
+ for (i = 0; i < 1000000; i++) {
+ a[i] = i;
+ }
+ var start = Date.now();
+ await a;
+ var end = Date.now();
+ console.log(end - start);
+ }
+ catch (e) {
+ console.error(e);
+ }
+})();
+
+(async function() {
+ try {
+ var a = [];
+ a[0] = a;
+ console.log(await a);
+ }
+ catch (e) {
+ console.error(e);
+ }
+})();
+
+(async function() {
+ try {
+ var o = {};
+ o.self = o;
+ console.log(await o);
+ }
+ catch (e) {
+ console.error(e);
+ }
+})();
diff --git a/example/co/exam1.js b/example/co/exam1.js
new file mode 100644
index 0000000..75dc411
--- /dev/null
+++ b/example/co/exam1.js
@@ -0,0 +1,7 @@
+var hprose = require('hprose');
+
+hprose.co(function*() {
+ var client = hprose.Client.create('http://hprose.com/example/');
+ yield client.useService();
+ console.log(yield client.hello("World"));
+});
diff --git a/example/co/exam10.js b/example/co/exam10.js
new file mode 100644
index 0000000..b0b19fd
--- /dev/null
+++ b/example/co/exam10.js
@@ -0,0 +1,19 @@
+var hprose = require('hprose');
+
+
+var coroutine = hprose.wrap(function*(client) {
+ console.log(1);
+ console.log((yield client.hello("hprose")));
+ var a = client.sum(1, 2, 3);
+ var b = client.sum(4, 5, 6);
+ var c = client.sum(7, 8, 9);
+ console.log((yield client.sum(a, b, c)));
+ console.log((yield client.hello("world")));
+});
+
+hprose.co(function*() {
+ var client = hprose.Client.create('http://hprose.com/example/');
+ yield client.useService();
+ coroutine(client);
+ coroutine(Promise.resolve(client));
+});
diff --git a/example/co/exam11.js b/example/co/exam11.js
new file mode 100644
index 0000000..13021d5
--- /dev/null
+++ b/example/co/exam11.js
@@ -0,0 +1,11 @@
+var hprose = require('hprose');
+
+hprose.co(function*() {
+ var client = hprose.Client.create('http://hprose.com/example/');
+ try {
+ console.log(yield client.invoke('ooxx'));
+ }
+ catch (e) {
+ console.log(e.message);
+ }
+});
\ No newline at end of file
diff --git a/example/co/exam12.js b/example/co/exam12.js
new file mode 100644
index 0000000..5053384
--- /dev/null
+++ b/example/co/exam12.js
@@ -0,0 +1,9 @@
+var hprose = require('hprose');
+
+hprose.co(function*() {
+ var client = hprose.Client.create('http://hprose.com/example/');
+ console.log(yield client.invoke('oo'));
+ console.log(yield client.invoke('xx'));
+}).catch(function(e) {
+ console.log(e.message);
+});
\ No newline at end of file
diff --git a/example/co/exam13.js b/example/co/exam13.js
new file mode 100644
index 0000000..265385c
--- /dev/null
+++ b/example/co/exam13.js
@@ -0,0 +1,7 @@
+var hprose = require('hprose');
+
+hprose.co(function*() {
+ var client = hprose.Client.create('http://hprose.com/example/');
+ console.log(yield client.invoke('oo').complete());
+ console.log(yield client.invoke('xx').complete());
+});
\ No newline at end of file
diff --git a/example/co/exam14.js b/example/co/exam14.js
new file mode 100644
index 0000000..63ad35c
--- /dev/null
+++ b/example/co/exam14.js
@@ -0,0 +1,26 @@
+var hprose = require('hprose');
+
+function sum(a, b, callback) {
+ callback(a + b);
+}
+
+var sum1 = hprose.promisify(sum);
+var sum2 = hprose.thunkify(sum);
+
+sum1(1, 2).then(function(result) {
+ console.log(result);
+});
+
+sum2(2, 3)(function(result) {
+ console.log(result);
+});
+
+hprose.co(function*() {
+ console.log(yield sum1(3, 4));
+ console.log(yield sum2(4, 5));
+});
+
+(async function() {
+ console.log(await sum1(5, 6));
+ console.log(await sum2(6, 7));
+})();
\ No newline at end of file
diff --git a/example/co/exam15.js b/example/co/exam15.js
new file mode 100644
index 0000000..02bd3dc
--- /dev/null
+++ b/example/co/exam15.js
@@ -0,0 +1,27 @@
+var hprose = require('hprose');
+
+function normal(p) {
+ console.log(p);
+ return normal;
+}
+
+function* coroutine(p) {
+ console.log(yield p);
+ return coroutine;
+}
+
+// hprose.co(function*() {
+// var p = Promise.resolve(123);
+// console.log(normal(p));
+// console.log(yield coroutine(p));
+// })
+
+function* run(fn) {
+ var p = Promise.resolve(123);
+ console.log(yield hprose.Future.toPromise(fn(p)));
+}
+
+hprose.co(function*() {
+ yield run(normal);
+ yield run(coroutine);
+});
\ No newline at end of file
diff --git a/example/co/exam2.js b/example/co/exam2.js
new file mode 100644
index 0000000..d3e55ee
--- /dev/null
+++ b/example/co/exam2.js
@@ -0,0 +1,16 @@
+var co = require('hprose').co;
+
+co(function*() {
+ try {
+ console.log(yield Promise.resolve("promise"));
+ console.log(yield function *() { return "generator" });
+ console.log(yield new Date());
+ console.log(yield 123);
+ console.log(yield 3.14);
+ console.log(yield "hello");
+ console.log(yield true);
+ }
+ catch (e) {
+ console.error(e);
+ }
+});
diff --git a/example/co/exam3.js b/example/co/exam3.js
new file mode 100644
index 0000000..2fe398d
--- /dev/null
+++ b/example/co/exam3.js
@@ -0,0 +1,39 @@
+var co = require('hprose').co;
+
+co(function*() {
+ try {
+ var a = [];
+ for (i = 0; i < 1000000; i++) {
+ a[i] = i;
+ }
+ var start = Date.now();
+ yield a;
+ var end = Date.now();
+ console.log(end - start);
+ }
+ catch (e) {
+ console.error(e);
+ }
+});
+
+co(function*() {
+ try {
+ var a = [];
+ a[0] = a;
+ console.log(yield a);
+ }
+ catch (e) {
+ console.error(e);
+ }
+});
+
+co(function*() {
+ try {
+ var o = {};
+ o.self = o;
+ console.log(yield o);
+ }
+ catch (e) {
+ console.error(e);
+ }
+});
diff --git a/example/co/exam4.js b/example/co/exam4.js
new file mode 100644
index 0000000..4e5d434
--- /dev/null
+++ b/example/co/exam4.js
@@ -0,0 +1,16 @@
+var hprose = require("hprose");
+var co = hprose.co;
+var thunkify = hprose.thunkify;
+
+var sum = thunkify(function(a, b, callback) {
+ console.log("call sum(" + Array.prototype.join.call(arguments) + ")");
+ callback(null, a + b);
+ callback(null, a + b + a);
+});
+
+co(function*() {
+ var result = sum(1, 2);
+ console.log(yield result);
+ console.log(yield sum(2, 3));
+ console.log(yield result);
+});
diff --git a/example/co/exam5.js b/example/co/exam5.js
new file mode 100644
index 0000000..349bf4e
--- /dev/null
+++ b/example/co/exam5.js
@@ -0,0 +1,14 @@
+var hprose = require("hprose");
+var co = hprose.co;
+var thunkify = hprose.thunkify;
+
+var sum = thunkify(function(a, b, callback) {
+ callback(a + b);
+});
+
+co(function*() {
+ var result = sum(1, 2);
+ console.log(yield result);
+ console.log(yield sum(2, 3));
+ console.log(yield result);
+});
diff --git a/example/co/exam6.js b/example/co/exam6.js
new file mode 100644
index 0000000..799b3fe
--- /dev/null
+++ b/example/co/exam6.js
@@ -0,0 +1,12 @@
+var hprose = require('hprose');
+
+hprose.co(function*() {
+ var client = hprose.Client.create('http://hprose.com/example/');
+ yield client.useService();
+ console.log(yield client.hello("Hprose"));
+ var a = client.sum(1, 2, 3);
+ var b = client.sum(4, 5, 6);
+ var c = client.sum(7, 8, 9);
+ console.log(yield client.sum(a, b, c));
+ console.log(yield client.hello("World"));
+});
diff --git a/example/co/exam7.js b/example/co/exam7.js
new file mode 100644
index 0000000..440e136
--- /dev/null
+++ b/example/co/exam7.js
@@ -0,0 +1,18 @@
+var hprose = require('hprose');
+
+var client = hprose.Client.create('http://hprose.com/example/');
+var proxy = client.useService();
+
+hprose.co(function*() {
+ var client = yield proxy;
+ for (var i = 0; i < 5; i++) {
+ console.log((yield client.hello("1-" + i)));
+ }
+});
+
+hprose.co(function*() {
+ var client = yield proxy;
+ for (var i = 0; i < 5; i++) {
+ console.log((yield client.hello("2-" + i)));
+ }
+});
diff --git a/example/co/exam8.js b/example/co/exam8.js
new file mode 100644
index 0000000..90fb7cc
--- /dev/null
+++ b/example/co/exam8.js
@@ -0,0 +1,22 @@
+var hprose = require('hprose');
+
+function *hello(n, client) {
+ var result = [];
+ for (var i = 0; i < 5; i++) {
+ result[i] = client.hello(n + "-" + i);
+ }
+ return Promise.all(result);
+}
+
+hprose.co(function*() {
+ var client = hprose.Client.create('http://hprose.com/example/');
+ yield client.useService();
+ var result = yield hprose.co(function *(client) {
+ var result = [];
+ for (var i = 0; i < 3; i++) {
+ result[i] = hprose.co(hello, i, client);
+ }
+ return Promise.all(result);
+ }, client);
+ console.log(result);
+});
diff --git a/example/co/exam9.js b/example/co/exam9.js
new file mode 100644
index 0000000..dfa447e
--- /dev/null
+++ b/example/co/exam9.js
@@ -0,0 +1,16 @@
+var hprose = require('hprose');
+
+hprose.co(function*() {
+ var client = hprose.Client.create('http://hprose.com/example/');
+ yield client.useService();
+ for (var i = 0; i < 5; i++) {
+ console.log(yield client.hello("1-" + i));
+ }
+ var console_log = hprose.wrap(console.log, console);
+ for (var i = 0; i < 5; i++) {
+ console_log(client.hello("2-" + i));
+ }
+ for (var i = 0; i < 5; i++) {
+ console.log(yield client.hello("3-" + i));
+ }
+});
diff --git a/example/httpclient.js b/example/httpclient.js
new file mode 100644
index 0000000..a0e0628
--- /dev/null
+++ b/example/httpclient.js
@@ -0,0 +1,19 @@
+/*jshint node:true, eqeqeq:true */
+'use strict';
+
+var hprose = require('../lib/hprose.js');
+var client = hprose.Client.create('http://127.0.0.1:8080/', []);
+client.simple = true;
+client.on('error', function(func, e) {
+ console.log(func, e);
+});
+hprose.co(function*() {
+ var proxy = client.useService(['hello']);
+ var start = new Date().getTime();
+ for (var i = 0; i < 100; i++) {
+ var result = yield proxy.hello(i);
+ console.log(result);
+ }
+ var end = new Date().getTime();
+ console.log("time: " + (end - start));
+});
diff --git a/example/httpserver.js b/example/httpserver.js
new file mode 100644
index 0000000..6e11757
--- /dev/null
+++ b/example/httpserver.js
@@ -0,0 +1,21 @@
+/*jshint node:true, eqeqeq:true */
+'use strict';
+
+var hprose = require('../lib/hprose.js');
+
+function* hello(name) {
+ return 'Hello ' + name + '!';
+}
+
+var server = hprose.Server.create("http://0.0.0.0:8080/");
+server.crossDomain = true;
+server.crossDomainXmlFile = './crossdomain.xml';
+server.debug = true;
+server.addFunction(hello);
+server.on('sendError', function(message) {
+ console.log(message.stack);
+});
+process.on('SIGINT', function() {
+ server.stop();
+});
+server.start();
diff --git a/example/middleware/batchlog/batchloghandler.js b/example/middleware/batchlog/batchloghandler.js
index d418f06..c2e5764 100644
--- a/example/middleware/batchlog/batchloghandler.js
+++ b/example/middleware/batchlog/batchloghandler.js
@@ -1,6 +1,6 @@
-module.exports = function(batches, context, next) {
+module.exports = function*(batches, context, next) {
console.log("before invoke:", batches);
- var result = next(batches, context);
+ var result = yield next(batches, context);
console.log("after invoke:", batches, result);
return result;
};
diff --git a/example/middleware/batchlog/loghandler.js b/example/middleware/batchlog/loghandler.js
index 24b6cab..02f301f 100644
--- a/example/middleware/batchlog/loghandler.js
+++ b/example/middleware/batchlog/loghandler.js
@@ -1,6 +1,6 @@
-module.exports = function(name, args, context, next) {
+module.exports = function*(name, args, context, next) {
console.log("before invoke:", name, args);
- var result = next(name, args, context);
+ var result = yield next(name, args, context);
console.log("after invoke:", name, args, result);
return result;
};
diff --git a/example/middleware/cache/loghandler.js b/example/middleware/cache/loghandler.js
index 24b6cab..02f301f 100644
--- a/example/middleware/cache/loghandler.js
+++ b/example/middleware/cache/loghandler.js
@@ -1,6 +1,6 @@
-module.exports = function(name, args, context, next) {
+module.exports = function*(name, args, context, next) {
console.log("before invoke:", name, args);
- var result = next(name, args, context);
+ var result = yield next(name, args, context);
console.log("after invoke:", name, args, result);
return result;
};
diff --git a/example/middleware/compressCache/server.js b/example/middleware/compressCache/server.js
index 5ce4454..a58028e 100644
--- a/example/middleware/compressCache/server.js
+++ b/example/middleware/compressCache/server.js
@@ -7,9 +7,9 @@ function echo(value) {
}
var server = hprose.Server.create("http://0.0.0.0:8080/");
server.beforeFilter.use(stathandler('BeforeFilter'))
- .use(sizehandler('Non compressed'));
+ .use(sizehandler('compressed'));
server.addFilter(new CompressFilter('Lzp3'));
server.afterFilter.use(stathandler('AfterFilter'))
- .use(sizehandler('compressed'));
+ .use(sizehandler('Non compressed'));
server.add(echo);
server.start();
diff --git a/example/middleware/compressCache/sizehandler.js b/example/middleware/compressCache/sizehandler.js
index d9e4da6..4c6e419 100644
--- a/example/middleware/compressCache/sizehandler.js
+++ b/example/middleware/compressCache/sizehandler.js
@@ -1,16 +1,9 @@
var hprose = require('hprose');
module.exports = function(message) {
- return function(request, context, next) {
+ return function*(request, context, next) {
console.log(message + ' request size: ' + request.length);
- var response = next(request, context);
- if (hprose.Future.isPromise(response)) {
- response.then(function(data) {
- console.log(message + ' response size: ' + data.length);
- });
- }
- else {
- console.log(message + ' response size: ' + response.length);
- }
+ var response = yield next(request, context);
+ console.log(message + ' response size: ' + response.length);
return response;
};
};
diff --git a/example/middleware/compressCache/stathandler.js b/example/middleware/compressCache/stathandler.js
index d8c8d65..ac84f64 100644
--- a/example/middleware/compressCache/stathandler.js
+++ b/example/middleware/compressCache/stathandler.js
@@ -1,17 +1,9 @@
module.exports = function(message) {
- return function(request, context, next) {
+ return function*(request, context, next) {
var start = Date.now();
- function showstat() {
- var end = Date.now();
- console.log(message + ': It takes ' + (end - start) + ' ms.');
- }
- var response = next(request, context);
- if (hprose.Future.isPromise(response)) {
- response.then(showstat);
- }
- else {
- showstat();
- }
+ var response = yield next(request, context);
+ var end = Date.now();
+ console.log(message + ': It takes ' + (end - start) + ' ms.');
return response;
};
};
diff --git a/example/middleware/log/loghandler.js b/example/middleware/log/loghandler.js
index 24b6cab..d637f41 100644
--- a/example/middleware/log/loghandler.js
+++ b/example/middleware/log/loghandler.js
@@ -1,6 +1,16 @@
+/*
module.exports = function(name, args, context, next) {
console.log("before invoke:", name, args);
var result = next(name, args, context);
+ result.then(function(result) {
+ console.log("after invoke:", name, args, result);
+ });
+ return result;
+};
+*/
+module.exports = function*(name, args, context, next) {
+ console.log("before invoke:", name, args);
+ var result = yield next(name, args, context);
console.log("after invoke:", name, args, result);
return result;
};
diff --git a/example/middleware/log2/loghandler.js b/example/middleware/log2/loghandler.js
index da05a2e..d182824 100644
--- a/example/middleware/log2/loghandler.js
+++ b/example/middleware/log2/loghandler.js
@@ -1,14 +1,7 @@
var hprose = require('hprose');
-module.exports = function(request, context, next) {
+module.exports = function*(request, context, next) {
console.log(hprose.BytesIO.toString(request));
- var response = next(request, context);
- if (hprose.Future.isPromise(response)) {
- response.then(function(data) {
- console.log(hprose.BytesIO.toString(data));
- });
- }
- else {
- console.log(hprose.BytesIO.toString(response));
- }
+ var response = yield next(request, context);
+ console.log(hprose.BytesIO.toString(response));
return response;
};
diff --git a/example/proxyclient.js b/example/proxyclient.js
index 5140f69..66770c7 100644
--- a/example/proxyclient.js
+++ b/example/proxyclient.js
@@ -2,11 +2,33 @@
'use strict';
var hprose = require('hprose');
-var client = hprose.Client.create('tcp://127.0.0.1:1234/', ['hello']);
+var client = hprose.Client.create('tcp://127.0.0.1:1234/', []);
client.fullDuplex = true;
client.maxPoolSize = 1;
-client.hello("World", function(result) {
+var proxy = client.useService();
+
+proxy.hello("World", function(result) {
console.log(result);
}, function(name, error) {
console.error(error);
});
+
+var weeks = {
+ 'Monday': 'Mon',
+ 'Tuesday': 'Tue',
+ 'Wednesday': 'Wed',
+ 'Thursday': 'Thu',
+ 'Friday': 'Fri',
+ 'Saturday': 'Sat',
+ 'Sunday': 'Sun',
+};
+
+proxy.swapKeyAndValue.onsuccess = function(result, args) {
+ console.log(weeks.constructor, weeks);
+ console.log(result.constructor, result);
+ console.log(args.constructor, args);
+};
+
+proxy.swapKeyAndValue.byref = true;
+
+proxy.swapKeyAndValue(weeks);
\ No newline at end of file
diff --git a/example/serialize.js b/example/serialize.js
index accce65..e9d6b3f 100644
--- a/example/serialize.js
+++ b/example/serialize.js
@@ -12,9 +12,9 @@ console.log(hprose.unserialize(hprose.serialize(12345678909876)));
console.log(hprose.unserialize(hprose.serialize(Math.PI)));
console.log(hprose.unserialize(hprose.serialize(new Date())));
console.log(hprose.serialize("Hello World!").toString());
-console.log(hprose.serialize("你好中国!").toString());
+console.log(hprose.serialize("你好中国!🇨🇳").toString());
console.log(hprose.unserialize(hprose.serialize("Hello World!")));
-console.log(hprose.unserialize(hprose.serialize("你好中国!")));
+console.log(hprose.unserialize(hprose.serialize("你好中国!🇨🇳")));
console.log(hprose.unserialize(hprose.serialize(new Buffer("你好"))).toString());
console.log(hprose.unserialize(new Buffer("l1234567890987654321234567890;")));
console.log(hprose.unserialize(hprose.serialize(NaN)));
diff --git a/example/server.js b/example/server.js
index f34ff0d..177badb 100644
--- a/example/server.js
+++ b/example/server.js
@@ -9,8 +9,8 @@ function hello(name, context) {
return 'Hello ' + name + '! -- ' + context.socket.remoteAddress;
}
-function hello2(name) {
- return 'Hello ' + name + '!';
+async function hello2(name) {
+ return await 'Hello ' + name + '!';
}
function asyncHello(name, callback) {
diff --git a/example/tcpclient4.js b/example/tcpclient4.js
new file mode 100644
index 0000000..fa61533
--- /dev/null
+++ b/example/tcpclient4.js
@@ -0,0 +1,41 @@
+/*jshint node:true, eqeqeq:true */
+'use strict';
+
+var hprose = require('../lib/hprose.js');
+var client = hprose.Client.create('tcp://127.0.0.1:4321/', ['hello']);
+client.fullDuplex = true;
+client.maxPoolSize = 1;
+var log = hprose.Future.wrap(console.log, console);
+log(client.hello("async world1"));
+log(client.hello("async world2"));
+log(client.hello("async world3"));
+log(client.hello("async world4"));
+log(client.hello("async world5"));
+log(client.hello("async world6"));
+
+// 串行异步
+client.hello("world1")
+.then(function(result) {
+ console.log(result);
+ return client.hello("world2");
+})
+.then(function(result) {
+ console.log(result);
+ return client.hello("world3");
+})
+.then(function(result) {
+ console.log(result);
+ return client.hello("world4");
+})
+.then(function(result) {
+ console.log(result);
+ return client.hello("world5");
+})
+.then(function(result) {
+ console.log(result);
+ return client.hello("world6");
+})
+.then(function(result) {
+ console.log(result);
+ client.close();
+});
diff --git a/example/tcpserver.js b/example/tcpserver.js
index aeeff31..f029378 100644
--- a/example/tcpserver.js
+++ b/example/tcpserver.js
@@ -10,7 +10,7 @@ function hello(name, context) {
}
function hello2(name) {
- return 'Hello ' + name + '!';
+ return name;
}
function asyncHello(name, callback) {
@@ -29,11 +29,21 @@ function getMaps() {
function LogFilter() {
this.inputFilter = function(value) {
- console.log(hprose.BytesIO.toString(value));
+ try {
+ console.log(hprose.BytesIO.toString(value));
+ }
+ catch(e) {
+ console.log(hprose.toBinaryString(value));
+ }
return value;
};
this.outputFilter = function(value) {
- console.log(hprose.BytesIO.toString(value));
+ try {
+ console.log(hprose.BytesIO.toString(value));
+ }
+ catch(e) {
+ console.log(hprose.toBinaryString(value));
+ }
return value;
};
}
diff --git a/example/testco.js b/example/testco.js
new file mode 100644
index 0000000..e0623cb
--- /dev/null
+++ b/example/testco.js
@@ -0,0 +1,24 @@
+var co = require('../lib/hprose.js').co;
+
+function* sleep() {
+ return new Promise(function(resolve) {
+ setTimeout(resolve, 1);
+ });
+};
+
+co(function*() {
+
+ for(var i = 0; true; ++i) {
+ yield sleep();
+
+ if (i % 10000 === 0) {
+ console.log(process.memoryUsage());
+ }
+
+ }
+
+}).then(function() {
+ console.log('finished')
+}, function(err) {
+ console.log('caught error: ', err.stack);
+});
\ No newline at end of file
diff --git a/example/testthunkify.js b/example/testthunkify.js
new file mode 100644
index 0000000..43d63ee
--- /dev/null
+++ b/example/testthunkify.js
@@ -0,0 +1,14 @@
+var thunkify = require('../lib/hprose.js').thunkify;
+
+var delay = thunkify(function (time, callback) {
+ setTimeout(callback, time);
+});
+
+var result = delay(100);
+setTimeout(function () {
+ console.log('a');
+ result(function () {
+ console.log('c');
+ });
+ console.log('b');
+}, 500);
\ No newline at end of file
diff --git a/example/timeclient.js b/example/timeclient.js
index 85dd394..75f98ef 100644
--- a/example/timeclient.js
+++ b/example/timeclient.js
@@ -1,8 +1,8 @@
/*jshint node:true, eqeqeq:true */
'use strict';
-var hprose = require('hprose');
-var client = hprose.Client.create("http://0.0.0.0:8080/");
+var hprose = require('../lib/hprose');
+var client = hprose.Client.create("http://127.0.0.1:8080/");
var count = 0;
client.subscribe('time', function(date) {
if (++count > 10) {
diff --git a/example/timeoutclient.js b/example/timeoutclient.js
new file mode 100644
index 0000000..4e905da
--- /dev/null
+++ b/example/timeoutclient.js
@@ -0,0 +1,17 @@
+/*jshint node:true, eqeqeq:true */
+'use strict';
+
+var hprose = require('../lib/hprose.js');
+var client = hprose.Client.create('tcp://127.0.0.1:4321/', ['sum']);
+// client.fullDuplex = false;
+client.keepAlive = false;
+client.timeout = 600;
+
+client.sum(1, 2);
+client.sum(1, 2).then(function(result) {
+ console.log("1 + 2 = " + result);
+}).catch(function() {
+ client.sum(2, 3, function(result) {
+ console.log("2 + 3 = " + result);
+ }, { timeout: 20000 });
+})
\ No newline at end of file
diff --git a/example/timeoutserver.js b/example/timeoutserver.js
new file mode 100644
index 0000000..a32ba96
--- /dev/null
+++ b/example/timeoutserver.js
@@ -0,0 +1,19 @@
+/*jshint node:true, eqeqeq:true */
+'use strict';
+
+var hprose = require('../lib/hprose.js');
+
+function sum(a, b) {
+ var promise = new hprose.Future();
+ setTimeout(function() {
+ promise.resolve(a + b);
+ }, 1000);
+ return promise;
+}
+
+var server = hprose.Server.create("tcp://0.0.0.0:4321");
+server.addFunction(sum);
+process.on('SIGINT', function() {
+ server.stop();
+});
+server.start();
diff --git a/example/timeserver.js b/example/timeserver.js
index c8d49f0..b24264b 100644
--- a/example/timeserver.js
+++ b/example/timeserver.js
@@ -1,13 +1,30 @@
/*jshint node:true, eqeqeq:true */
'use strict';
-var hprose = require('hprose');
+var hprose = require('../lib/hprose');
var server = hprose.Server.create("http://0.0.0.0:8080/");
server.publish('time');
+
+function ClientListFilter() {
+ this.inputFilter = function(value) {
+ return value;
+ };
+ this.outputFilter = function(value, context) {
+ console.log(context.clients.idlist('time'));
+ return value;
+ };
+}
+
+server.filter = new ClientListFilter();
+
setInterval(function() {
server.push('time', new Date());
}, 1000);
+
process.on('SIGINT', function() {
- server.stop();
+ console.log("server is stoping!");
+ server.stop();
+ process.exit();
});
+
server.start();
diff --git a/example/ws_client.js b/example/ws_client.js
new file mode 100644
index 0000000..d6950e0
--- /dev/null
+++ b/example/ws_client.js
@@ -0,0 +1,49 @@
+/*jshint node:true, eqeqeq:true */
+'use strict';
+
+var hprose = require('../lib/hprose.js');
+var client = hprose.Client.create('ws://127.0.0.1:8080', []);
+client.keepAlive = false;
+client.simple = true;
+var var_dump = hprose.Future.wrap(console.log, console);
+var proxy = client.useService(['hello']);
+
+var_dump(proxy.hello('async world1'));
+var_dump(proxy.hello('async world2'));
+var_dump(proxy.hello('async world3'));
+var_dump(proxy.hello('async world4'));
+var_dump(proxy.hello('async world5'));
+var_dump(proxy.hello('async world6'));
+
+proxy.hello("world1")
+.then(function(result) {
+ console.log(result);
+ return proxy.hello("world2");
+})
+.then(function(result) {
+ console.log(result);
+ return proxy.hello("world3");
+})
+.then(function(result) {
+ console.log(result);
+ return proxy.hello("world4");
+})
+.then(function(result) {
+ console.log(result);
+ return proxy.hello("world5");
+})
+.then(function(result) {
+ console.log(result);
+ return proxy.hello("world6");
+})
+.then(function(result) {
+ console.log(result);
+});
+
+var_dump(proxy.hello('async world1'));
+var_dump(proxy.hello('async world2'));
+var_dump(proxy.hello('async world3'));
+var_dump(proxy.hello('async world4'));
+var_dump(proxy.hello('async world5'));
+var_dump(proxy.hello('async world6'));
+
diff --git a/lib/client/Client.js b/lib/client/Client.js
index 4902f7d..0a89255 100644
--- a/lib/client/Client.js
+++ b/lib/client/Client.js
@@ -6,27 +6,24 @@
| http://www.hprose.org/ |
| |
\**********************************************************/
-
/**********************************************************\
* *
* hprose/client/Client.js *
* *
* HproseClient for Node.js. *
* *
- * LastModified: Aug 18, 2015 *
+ * LastModified: Feb 6, 2018 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
-/*global Proxy */
+/* global Proxy */
'use strict';
var util = require('util');
var parse = require('url').parse;
var EventEmitter = require('events').EventEmitter;
-var setImmediate = global.setImmediate;
var Tags = global.hprose.Tags;
var ResultMode = global.hprose.ResultMode;
var BytesIO = global.hprose.BytesIO;
@@ -34,6 +31,7 @@ var Writer = global.hprose.Writer;
var Reader = global.hprose.Reader;
var Future = global.hprose.Future;
var slice = Function.prototype.call.bind(Array.prototype.slice);
+var isObjectEmpty = global.hprose.isObjectEmpty;
var GETFUNCTIONS = new Uint8Array(1);
GETFUNCTIONS[0] = Tags.TagEnd;
@@ -45,24 +43,56 @@ var s_string = 'string';
var s_number = 'number';
var s_function = 'function';
var s_object = 'object';
-var s_undefined = 'undefined';
-function HproseProxy(setFunction, ns) {
+function HproseOldProxy(setFunction, ns) {
+ var settings = {};
+ var target = {};
this.get = function(proxy, name) {
- if (ns) name = ns + '_' + name;
- return Proxy.createFunction(
- new HproseProxy(setFunction, name),
- setFunction(this, name)
- );
+ if (ns) { name = ns + '_' + name; }
+ if (name === 'then') { return undefined; }
+ if (!proxy.hasOwnProperty(name)) {
+ settings[name] = {};
+ var handler = new HproseOldProxy(setFunction, name);
+ handler.set = function(proxy, prop, value) {
+ settings[name][prop] = value;
+ return true;
+ };
+ target[name] = Proxy.createFunction(handler, setFunction(settings, name));
+ }
+ return target[name];
+ };
+}
+
+function HproseProxy(setFunction, ns) {
+ var settings = {};
+ this.get = function(target, prop, receiver) {
+ var name = prop.toString();
+ if (ns) { name = ns + '_' + name; }
+ if (name === 'then') { return undefined; }
+ if (!target.hasOwnProperty(name)) {
+ settings[name] = {};
+ var handler = new HproseProxy(setFunction, name);
+ var func = setFunction(settings, name);
+ handler.apply = function(target, thisArg, argumentsList) {
+ return func.apply(null, argumentsList);
+ }
+ handler.set = function(target, prop, value, receiver) {
+ settings[name][prop] = value;
+ return true;
+ };
+ target[name] = new Proxy(function() {}, handler);
+ }
+ return target[name];
};
}
function Client(uri, functions, settings) {
EventEmitter.call(this);
+ this.on('error', noop);
// private members
var _uri,
- _uris = [],
+ _uriList = [],
_index = -1,
_byref = false,
_simple = false,
@@ -70,10 +100,12 @@ function Client(uri, functions, settings) {
_retry = 10,
_idempotent = false,
_failswitch = false,
+ _failround = 0,
_lock = false,
_tasks = [],
_useHarmonyMap = false,
_onerror = noop,
+ _onfailswitch = noop,
_filters = [],
_batch = false,
_batches = [],
@@ -111,46 +143,92 @@ function Client(uri, functions, settings) {
request = outputFilter(request, context);
return _afterFilterHandler(request, context)
.then(function(response) {
- if (context.oneway) return;
+ if (context.oneway) { return; }
return inputFilter(response, context);
});
}
function afterFilterHandler(request, context) {
- return self.sendAndReceive(request, context);
+ return self.sendAndReceive(request, context).catchError(function(e) {
+ var response = retry(request, context);
+ if (response !== null) {
+ return response;
+ }
+ throw e;
+ });
}
function sendAndReceive(request, context, onsuccess, onerror) {
- _beforeFilterHandler(request, context)
- .then(onsuccess, function(e) {
- if (retry(request, context, onsuccess, onerror)) return;
- onerror(e);
- });
+ _beforeFilterHandler(request, context).then(onsuccess, onerror);
+ }
+
+ function failswitch() {
+ var n = _uriList.length;
+ if (n > 1) {
+ var i = _index + 1;
+ if (i >= n) {
+ i = 0;
+ _failround++;
+ }
+ _index = i;
+ _uri = _uriList[_index];
+ }
+ else {
+ _failround++;
+ }
+ _onfailswitch(self);
+ self.emit('failswitch', self);
}
- function retry(data, context, onsuccess, onerror) {
+ function retry(data, context) {
if (context.failswitch) {
- if (++_index >= _uris.length) {
- _index = 0;
- _uri = _uris[_index];
+ failswitch();
+ }
+ if (context.idempotent && (context.retried < context.retry)) {
+ var interval = ++context.retried * 500;
+ if (context.failswitch) {
+ interval -= (_uriList.length - 1) * 500;
+ }
+ if (interval > 5000) {
+ interval = 5000;
+ }
+ if (interval > 0) {
+ return Future.delayed(interval, function() {
+ return afterFilterHandler(data, context);
+ });
+ }
+ else {
+ return afterFilterHandler(data, context);
}
}
- if (context.idempotent) {
- if (--context.retry >= 0) {
- var interval = (10 - context.retry) * 500;
- if (context.retry > 10) interval = 500;
- global.setTimeout(function() {
- sendAndReceive(data, context, onsuccess, onerror);
- }, interval);
- return true;
+ return null;
+ }
+
+ function normalizeFunctions(functions) {
+ var root = [Object.create(null)];
+ for (var i in functions) {
+ var func = functions[i].split('_');
+ var n = func.length - 1;
+ if (n > 0) {
+ var node = root;
+ for (var j = 0; j < n; j++) {
+ var f = func[j];
+ if (node[0][f] === undefined) {
+ node[0][f] = [Object.create(null)];
+ }
+ node = node[0][f];
+ }
+ node.push(func[n]);
}
+ root.push(functions[i]);
}
- return false;
+ return root;
}
function initService(stub) {
var context = {
retry: _retry,
+ retried: 0,
idempotent: true,
failswitch: true,
timeout: _timeout,
@@ -168,7 +246,7 @@ function Client(uri, functions, settings) {
error = new Error(reader.readString());
break;
case Tags.TagFunctions:
- var functions = reader.readList();
+ var functions = normalizeFunctions(reader.readList());
reader.checkTag(Tags.TagEnd);
setFunctions(stub, functions);
break;
@@ -204,12 +282,12 @@ function Client(uri, functions, settings) {
}
function setMethods(stub, obj, namespace, name, methods) {
- if (obj[name] !== undefined) return;
+ if (obj[name] !== undefined) { return; }
obj[name] = {};
if (typeof(methods) === s_string || methods.constructor === Object) {
methods = [methods];
}
- if (util.isArray(methods)) {
+ if (Array.isArray(methods)) {
for (var i = 0; i < methods.length; i++) {
var m = methods[i];
if (typeof(m) === s_string) {
@@ -217,7 +295,7 @@ function Client(uri, functions, settings) {
}
else {
for (var n in m) {
- setMethods(stub, obj[name], name + '_', n, m[n]);
+ setMethods(stub, obj[name], namespace + name + '_', n, m[n]);
}
}
}
@@ -242,7 +320,7 @@ function Client(uri, functions, settings) {
function copyargs(src, dest) {
var n = Math.min(src.length, dest.length);
- for (var i = 0; i < n; ++i) dest[i] = src[i];
+ for (var i = 0; i < n; ++i) { dest[i] = src[i]; }
}
function initContext(batch) {
@@ -264,6 +342,7 @@ function Client(uri, functions, settings) {
simple: _simple,
timeout: _timeout,
retry: _retry,
+ retried: 0,
idempotent: _idempotent,
failswitch: _failswitch,
oneway: false,
@@ -288,9 +367,9 @@ function Client(uri, functions, settings) {
}
var i = 0, n = args.length;
for (; i < n; ++i) {
- if (typeof args[i] === s_function) break;
+ if (typeof args[i] === s_function) { break; }
}
- if (i === n) return context;
+ if (i === n) { return context; }
var extra = args.splice(i, n - i);
context.onsuccess = extra[0];
n = extra.length;
@@ -432,7 +511,7 @@ function Client(uri, functions, settings) {
return function() {
if (sync) {
_lock = false;
- setImmediate(function(tasks) {
+ process.nextTick(function(tasks) {
tasks.forEach(function(task) {
if ('settings' in task) {
endBatch(task.settings)
@@ -449,7 +528,7 @@ function Client(uri, functions, settings) {
}
function call(name, args, context) {
- if (context.sync) _lock = true;
+ if (context.sync) { _lock = true; }
var promise = Future.promise(function(resolve, reject) {
_invokeHandler(name, args, context).then(function(result) {
try {
@@ -493,6 +572,7 @@ function Client(uri, functions, settings) {
var context = {
timeout: _timeout,
retry: _retry,
+ retried: 0,
idempotent: _idempotent,
failswitch: _failswitch,
oneway: false,
@@ -615,9 +695,9 @@ function Client(uri, functions, settings) {
});
}
var batchSize = _batches.length;
- if (batchSize === 0) return;
+ if (batchSize === 0) { return Future.value([]); }
var context = getBatchContext(settings);
- if (context.sync) _lock = true;
+ if (context.sync) { _lock = true; }
var batches = _batches;
_batches = [];
var promise = Future.promise(function(resolve, reject) {
@@ -672,15 +752,43 @@ function Client(uri, functions, settings) {
_onerror = value;
}
}
+ function getOnFailswitch() {
+ return _onfailswitch;
+ }
+ function setOnFailswitch(value) {
+ if (typeof(value) === s_function) {
+ _onfailswitch = value;
+ }
+ }
function getUri() {
return _uri;
}
+ function getUriList() {
+ return _uriList;
+ }
+ function setUriList(uriList) {
+ if (typeof(uriList) === s_string) {
+ _uriList = [uriList];
+ }
+ else if (Array.isArray(uriList)) {
+ _uriList = uriList.slice(0);
+ _uriList.sort(function() { return Math.random() - 0.5; });
+ }
+ else {
+ return;
+ }
+ _index = 0;
+ _uri = _uriList[_index];
+ }
function getFailswitch() {
return _failswitch;
}
function setFailswitch(value) {
_failswitch = !!value;
}
+ function getFailround() {
+ return _failround;
+ }
function getTimeout() {
return _timeout;
}
@@ -779,6 +887,9 @@ function Client(uri, functions, settings) {
_filters.splice(i, 1);
return true;
}
+ function filters() {
+ return _filters;
+ }
function useService(uri, functions, create) {
if (create === undefined) {
if (typeof(functions) === s_boolean) {
@@ -791,7 +902,7 @@ function Client(uri, functions, settings) {
uri = false;
}
else if (uri && uri.constructor === Object ||
- util.isArray(uri)) {
+ Array.isArray(uri)) {
functions = uri;
uri = false;
}
@@ -811,15 +922,20 @@ function Client(uri, functions, settings) {
(functions && functions.constructor === Object)) {
functions = [functions];
}
- if (util.isArray(functions)) {
+ if (Array.isArray(functions)) {
setFunctions(stub, functions);
}
else {
if (typeof(Proxy) === 'undefined') {
- setImmediate(initService, stub);
+ process.nextTick(initService, stub);
return _ready;
}
- stub = Proxy.create(new HproseProxy(setFunction));
+ if ('create' in Proxy) {
+ stub = Proxy.create(new HproseOldProxy(setFunction));
+ }
+ else {
+ stub = new Proxy({}, new HproseProxy(setFunction));
+ }
}
_ready.resolve(stub);
return stub;
@@ -829,9 +945,9 @@ function Client(uri, functions, settings) {
if ((argc < 1) || (typeof name !== s_string)) {
throw new Error('name must be a string');
}
- if (argc === 1) args = [];
+ if (argc === 1) { args = []; }
if (argc === 2) {
- if (!util.isArray(args)) {
+ if (!Array.isArray(args)) {
var _args = [];
if (typeof args !== s_function) {
_args.push(noop);
@@ -853,22 +969,18 @@ function Client(uri, functions, settings) {
function ready(onComplete, onError) {
return _ready.then(onComplete, onError);
}
- function getTopic(name, id, create) {
+ function getTopic(name, id) {
if (_topics[name]) {
var topics = _topics[name];
if (topics[id]) {
return topics[id];
}
- return null;
- }
- if (create) {
- _topics[name] = Object.create(null);
}
return null;
}
- // subscribe(name, callback, timeout)
- // subscribe(name, id, callback, timeout)
- function subscribe(name, id, callback, timeout) {
+ // subscribe(name, callback, timeout, failswitch)
+ // subscribe(name, id, callback, timeout, failswitch)
+ function subscribe(name, id, callback, timeout, failswitch) {
if (typeof name !== s_string) {
throw new TypeError('topic name must be a string.');
}
@@ -880,14 +992,14 @@ function Client(uri, functions, settings) {
throw new TypeError('callback must be a function.');
}
}
+ if (!_topics[name]) {
+ _topics[name] = Object.create(null);
+ }
if (typeof id === s_function) {
timeout = callback;
callback = id;
- if (_id === null) {
- _id = autoId();
- }
- _id.then(function(id) {
- subscribe(name, id, callback, timeout);
+ autoId().then(function(id) {
+ subscribe(name, id, callback, timeout, failswitch);
});
return;
}
@@ -896,23 +1008,24 @@ function Client(uri, functions, settings) {
}
if (Future.isPromise(id)) {
id.then(function(id) {
- subscribe(name, id, callback, timeout);
+ subscribe(name, id, callback, timeout, failswitch);
});
return;
}
- if (timeout === undefined) timeout = _timeout;
- var topic = getTopic(name, id, true);
+ // Default subscribe timeout is 5 minutes.
+ if (timeout === undefined) { timeout = 300000; }
+ var topic = getTopic(name, id);
if (topic === null) {
var cb = function() {
_invoke(self, name, [id, topic.handler, cb, {
idempotent: true,
- failswitch: false,
+ failswitch: failswitch,
timeout: timeout
}], false);
};
topic = {
handler: function(result) {
- var topic = getTopic(name, id, false);
+ var topic = getTopic(name, id);
if (topic) {
if (result !== null) {
var callbacks = topic.callbacks;
@@ -923,7 +1036,7 @@ function Client(uri, functions, settings) {
catch (e) {}
}
}
- if (getTopic(name, id, false) !== null) cb();
+ if (getTopic(name, id) !== null) { cb(); }
}
},
callbacks: [callback]
@@ -1000,12 +1113,28 @@ function Client(uri, functions, settings) {
else {
delTopic(_topics[name], id, callback);
}
+ if (isObjectEmpty(_topics[name])) {
+ delete _topics[name];
+ }
+ }
+ function isSubscribed(name) {
+ return !!_topics[name];
+ }
+ function subscribedList() {
+ var list = [];
+ for (var name in _topics) {
+ list.push(name);
+ }
+ return list;
}
function getId() {
return _id;
}
function autoId() {
- return _invoke(self, '#', [], false);
+ if (_id === null) {
+ _id = _invoke(self, '#', [], false);
+ }
+ return _id;
}
autoId.sync = true;
autoId.idempotent = true;
@@ -1015,14 +1144,7 @@ function Client(uri, functions, settings) {
_invokeHandler = _invokeHandlers.reduceRight(
function(next, handler) {
return function(name, args, context) {
- try {
- var result = handler(name, args, context, next);
- if (Future.isFuture(result)) return result;
- return Future.value(result);
- }
- catch (e) {
- return Future.error(e);
- }
+ return Future.toPromise(handler(name, args, context, next));
};
}, invokeHandler);
}
@@ -1031,14 +1153,7 @@ function Client(uri, functions, settings) {
_batchInvokeHandler = _batchInvokeHandlers.reduceRight(
function(next, handler) {
return function(batches, context) {
- try {
- var result = handler(batches, context, next);
- if (Future.isFuture(result)) return result;
- return Future.value(result);
- }
- catch (e) {
- return Future.error(e);
- }
+ return Future.toPromise(handler(batches, context, next));
};
}, batchInvokeHandler);
}
@@ -1047,14 +1162,7 @@ function Client(uri, functions, settings) {
_beforeFilterHandler = _beforeFilterHandlers.reduceRight(
function(next, handler) {
return function(request, context) {
- try {
- var response = handler(request, context, next);
- if (Future.isFuture(response)) return response;
- return Future.value(response);
- }
- catch (e) {
- return Future.error(e);
- }
+ return Future.toPromise(handler(request, context, next));
};
}, beforeFilterHandler);
}
@@ -1063,14 +1171,7 @@ function Client(uri, functions, settings) {
_afterFilterHandler = _afterFilterHandlers.reduceRight(
function(next, handler) {
return function(request, context) {
- try {
- var response = handler(request, context, next);
- if (Future.isFuture(response)) return response;
- return Future.value(response);
- }
- catch (e) {
- return Future.error(e);
- }
+ return Future.toPromise(handler(request, context, next));
};
}, afterFilterHandler);
}
@@ -1100,11 +1201,13 @@ function Client(uri, functions, settings) {
});
Object.defineProperties(this, {
'#': { value: autoId },
- onError: { get: getOnError, set: setOnError },
onerror: { get: getOnError, set: setOnError },
+ onfailswitch: { get: getOnFailswitch, set: setOnFailswitch },
uri: { get: getUri },
+ uriList: { get: getUriList, set: setUriList },
id: { get: getId },
failswitch: { get: getFailswitch, set: setFailswitch },
+ failround: { get: getFailround },
timeout: { get: getTimeout, set: setTimeout },
retry: { get: getRetry, set: setRetry },
idempotent: { get: getIdempotent, set: setIdempotent },
@@ -1117,11 +1220,14 @@ function Client(uri, functions, settings) {
filter: { get: getFilter, set: setFilter },
addFilter: { value: addFilter },
removeFilter: { value: removeFilter },
+ filters: { get: filters },
useService: { value: useService },
invoke: { value: invoke },
ready: { value: ready },
subscribe: {value: subscribe },
unsubscribe: {value: unsubscribe },
+ isSubscribed: { value : isSubscribed },
+ subscribedList: { value : subscribedList },
use: { value: use },
batch: { value: batch },
beforeFilter: { value: beforeFilter },
@@ -1137,15 +1243,9 @@ function Client(uri, functions, settings) {
}
});
}
- if (typeof(uri) === s_string) {
- _uris = [uri];
- _index = 0;
- useService(uri, functions);
- }
- else if (util.isArray(uri)) {
- _uris = uri;
- _index = Math.floor(Math.random() * _uris.length);
- useService(_uris[_index], functions);
+ if (uri) {
+ setUriList(uri);
+ useService(functions);
}
}
}
@@ -1185,7 +1285,7 @@ function create(uri, functions, settings) {
if (typeof uri === 'string') {
checkuri(uri);
}
- else if (util.isArray(uri)) {
+ else if (Array.isArray(uri)) {
uri.forEach(function(uri) { checkuri(uri); });
throw new Error('Not support multiple protocol.');
}
diff --git a/lib/client/HttpClient.js b/lib/client/HttpClient.js
index 3a51591..84c6f68 100644
--- a/lib/client/HttpClient.js
+++ b/lib/client/HttpClient.js
@@ -13,12 +13,11 @@
* *
* Hprose Http Client for Node.js. *
* *
- * LastModified: Aug 5, 2015 *
+ * LastModified: Dec 4, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var util = require('util');
@@ -27,7 +26,6 @@ var https = require('https');
var parse = require('url').parse;
var TimeoutError = require('../common/TimeoutError');
-var setImmediate = global.setImmediate;
var Client = global.hprose.Client;
var BytesIO = global.hprose.BytesIO;
var Future = global.hprose.Future;
@@ -43,12 +41,12 @@ function setCookie(headers, host) {
cookies = value.replace(/(^\s*)|(\s*$)/g, '').split(';');
cookie = {};
value = cookies[0].replace(/(^\s*)|(\s*$)/g, '').split('=', 2);
- if (value[1] === undefined) value[1] = null;
+ if (value[1] === undefined) { value[1] = null; }
cookie.name = value[0];
cookie.value = value[1];
for (i = 1; i < cookies.length; i++) {
value = cookies[i].replace(/(^\s*)|(\s*$)/g, '').split('=', 2);
- if (value[1] === undefined) value[1] = null;
+ if (value[1] === undefined) { value[1] = null; }
cookie[value[0].toUpperCase()] = value[1];
}
// Tomcat can return SetCookie2 with path wrapped in "
@@ -127,7 +125,27 @@ function HttpClient(uri, functions, settings) {
var self = this;
- function send(request, future) {
+ function getRequestHeader(headers) {
+ var header = Object.create(null);
+ var name, value;
+ for (name in _header) {
+ header[name] = _header[name];
+ }
+ if (headers) {
+ for (name in headers) {
+ value = headers[name];
+ if (Array.isArray(value)) {
+ header[name] = value.join(', ');
+ }
+ else {
+ header[name] = value;
+ }
+ }
+ }
+ return header;
+ }
+
+ function send(request, future, context) {
request = BytesIO.toBuffer(request);
var options = parse(self.uri);
var protocol = options.protocol;
@@ -149,16 +167,14 @@ function HttpClient(uri, functions, settings) {
options[key] = self.options[key];
}
options.method = 'POST';
- options.headers = Object.create(null);
- for (var name in _header) {
- options.headers[name] = _header[name];
- }
+ options.headers = getRequestHeader(context.httpHeader);
options.headers['Content-Length'] = request.length;
var cookie = getCookie(options.host, options.path, secure);
if (cookie !== '') {
options.headers.Cookie = cookie;
}
var req = client.request(options, function(resp) {
+ context.httpHeader = resp.headers;
var bytes = new BytesIO();
resp.on('data', function(data) { bytes.write(data); });
resp.on('end', function() {
@@ -179,11 +195,11 @@ function HttpClient(uri, functions, settings) {
return req;
}
- function sendAndReceive(request, env) {
+ function sendAndReceive(request, context) {
var future = new Future();
- var req = send(request, future);
- if (env.timeout > 0) {
- future = future.timeout(env.timeout).catchError(function(e) {
+ var req = send(request, future, context);
+ if (context.timeout > 0) {
+ future = future.timeout(context.timeout).catchError(function(e) {
req.removeAllListeners('error');
req.on('error', noop);
req.abort();
@@ -193,7 +209,7 @@ function HttpClient(uri, functions, settings) {
return e instanceof TimeoutError;
});
}
- if (env.oneway) future.resolve();
+ if (context.oneway) { future.resolve(); }
return future;
}
@@ -229,11 +245,11 @@ function create(uri, functions, settings) {
if (typeof uri === 'string') {
checkuri(uri);
}
- else if (util.isArray(uri)) {
+ else if (Array.isArray(uri)) {
uri.forEach(function(uri) { checkuri(uri); });
}
else {
- return new Error('You should set server uri first!');
+ throw new Error('You should set server uri first!');
}
return new HttpClient(uri, functions, settings);
}
diff --git a/lib/client/SocketClient.js b/lib/client/SocketClient.js
index 0749418..5a9a9d8 100644
--- a/lib/client/SocketClient.js
+++ b/lib/client/SocketClient.js
@@ -13,19 +13,17 @@
* *
* Hprose Socket Client for Node.js. *
* *
- * LastModified: Aug 14, 2015 *
+ * LastModified: Dec 2, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var util = require('util');
var net = require('net');
var tls = require('tls');
var parse = require('url').parse;
-var EventEmitter = require('events').EventEmitter;
var TimeoutError = require('../common/TimeoutError');
var Client = global.hprose.Client;
@@ -89,7 +87,7 @@ Object.defineProperties(SocketTransporter.prototype, {
protocol === 'tcp6:') {
socket = net;
options.host = parser.hostname;
- options.port = parseInt(parser.port);
+ options.port = parseInt(parser.port, 10);
if (protocol === 'tcp4:') {
options.family = 4;
}
@@ -103,7 +101,7 @@ Object.defineProperties(SocketTransporter.prototype, {
protocol === 'tls:') {
socket = tls;
options.host = parser.hostname;
- options.port = parseInt(parser.port);
+ options.port = parseInt(parser.port, 10);
if (protocol === 'tcp4s:') {
options.family = 4;
}
@@ -139,7 +137,7 @@ FullDuplexSocketTransporter.prototype = Object.create(
fetch: { value: function() {
var pool = this.pool;
while (pool.length > 0) {
- var conn = pool.shift();
+ var conn = pool.pop();
if (conn.connected) {
if (conn.count === 0) {
conn.removeAllListeners('timeout');
@@ -194,19 +192,21 @@ FullDuplexSocketTransporter.prototype = Object.create(
sendNext: { value: function(conn) {
if (conn.count < 10) {
if (this.requests.length > 0) {
- var request = this.requests.shift();
+ var request = this.requests.pop();
request.push(conn);
this.send.apply(this, request);
}
else {
- this.pool.push(conn);
+ if (this.pool.lastIndexOf(conn) < 0) {
+ this.pool.push(conn);
+ }
}
}
} },
- send: { value: function(request, future, id, env, conn) {
+ send: { value: function(request, future, id, context, conn) {
var self = this;
- var timeout = env.timeout;
+ var timeout = context.timeout;
if (timeout > 0) {
conn.timeoutIds[id] = global.setTimeout(function() {
self.clean(conn, id);
@@ -233,11 +233,11 @@ FullDuplexSocketTransporter.prototype = Object.create(
getNextId: { value: function() {
return (this.nextid < 0x7fffffff) ? ++this.nextid : this.nextid = 0;
} },
- sendAndReceive: { value: function(request, future, env) {
+ sendAndReceive: { value: function(request, future, context) {
var conn = this.fetch();
var id = this.getNextId();
if (conn) {
- this.send(request, future, id, env, conn);
+ this.send(request, future, id, context, conn);
}
else if (this.size < this.client.maxPoolSize) {
conn = this.create();
@@ -250,11 +250,11 @@ FullDuplexSocketTransporter.prototype = Object.create(
conn.removeAllListeners('error');
conn.connected = true;
self.init(conn);
- self.send(request, future, id, env, conn);
+ self.send(request, future, id, context, conn);
});
}
else {
- this.requests.push([request, future, id, env]);
+ this.requests.push([request, future, id, context]);
}
} }
});
@@ -270,7 +270,7 @@ HalfDuplexSocketTransporter.prototype = Object.create(
fetch: { value: function() {
var pool = this.pool;
while (pool.length > 0) {
- var conn = pool.shift();
+ var conn = pool.pop();
if (conn.connected) {
conn.removeAllListeners('timeout');
conn.ref();
@@ -280,12 +280,14 @@ HalfDuplexSocketTransporter.prototype = Object.create(
return null;
} },
recycle: { value: function(conn) {
- conn.unref();
- conn.setTimeout(this.client.poolTimeout, function() {
- conn.connected = false;
- conn.end();
- });
- this.pool.push(conn);
+ if (this.pool.lastIndexOf(conn) < 0) {
+ conn.unref();
+ conn.setTimeout(this.client.poolTimeout, function() {
+ conn.connected = false;
+ conn.end();
+ });
+ this.pool.push(conn);
+ }
} },
clean: { value: function(conn) {
conn.removeAllListeners('receive');
@@ -297,7 +299,7 @@ HalfDuplexSocketTransporter.prototype = Object.create(
} },
sendNext: { value: function(conn) {
if (this.requests.length > 0) {
- var request = this.requests.shift();
+ var request = this.requests.pop();
request.push(conn);
this.send.apply(this, request);
}
@@ -305,13 +307,14 @@ HalfDuplexSocketTransporter.prototype = Object.create(
this.recycle(conn);
}
} },
- send: { value: function(request, future, env, conn) {
+ send: { value: function(request, future, context, conn) {
var self = this;
- var timeout = env.timeout;
+ var timeout = context.timeout;
if (timeout > 0) {
conn.timeoutId = global.setTimeout(function() {
self.clean(conn);
- self.recycle(conn);
+ conn.connected = false;
+ conn.end();
future.reject(new TimeoutError('timeout'));
}, timeout);
}
@@ -328,16 +331,16 @@ HalfDuplexSocketTransporter.prototype = Object.create(
var len = request.length;
var buf = new Buffer(4 + len);
- buf.writeUInt32BE(len, 0);
+ buf.writeInt32BE(len, 0);
for (var i = 0; i < len; i++) {
buf[i + 4] = request[i];
}
conn.write(buf);
} },
- sendAndReceive: { value: function(request, future, env) {
+ sendAndReceive: { value: function(request, future, context) {
var conn = this.fetch();
if (conn) {
- this.send(request, future, env, conn);
+ this.send(request, future, context, conn);
}
else if (this.size < this.client.maxPoolSize) {
conn = this.create();
@@ -349,11 +352,11 @@ HalfDuplexSocketTransporter.prototype = Object.create(
conn.once('connect', function() {
conn.removeAllListeners('error');
conn.connected = true;
- self.send(request, future, env, conn);
+ self.send(request, future, context, conn);
});
}
else {
- this.requests.push([request, future, env]);
+ this.requests.push([request, future, context]);
}
} }
});
@@ -419,21 +422,21 @@ function SocketClient(uri, functions, settings) {
}
}
- function sendAndReceive(request, env) {
+ function sendAndReceive(request, context) {
var future = new Future();
if (_fullDuplex) {
if ((fdtrans === null) || (fdtrans.uri !== self.uri)) {
fdtrans = new FullDuplexSocketTransporter(self);
}
- fdtrans.sendAndReceive(request, future, env);
+ fdtrans.sendAndReceive(request, future, context);
}
else {
if ((hdtrans === null) || (hdtrans.uri !== self.uri)) {
hdtrans = new HalfDuplexSocketTransporter(self);
}
- hdtrans.sendAndReceive(request, future, env);
+ hdtrans.sendAndReceive(request, future, context);
}
- if (env.oneway) future.resolve();
+ if (context.oneway) { future.resolve(); }
return future;
}
@@ -465,11 +468,11 @@ function create(uri, functions, settings) {
if (typeof uri === 'string') {
checkuri(uri);
}
- else if (util.isArray(uri)) {
+ else if (Array.isArray(uri)) {
uri.forEach(function(uri) { checkuri(uri); });
}
else {
- return new Error('You should set server uri first!');
+ throw new Error('You should set server uri first!');
}
return new SocketClient(uri, functions, settings);
}
diff --git a/lib/client/WebSocketClient.js b/lib/client/WebSocketClient.js
index b10a68d..0d8b60d 100644
--- a/lib/client/WebSocketClient.js
+++ b/lib/client/WebSocketClient.js
@@ -12,16 +12,17 @@
* *
* Hprose WebSocket Client for HTML5. *
* *
- * LastModified: Aug 15, 2015 *
+ * LastModified: Aug 20, 2017 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var util = require('util');
var parse = require('url').parse;
+
+/*jshint -W079*/
var WebSocket = require('ws');
var Client = global.hprose.Client;
@@ -29,8 +30,6 @@ var BytesIO = global.hprose.BytesIO;
var Future = global.hprose.Future;
var TimeoutError = require('../common/TimeoutError');
-function noop(){}
-
function WebSocketClient(uri, functions, settings) {
if (this.constructor !== WebSocketClient) {
return new WebSocketClient(uri, functions, settings);
@@ -39,7 +38,6 @@ function WebSocketClient(uri, functions, settings) {
var _id = 0;
var _count = 0;
- var _reqcount = 0;
var _futures = [];
var _requests = [];
var _ready = null;
@@ -71,7 +69,7 @@ function WebSocketClient(uri, functions, settings) {
function onopen() {
_ready.resolve();
}
- function onmessage(data, flags) {
+ function onmessage(data) {
var bytes = new BytesIO(data);
var id = bytes.readInt32BE();
var future = _futures[id];
@@ -82,11 +80,11 @@ function WebSocketClient(uri, functions, settings) {
}
if ((_count < 100) && (_requests.length > 0)) {
++_count;
- var request = _requests.shift();
+ var request = _requests.pop();
_ready.then(function() { send(request[0], request[1]); });
}
if (_count === 0) {
- if (!self.keepAlive) close();
+ if (!self.keepAlive) { close(); }
}
}
function onclose(code, message) {
@@ -109,25 +107,26 @@ function WebSocketClient(uri, functions, settings) {
ws.on('error', onerror);
ws.on('close', onclose);
}
- function sendAndReceive(request, env) {
- if (ws === null ||
- ws.readyState === WebSocket.CLOSING ||
- ws.readyState === WebSocket.CLOSED) {
- connect();
- }
+ function sendAndReceive(request, context) {
var id = getNextId();
var future = new Future();
_futures[id] = future;
- if (env.timeout > 0) {
- future = future.timeout(env.timeout).catchError(function(e) {
+ if (context.timeout > 0) {
+ future = future.timeout(context.timeout).catchError(function(e) {
delete _futures[id];
--_count;
+ close();
throw e;
},
function(e) {
return e instanceof TimeoutError;
});
}
+ if (ws === null ||
+ ws.readyState === WebSocket.CLOSING ||
+ ws.readyState === WebSocket.CLOSED) {
+ connect();
+ }
if (_count < 100) {
++_count;
_ready.then(function() { send(id, request); });
@@ -135,7 +134,7 @@ function WebSocketClient(uri, functions, settings) {
else {
_requests.push([id, request]);
}
- if (env.oneway) future.resolve();
+ if (context.oneway) { future.resolve(); }
return future;
}
function close() {
@@ -149,7 +148,7 @@ function WebSocketClient(uri, functions, settings) {
}
Object.defineProperties(this, {
sendAndReceive: { value: sendAndReceive },
- close: { value: close },
+ close: { value: close }
});
}
@@ -166,11 +165,11 @@ function create(uri, functions, settings) {
if (typeof uri === 'string') {
checkuri(uri);
}
- else if (util.isArray(uri)) {
+ else if (Array.isArray(uri)) {
uri.forEach(function(uri) { checkuri(uri); });
}
else {
- return new Error('You should set server uri first!');
+ throw new Error('You should set server uri first!');
}
return new WebSocketClient(uri, functions, settings);
}
diff --git a/lib/common/Future.js b/lib/common/Future.js
index c3fb4d2..7176bde 100644
--- a/lib/common/Future.js
+++ b/lib/common/Future.js
@@ -13,440 +13,612 @@
* *
* Hprose Future for Node.js. *
* *
- * LastModified: Aug 2, 2015 *
+ * LastModified: Dec 5, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
-'use strict';
+(function() {
+ 'use strict';
-var util = require('util');
-var TimeoutError = require('./TimeoutError');
+ var TimeoutError = require('./TimeoutError');
-var PENDING = 0;
-var FULFILLED = 1;
-var REJECTED = 2;
+ var PENDING = 0;
+ var FULFILLED = 1;
+ var REJECTED = 2;
-var hasPromise = 'Promise' in global;
-var setImmediate = global.setImmediate;
-var setTimeout = global.setTimeout;
-var clearTimeout = global.clearTimeout;
-var foreach = Function.prototype.call.bind(Array.prototype.forEach);
-var slice = Function.prototype.call.bind(Array.prototype.slice);
+ var hasPromise = 'Promise' in global;
+ var setTimeout = global.setTimeout;
+ var clearTimeout = global.clearTimeout;
+ var foreach = Array.prototype.forEach;
+ var slice = Array.prototype.slice;
-function Future(computation) {
- Object.defineProperties(this, {
- _subscribers: { value: [] },
- resolve: { value: this.resolve.bind(this) },
- reject: { value: this.reject.bind(this) },
- });
- var self = this;
- if (typeof computation === 'function') {
- setImmediate(function() {
+ function Future(computation) {
+ var self = this;
+ Object.defineProperties(this, {
+ _subscribers: { value: [] },
+ resolve: { value: this.resolve.bind(this) },
+ reject: { value: this.reject.bind(this) }
+ });
+ if (typeof computation === 'function') {
+ process.nextTick(function() {
+ try {
+ self.resolve(computation());
+ }
+ catch(e) {
+ self.reject(e);
+ }
+ });
+ }
+ }
+
+ function isFuture(obj) {
+ return obj instanceof Future;
+ }
+
+ function toFuture(obj) {
+ return isFuture(obj) ? obj : value(obj);
+ }
+
+ function isPromise(obj) {
+ return 'function' === typeof obj.then;
+ }
+
+ function delayed(duration, value) {
+ var computation = (typeof value === 'function') ?
+ value :
+ function() { return value; };
+ var future = new Future();
+ setTimeout(function() {
try {
- self.resolve(computation());
+ future.resolve(computation());
}
catch(e) {
- self.reject(e);
+ future.reject(e);
}
- });
+ }, duration);
+ return future;
}
-}
-function isFuture(obj) {
- return obj instanceof Future;
-}
+ function error(e) {
+ var future = new Future();
+ future.reject(e);
+ return future;
+ }
-function isPromise(obj) {
- return isFuture(obj) || (hasPromise && (obj instanceof global.Promise) && (typeof (obj.then === 'function')));
-}
+ function value(v) {
+ var future = new Future();
+ future.resolve(v);
+ return future;
+ }
-function delayed(duration, value) {
- var computation = (typeof value === 'function') ?
- value :
- function() { return value; };
- var future = new Future();
- setTimeout(function() {
+ function sync(computation) {
try {
- future.resolve(computation());
+ var result = computation();
+ return value(result);
}
catch(e) {
- future.reject(e);
+ return error(e);
}
- }, duration);
- return future;
-}
-
-function error(e) {
- var future = new Future();
- future.reject(e);
- return future;
-}
-
-function value(v) {
- var future = new Future();
- future.resolve(v);
- return future;
-}
-
-function sync(computation) {
- try {
- var result = computation();
- return value(result);
- }
- catch(e) {
- return error(e);
- }
-}
-
-function promise(executor) {
- var future = new Future();
- executor(future.resolve, future.reject);
- return future;
-}
-
-function arraysize(array) {
- var size = 0;
- foreach(array, function() { ++size; });
- return size;
-}
-
-function all(array) {
- array = isPromise(array) ? array : value(array);
- return array.then(function(array) {
- var n = array.length;
- var count = arraysize(array);
- var result = new Array(n);
- if (count === 0) return value(result);
+ }
+
+ function promise(executor) {
var future = new Future();
- foreach(array, function(element, index) {
- var f = (isPromise(element) ? element : value(element));
- f.then(function(value) {
- result[index] = value;
- if (--count === 0) {
- future.resolve(result);
- }
- },
- future.reject);
- });
+ executor(future.resolve, future.reject);
return future;
- });
-}
+ }
-function join() {
- return all(arguments);
-}
+ function arraysize(array) {
+ var size = 0;
+ foreach.call(array, function() { ++size; });
+ return size;
+ }
-function race(array) {
- array = isPromise(array) ? array : value(array);
- return array.then(function(array) {
- var future = new Future();
- foreach(array, function(element) {
- var f = (isPromise(element) ? element : value(element));
- f.then(future.resolve, future.reject);
+ function all(array) {
+ return toFuture(array).then(function(array) {
+ var n = array.length;
+ var count = arraysize(array);
+ var result = new Array(n);
+ if (count === 0) { return result; }
+ var future = new Future();
+ foreach.call(array, function(element, index) {
+ toFuture(element).then(function(value) {
+ result[index] = value;
+ if (--count === 0) {
+ future.resolve(result);
+ }
+ },
+ future.reject);
+ });
+ return future;
});
- return future;
- });
-}
-
-function any(array) {
- array = isPromise(array) ? array : value(array);
- return array.then(function(array) {
- var n = array.length;
- var count = arraysize(array);
- if (count === 0) {
- throw new RangeError('any(): array must not be empty');
- }
- var reasons = new Array(n);
- var future = new Future();
- foreach(array, function(element, index) {
- var f = (isPromise(element) ? element : value(element));
- f.then(future.resolve, function(e) {
- reasons[index] = e;
- if (--count === 0) {
- future.reject(reasons);
- }
+ }
+
+ function join() {
+ return all(arguments);
+ }
+
+ function race(array) {
+ return toFuture(array).then(function(array) {
+ var future = new Future();
+ foreach.call(array, function(element) {
+ toFuture(element).fill(future);
});
+ return future;
});
- return future;
- });
-}
-
-function settle(array) {
- array = isPromise(array) ? array : value(array);
- return array.then(function(array) {
- var n = array.length;
- var count = arraysize(array);
- var result = new Array(n);
- if (count === 0) return value(result);
- var future = new Future();
- foreach(array, function(element, index) {
- var f = (isPromise(element) ? element : value(element));
- f.whenComplete(function() {
- result[index] = f.inspect();
- if (--count === 0) {
- future.resolve(result);
- }
+ }
+
+ function any(array) {
+ return toFuture(array).then(function(array) {
+ var n = array.length;
+ var count = arraysize(array);
+ if (count === 0) {
+ throw new RangeError('any(): array must not be empty');
+ }
+ var reasons = new Array(n);
+ var future = new Future();
+ foreach.call(array, function(element, index) {
+ toFuture(element).then(future.resolve, function(e) {
+ reasons[index] = e;
+ if (--count === 0) {
+ future.reject(reasons);
+ }
+ });
});
+ return future;
});
- return future;
- });
-}
+ }
-function attempt(handler/*, arg1, arg2, ... */) {
- var args = slice(arguments, 1);
- return all(args).then(function(args) {
- return handler.apply(undefined, args);
- });
-}
+ function settle(array) {
+ return toFuture(array).then(function(array) {
+ var n = array.length;
+ var count = arraysize(array);
+ var result = new Array(n);
+ if (count === 0) { return result; }
+ var future = new Future();
+ foreach.call(array, function(element, index) {
+ var f = toFuture(element);
+ f.complete(function() {
+ result[index] = f.inspect();
+ if (--count === 0) {
+ future.resolve(result);
+ }
+ });
+ });
+ return future;
+ });
+ }
-function run(handler, thisArg/*, arg1, arg2, ... */) {
- var args = slice(arguments, 2);
- return all(args).then(function(args) {
- return handler.apply(thisArg, args);
- });
-}
+ function attempt(handler/*, arg1, arg2, ... */) {
+ var thisArg = (function() { return this; })();
+ var args = slice.call(arguments, 1);
+ return all(args).then(function(args) {
+ return handler.apply(thisArg, args);
+ });
+ }
-function wrap(handler, thisArg) {
- return function() {
- return all(arguments).then(function(args) {
+ function run(handler, thisArg/*, arg1, arg2, ... */) {
+ var args = slice.call(arguments, 2);
+ return all(args).then(function(args) {
return handler.apply(thisArg, args);
});
- };
-}
+ }
-function forEach(array, callback, thisArg) {
- return all(array).then(function(array) {
- return array.forEach(callback, thisArg);
- });
-}
+ function isGenerator(obj) {
+ if (!obj) {
+ return false;
+ }
+ return 'function' == typeof obj.next && 'function' == typeof obj['throw'];
+ }
-function every(array, callback, thisArg) {
- return all(array).then(function(array) {
- return array.every(callback, thisArg);
- });
-}
+ function isGeneratorFunction(obj) {
+ if (!obj) {
+ return false;
+ }
+ var constructor = obj.constructor;
+ if (!constructor) {
+ return false;
+ }
+ if ('GeneratorFunction' === constructor.name ||
+ 'GeneratorFunction' === constructor.displayName) {
+ return true;
+ }
+ return isGenerator(constructor.prototype);
+ }
-function some(array, callback, thisArg) {
- return all(array).then(function(array) {
- return array.some(callback, thisArg);
- });
-}
+ function getThunkCallback(future) {
+ return function(err, res) {
+ if (err instanceof Error) {
+ return future.reject(err);
+ }
+ if (arguments.length < 2) {
+ return future.resolve(err);
+ }
+ if (err === null || err === undefined) {
+ res = slice.call(arguments, 1);
+ }
+ else {
+ res = slice.call(arguments, 0);
+ }
+ if (res.length == 1) {
+ future.resolve(res[0]);
+ }
+ else {
+ future.resolve(res);
+ }
+ };
+ }
-function filter(array, callback, thisArg) {
- return all(array).then(function(array) {
- return array.filter(callback, thisArg);
- });
-}
+ function thunkToPromise(fn) {
+ if (isGeneratorFunction(fn) || isGenerator(fn)) {
+ return co(fn);
+ }
+ var thisArg = (function() { return this; })();
+ var future = new Future();
+ fn.call(thisArg, getThunkCallback(future));
+ return future;
+ }
-function map(array, callback, thisArg) {
- return all(array).then(function(array) {
- return array.map(callback, thisArg);
- });
-}
+ function thunkify(fn) {
+ return function() {
+ var args = slice.call(arguments, 0);
+ var thisArg = this;
+ var results = new Future();
+ args.push(function() {
+ thisArg = this;
+ results.resolve(arguments);
+ });
+ try {
+ fn.apply(this, args);
+ }
+ catch (err) {
+ results.resolve([err]);
+ }
+ return function(done) {
+ results.then(function(results) {
+ done.apply(thisArg, results);
+ });
+ };
+ };
+ }
-function reduce(array, callback, initialValue) {
- if (arguments.length > 2) {
- return all(array).then(function(array) {
- if (!isPromise(initialValue)) {
- initialValue = value(initialValue);
+ function promisify(fn) {
+ return function() {
+ var args = slice.call(arguments, 0);
+ var future = new Future();
+ args.push(getThunkCallback(future));
+ try {
+ fn.apply(this, args);
+ }
+ catch (err) {
+ future.reject(err);
+ }
+ return future;
+ };
+ }
+
+ function toPromise(obj) {
+ if (isGeneratorFunction(obj) || isGenerator(obj)) {
+ return co(obj);
+ }
+ return toFuture(obj);
+ }
+
+ function co(gen) {
+ var thisArg = (function() { return this; })();
+ if (typeof gen === 'function') {
+ var args = slice.call(arguments, 1);
+ gen = gen.apply(thisArg, args);
+ }
+
+ if (!gen || typeof gen.next !== 'function') {
+ return toFuture(gen);
+ }
+
+ var future = new Future();
+
+ function onFulfilled(res) {
+ try {
+ next(gen.next(res));
+ }
+ catch (e) {
+ future.reject(e);
+ }
+ }
+
+ function onRejected(err) {
+ try {
+ next(gen['throw'](err));
}
- return initialValue.then(function(value) {
- return array.reduce(callback, value);
+ catch (e) {
+ future.reject(e);
+ }
+ }
+
+ function next(ret) {
+ if (ret.done) {
+ future.resolve(ret.value);
+ }
+ else {
+ (('function' == typeof ret.value) ?
+ thunkToPromise(ret.value) :
+ toPromise(ret.value)).then(onFulfilled, onRejected);
+ }
+ }
+
+ onFulfilled();
+
+ return future;
+ }
+
+ function wrap(handler, thisArg) {
+ return function() {
+ thisArg = thisArg || this;
+ return all(arguments).then(function(args) {
+ var result = handler.apply(thisArg, args);
+ if (isGeneratorFunction(result) || isGenerator(result)) {
+ return co.call(thisArg, result);
+ }
+ return result;
});
+ };
+ }
+
+ co.wrap = wrap;
+
+ function forEach(array, callback, thisArg) {
+ thisArg = thisArg || (function() { return this; })();
+ return all(array).then(function(array) {
+ return array.forEach(callback, thisArg);
});
}
- return all(array).then(function(array) {
- return array.reduce(callback);
- });
-}
-function reduceRight(array, callback, initialValue) {
- if (arguments.length > 2) {
+ function every(array, callback, thisArg) {
+ thisArg = thisArg || (function() { return this; })();
return all(array).then(function(array) {
- if (!isPromise(initialValue)) {
- initialValue = value(initialValue);
- }
- return initialValue.then(function(value) {
- return array.reduceRight(callback, value);
- });
+ return array.every(callback, thisArg);
});
}
- return all(array).then(function(array) {
- return array.reduceRight(callback);
- });
-}
-
-Object.defineProperties(Future, {
- // port from Dart
- delayed: { value: delayed },
- error: { value: error },
- sync: { value: sync },
- value: { value: value },
- // Promise compatible
- all: { value: all },
- race: { value: race },
- resolve: { value: value },
- reject: { value: error },
- // extended methods
- promise: { value: promise },
- isFuture: { value: isFuture },
- isPromise: { value: isPromise },
- join: { value: join },
- any: { value: any },
- settle: { value: settle },
- attempt: { value: attempt },
- run: { value: run },
- wrap: { value: wrap },
- // for array
- forEach: { value: forEach },
- every: { value: every },
- some: { value: some },
- filter: { value: filter },
- map: { value: map },
- reduce: { value: reduce },
- reduceRight: { value: reduceRight }
-});
-
-function _call(callback, next, x) {
- setImmediate(function() {
- try {
- var r = callback(x);
- next.resolve(r);
+
+ function some(array, callback, thisArg) {
+ thisArg = thisArg || (function() { return this; })();
+ return all(array).then(function(array) {
+ return array.some(callback, thisArg);
+ });
+ }
+
+ function filter(array, callback, thisArg) {
+ thisArg = thisArg || (function() { return this; })();
+ return all(array).then(function(array) {
+ return array.filter(callback, thisArg);
+ });
+ }
+
+ function map(array, callback, thisArg) {
+ thisArg = thisArg || (function() { return this; })();
+ return all(array).then(function(array) {
+ return array.map(callback, thisArg);
+ });
+ }
+
+ function reduce(array, callback, initialValue) {
+ if (arguments.length > 2) {
+ return all(array).then(function(array) {
+ return toFuture(initialValue).then(function(value) {
+ return array.reduce(callback, value);
+ });
+ });
}
- catch(e) {
- next.reject(e);
+ return all(array).then(function(array) {
+ return array.reduce(callback);
+ });
+ }
+
+ function reduceRight(array, callback, initialValue) {
+ if (arguments.length > 2) {
+ return all(array).then(function(array) {
+ return toFuture(initialValue).then(function(value) {
+ return array.reduceRight(callback, value);
+ });
+ });
}
- });
-}
+ return all(array).then(function(array) {
+ return array.reduceRight(callback);
+ });
+ }
+
+ function indexOf(array, searchElement, fromIndex) {
+ return all(array).then(function(array) {
+ return toFuture(searchElement).then(function(searchElement) {
+ return array.indexOf(searchElement, fromIndex);
+ });
+ });
+ }
-function _reject(onreject, next, e) {
- if (onreject) {
- _call(onreject, next, e);
+ function lastIndexOf(array, searchElement, fromIndex) {
+ return all(array).then(function(array) {
+ return toFuture(searchElement).then(function(searchElement) {
+ if (fromIndex === undefined) {
+ fromIndex = array.length - 1;
+ }
+ return array.lastIndexOf(searchElement, fromIndex);
+ });
+ });
}
- else {
- next.reject(e);
+
+ function includes(array, searchElement, fromIndex) {
+ return all(array).then(function(array) {
+ return toFuture(searchElement).then(function(searchElement) {
+ return array.includes(searchElement, fromIndex);
+ });
+ });
}
-}
+ function find(array, predicate, thisArg) {
+ thisArg = thisArg || (function() { return this; })();
+ return all(array).then(function(array) {
+ return array.find(predicate, thisArg);
+ });
+ }
-function _resolve(onfulfill, onreject, self, next, x) {
- function resolvePromise(y) {
- _resolve(onfulfill, onreject, self, next, y);
+ function findIndex(array, predicate, thisArg) {
+ thisArg = thisArg || (function() { return this; })();
+ return all(array).then(function(array) {
+ return array.findIndex(predicate, thisArg);
+ });
}
- function rejectPromise(r) {
- _reject(onreject, next, r);
+
+ Object.defineProperties(Future, {
+ // port from Dart
+ delayed: { value: delayed },
+ error: { value: error },
+ sync: { value: sync },
+ value: { value: value },
+ // Promise compatible
+ all: { value: all },
+ race: { value: race },
+ resolve: { value: value },
+ reject: { value: error },
+ // extended methods
+ promise: { value: promise },
+ isFuture: { value: isFuture },
+ toFuture: { value: toFuture },
+ isPromise: { value: isPromise },
+ toPromise: { value: toPromise },
+ join: { value: join },
+ any: { value: any },
+ settle: { value: settle },
+ attempt: { value: attempt },
+ run: { value: run },
+ thunkify: { value: thunkify },
+ promisify: { value: promisify },
+ co: { value: co },
+ wrap: { value: wrap },
+ // for array
+ forEach: { value: forEach },
+ every: { value: every },
+ some: { value: some },
+ filter: { value: filter },
+ map: { value: map },
+ reduce: { value: reduce },
+ reduceRight: { value: reduceRight },
+ indexOf: { value: indexOf },
+ lastIndexOf: { value: lastIndexOf },
+ includes: { value: includes },
+ find: { value: find },
+ findIndex: { value: findIndex }
+ });
+
+ function _call(callback, next, x) {
+ process.nextTick(function() {
+ try {
+ var r = callback(x);
+ next.resolve(r);
+ }
+ catch(e) {
+ next.reject(e);
+ }
+ });
}
- if (isPromise(x)) {
- if (x === self) {
- rejectPromise(new TypeError('Self resolution'));
- return;
+
+ function _resolve(onfulfill, next, x) {
+ if (onfulfill) {
+ _call(onfulfill, next, x);
+ }
+ else {
+ next.resolve(x);
}
- x.then(resolvePromise, rejectPromise);
- return;
}
- if ((x !== null) &&
- (typeof x === 'object') ||
- (typeof x === 'function')) {
- var then;
- try {
- then = x.then;
+
+ function _reject(onreject, next, e) {
+ if (onreject) {
+ _call(onreject, next, e);
}
- catch (e) {
- rejectPromise(e);
- return;
+ else {
+ next.reject(e);
}
- if (typeof then === 'function') {
- var notrun = true;
- try {
- then.call(x, function(y) {
- if (notrun) {
- notrun = false;
- resolvePromise(y);
- }
- }, function(r) {
- if (notrun) {
- notrun = false;
- rejectPromise(r);
- }
- });
+ }
+
+ Object.defineProperties(Future.prototype, {
+ _value: { writable: true },
+ _reason: { writable: true },
+ _state: { value: PENDING, writable: true },
+ resolve: { value: function(value) {
+ if (value === this) {
+ this.reject(new TypeError('Self resolution'));
return;
}
- catch (e) {
- if (notrun) {
- notrun = false;
- rejectPromise(e);
- }
+ if (isFuture(value)) {
+ value.fill(this);
+ return;
}
- return;
- }
- }
- if (onfulfill) {
- _call(onfulfill, next, x);
- }
- else {
- next.resolve(x);
- }
-}
-
-Object.defineProperties(Future.prototype, {
- _value: { writable: true },
- _reason: { writable: true },
- _state: { value: PENDING, writable: true },
- resolve: { value: function(value) {
- if (this._state === PENDING) {
- this._state = FULFILLED;
- this._value = value;
- var subscribers = this._subscribers;
- while (subscribers.length > 0) {
- var subscriber = subscribers.shift();
- _resolve(subscriber.onfulfill,
- subscriber.onreject,
- this,
- subscriber.next,
- value);
+ if ((value !== null) &&
+ (typeof value === 'object') ||
+ (typeof value === 'function')) {
+ var then;
+ try {
+ then = value.then;
+ }
+ catch (e) {
+ this.reject(e);
+ return;
+ }
+ if (typeof then === 'function') {
+ var notrun = true;
+ try {
+ var self = this;
+ then.call(value, function(y) {
+ if (notrun) {
+ notrun = false;
+ self.resolve(y);
+ }
+ }, function(r) {
+ if (notrun) {
+ notrun = false;
+ self.reject(r);
+ }
+ });
+ return;
+ }
+ catch (e) {
+ if (notrun) {
+ notrun = false;
+ this.reject(e);
+ }
+ }
+ return;
+ }
}
- }
- } },
- reject: { value: function(reason) {
- if (this._state === PENDING) {
- this._state = REJECTED;
- this._reason = reason;
- var subscribers = this._subscribers;
- while (subscribers.length > 0) {
- var subscriber = subscribers.shift();
- if (subscriber.onreject) {
- _call(subscriber.onreject,
- subscriber.next,
- reason);
+ if (this._state === PENDING) {
+ this._state = FULFILLED;
+ this._value = value;
+ var subscribers = this._subscribers;
+ while (subscribers.length > 0) {
+ var subscriber = subscribers.shift();
+ _resolve(subscriber.onfulfill, subscriber.next, value);
}
- else {
- subscriber.next.reject(reason);
+ }
+ } },
+ reject: { value: function(reason) {
+ if (this._state === PENDING) {
+ this._state = REJECTED;
+ this._reason = reason;
+ var subscribers = this._subscribers;
+ while (subscribers.length > 0) {
+ var subscriber = subscribers.shift();
+ _reject(subscriber.onreject, subscriber.next, reason);
}
}
- }
- } },
- then: { value: function(onfulfill, onreject) {
- if (typeof onfulfill !== 'function') onfulfill = null;
- if (typeof onreject !== 'function') onreject = null;
- if (onfulfill || onreject) {
+ } },
+ then: { value: function(onfulfill, onreject) {
+ if (typeof onfulfill !== 'function') { onfulfill = null; }
+ if (typeof onreject !== 'function') { onreject = null; }
var next = new Future();
if (this._state === FULFILLED) {
- if (onfulfill) {
- _resolve(onfulfill, onreject, this, next, this._value);
- }
- else {
- next.resolve(this._value);
- }
+ _resolve(onfulfill, next, this._value);
}
else if (this._state === REJECTED) {
- if (onreject) {
- _call(onreject, next, this._reason);
- }
- else {
- next.reject(this._reason);
- }
+ _reject(onreject, next, this._reason);
}
else {
this._subscribers.push({
@@ -456,198 +628,225 @@ Object.defineProperties(Future.prototype, {
});
}
return next;
- }
- return this;
- } },
- inspect: { value: function() {
- switch (this._state) {
- case PENDING: return { state: 'pending' };
- case FULFILLED: return { state: 'fulfilled', value: this._value };
- case REJECTED: return { state: 'rejected', reason: this._reason };
- }
- } },
- catchError: { value: function(onreject, test) {
- if (typeof test === 'function') {
- var self = this;
- return this['catch'](function(e) {
- if (test(e)) {
- return self['catch'](onreject);
- }
- else {
- throw e;
- }
+ } },
+ done: { value: function(onfulfill, onreject) {
+ this.then(onfulfill, onreject).then(null, function(error) {
+ process.nextTick(function() { throw error; });
});
- }
- return this['catch'](onreject);
- } },
- 'catch': { value: function(onreject) {
- return this.then(null, onreject);
- } },
- whenComplete: { value: function(action) {
- return this.then(
- function(v) {
- var f = action();
- if (f === undefined) return v;
- f = isPromise(f) ? f : value(f);
- return f.then(function() { return v; });
- },
- function(e) {
- var f = action();
- if (f === undefined) throw e;
- f = isPromise(f) ? f : value(f);
- return f.then(function() { throw e; });
- }
- );
- } },
- timeout: { value: function(duration, reason) {
- var future = new Future();
- var timeoutId = setTimeout(function() {
- future.reject(reason || new TimeoutError('timeout'));
- }, duration);
- this.whenComplete(function() { clearTimeout(timeoutId); })
- .then(future.resolve, future.reject);
- return future;
- } },
- delay: { value: function(duration) {
- var future = new Future();
- this.then(function(result) {
- setTimeout(function() {
- future.resolve(result);
+ } },
+ inspect: { value: function() {
+ switch (this._state) {
+ case PENDING: return { state: 'pending' };
+ case FULFILLED: return { state: 'fulfilled', value: this._value };
+ case REJECTED: return { state: 'rejected', reason: this._reason };
+ }
+ } },
+ catchError: { value: function(onreject, test) {
+ if (typeof test === 'function') {
+ var self = this;
+ return this['catch'](function(e) {
+ if (test(e)) {
+ return self['catch'](onreject);
+ }
+ else {
+ throw e;
+ }
+ });
+ }
+ return this['catch'](onreject);
+ } },
+ 'catch': { value: function(onreject) {
+ return this.then(null, onreject);
+ } },
+ fail: { value: function(onreject) {
+ this.done(null, onreject);
+ } },
+ whenComplete: { value: function(action) {
+ return this.then(
+ function(v) { action(); return v; },
+ function(e) { action(); throw e; }
+ );
+ } },
+ complete: { value: function(oncomplete) {
+ oncomplete = oncomplete || function(v) { return v; };
+ return this.then(oncomplete, oncomplete);
+ } },
+ always: { value: function(oncomplete) {
+ this.done(oncomplete, oncomplete);
+ } },
+ fill: { value: function(future) {
+ this.then(future.resolve, future.reject);
+ } },
+ timeout: { value: function(duration, reason) {
+ var future = new Future();
+ var timeoutId = setTimeout(function() {
+ future.reject(reason || new TimeoutError('timeout'));
}, duration);
- },
- future.reject);
- return future;
- } },
- tap: { value: function(onfulfilledSideEffect, thisArg) {
- return this.then(function(result) {
- onfulfilledSideEffect.call(thisArg, result);
- return result;
- });
- } },
- spread: { value: function(onfulfilledArray, thisArg) {
- return this.then(function(array) {
- return onfulfilledArray.apply(thisArg, array);
- });
- } },
- get: { value: function(key) {
- return this.then(function(result) {
- return result[key];
- });
- } },
- set: { value: function(key, value) {
- return this.then(function(result) {
- result[key] = value;
- return result;
- });
- } },
- apply: { value: function(method, args) {
- args = args || [];
- return this.then(function(result) {
- return all(args).then(function(args) {
- return result[method].apply(result, args);
+ this.whenComplete(function() { clearTimeout(timeoutId); })
+ .fill(future);
+ return future;
+ } },
+ delay: { value: function(duration) {
+ var future = new Future();
+ this.then(function(result) {
+ setTimeout(function() {
+ future.resolve(result);
+ }, duration);
+ },
+ future.reject);
+ return future;
+ } },
+ tap: { value: function(onfulfilledSideEffect, thisArg) {
+ return this.then(function(result) {
+ onfulfilledSideEffect.call(thisArg, result);
+ return result;
});
- });
- } },
- call: { value: function(method) {
- var args = slice(arguments, 1);
- return this.then(function(result) {
- return all(args).then(function(args) {
- return result[method].apply(result, args);
+ } },
+ spread: { value: function(onfulfilledArray, thisArg) {
+ return this.then(function(array) {
+ return onfulfilledArray.apply(thisArg, array);
});
- });
- } },
- bind: { value: function(method) {
- var bindargs = slice(arguments);
- if (util.isArray(method)) {
- for (var i = 0, n = method.length; i < n; ++i) {
- bindargs[0] = method[i];
- this.bind.apply(this, bindargs);
- }
- return;
- }
- bindargs.shift();
- var self = this;
- Object.defineProperty(this, method, { value: function() {
- var args = slice(arguments);
- return self.then(function(result) {
- return all(bindargs.concat(args)).then(function(args) {
+ } },
+ get: { value: function(key) {
+ return this.then(function(result) {
+ return result[key];
+ });
+ } },
+ set: { value: function(key, value) {
+ return this.then(function(result) {
+ result[key] = value;
+ return result;
+ });
+ } },
+ apply: { value: function(method, args) {
+ args = args || [];
+ return this.then(function(result) {
+ return all(args).then(function(args) {
return result[method].apply(result, args);
});
});
- } });
- return this;
- } },
- forEach: { value: function(callback, thisArg) {
- return forEach(this, callback, thisArg);
- } },
- every: { value: function(callback, thisArg) {
- return every(this, callback, thisArg);
- } },
- some: { value: function(callback, thisArg) {
- return some(this, callback, thisArg);
- } },
- filter: { value: function(callback, thisArg) {
- return filter(this, callback, thisArg);
- } },
- map: { value: function(callback, thisArg) {
- return map(this, callback, thisArg);
- } },
- reduce: { value: function(callback, initialValue) {
- if (arguments.length > 1) {
- return reduce(this, callback, initialValue);
- }
- return reduce(this, callback);
- } },
- reduceRight: { value: function(callback, initialValue) {
- if (arguments.length > 1) {
- return reduceRight(this, callback, initialValue);
- }
- return reduceRight(this, callback);
- } }
-});
-
-global.hprose.Future = Future;
-
-function Completer() {
- var future = new Future();
- Object.defineProperties(this, {
- future: { value: future },
- complete: { value: future.resolve },
- completeError: { value: future.reject },
- isCompleted: { get: function() {
- return ( future._state !== PENDING );
+ } },
+ call: { value: function(method) {
+ var args = slice.call(arguments, 1);
+ return this.then(function(result) {
+ return all(args).then(function(args) {
+ return result[method].apply(result, args);
+ });
+ });
+ } },
+ bind: { value: function(method) {
+ var bindargs = slice.call(arguments);
+ if (Array.isArray(method)) {
+ for (var i = 0, n = method.length; i < n; ++i) {
+ bindargs[0] = method[i];
+ this.bind.apply(this, bindargs);
+ }
+ return;
+ }
+ bindargs.shift();
+ var self = this;
+ Object.defineProperty(this, method, { value: function() {
+ var args = slice.call(arguments);
+ return self.then(function(result) {
+ return all(bindargs.concat(args)).then(function(args) {
+ return result[method].apply(result, args);
+ });
+ });
+ } });
+ return this;
+ } },
+ forEach: { value: function(callback, thisArg) {
+ return forEach(this, callback, thisArg);
+ } },
+ every: { value: function(callback, thisArg) {
+ return every(this, callback, thisArg);
+ } },
+ some: { value: function(callback, thisArg) {
+ return some(this, callback, thisArg);
+ } },
+ filter: { value: function(callback, thisArg) {
+ return filter(this, callback, thisArg);
+ } },
+ map: { value: function(callback, thisArg) {
+ return map(this, callback, thisArg);
+ } },
+ reduce: { value: function(callback, initialValue) {
+ if (arguments.length > 1) {
+ return reduce(this, callback, initialValue);
+ }
+ return reduce(this, callback);
+ } },
+ reduceRight: { value: function(callback, initialValue) {
+ if (arguments.length > 1) {
+ return reduceRight(this, callback, initialValue);
+ }
+ return reduceRight(this, callback);
+ } },
+ indexOf: { value: function(searchElement, fromIndex) {
+ return indexOf(this, searchElement, fromIndex);
+ } },
+ lastIndexOf: { value: function(searchElement, fromIndex) {
+ return lastIndexOf(this, searchElement, fromIndex);
+ } },
+ includes: { value: function(searchElement, fromIndex) {
+ return includes(this, searchElement, fromIndex);
+ } },
+ find: { value: function(predicate, thisArg) {
+ return find(this, predicate, thisArg);
+ } },
+ findIndex: { value: function(predicate, thisArg) {
+ return findIndex(this, predicate, thisArg);
} }
});
-}
-global.hprose.Completer = Completer;
+ global.hprose.Future = Future;
-global.hprose.resolved = value;
+ global.hprose.thunkify = thunkify;
+ global.hprose.promisify = promisify;
+ global.hprose.co = co;
+ global.hprose.co.wrap = global.hprose.wrap = wrap;
-global.hprose.rejected = error;
+ function Completer() {
+ var future = new Future();
+ Object.defineProperties(this, {
+ future: { value: future },
+ complete: { value: future.resolve },
+ completeError: { value: future.reject },
+ isCompleted: { get: function() {
+ return ( future._state !== PENDING );
+ } }
+ });
+ }
-global.hprose.deferred = function() {
- var self = new Future();
- return Object.create(null, {
- promise: { value: self },
- resolve: { value: self.resolve },
- reject: { value: self.reject },
- });
-};
+ global.hprose.Completer = Completer;
+
+ global.hprose.resolved = value;
+
+ global.hprose.rejected = error;
+
+ global.hprose.deferred = function() {
+ var self = new Future();
+ return Object.create(null, {
+ promise: { value: self },
+ resolve: { value: self.resolve },
+ reject: { value: self.reject }
+ });
+ };
-if (hasPromise) return;
+ if (hasPromise) { return; }
-global.Promise = function(executor) {
- Future.call(this);
- executor(this.resolve, this.reject);
-};
+ global.Promise = function(executor) {
+ Future.call(this);
+ executor(this.resolve, this.reject);
+ };
-global.Promise.prototype = Object.create(Future.prototype);
-global.Promise.prototype.constructor = Future;
+ global.Promise.prototype = Object.create(Future.prototype);
+ global.Promise.prototype.constructor = Future;
-Object.defineProperties(global.Promise, {
- all: { value: all },
- race: { value: race },
- resolve: { value: value },
- reject: { value: error }
-});
+ Object.defineProperties(global.Promise, {
+ all: { value: all },
+ race: { value: race },
+ resolve: { value: value },
+ reject: { value: error }
+ });
+})();
diff --git a/lib/common/HarmonyMaps.js b/lib/common/HarmonyMaps.js
index 64c6ec6..e3a2771 100644
--- a/lib/common/HarmonyMaps.js
+++ b/lib/common/HarmonyMaps.js
@@ -13,283 +13,288 @@
* *
* Harmony Maps for Node.js. *
* *
- * LastModified: Aug 2, 2015 *
+ * LastModified: Mar 3, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, unused:false, eqeqeq:true */
-'use strict';
+(function() {
+ 'use strict';
-var hasWeakMap = 'WeakMap' in global;
-var hasMap = 'Map' in global;
-var hasForEach = true;
+ var hasWeakMap = 'WeakMap' in global;
+ var hasMap = 'Map' in global;
+ var hasForEach = true;
-if (hasMap) {
- hasForEach = 'forEach' in new global.Map();
-}
+ if (hasMap) {
+ hasForEach = 'forEach' in new global.Map();
+ }
-if (hasWeakMap && hasMap && hasForEach) return;
+ if (hasWeakMap && hasMap && hasForEach) { return; }
-var util = require('util');
-
-var namespaces = Object.create(null);
-var count = 0;
-var reDefineValueOf = function (obj) {
- var privates = Object.create(null);
- var baseValueOf = obj.valueOf;
- Object.defineProperty(obj, 'valueOf', {
- value: function (namespace, n) {
- if ((this === obj) &&
- (n in namespaces) &&
- (namespaces[n] === namespace)) {
- if (!(n in privates)) privates[n] = Object.create(null);
- return privates[n];
- }
- else {
- return baseValueOf.apply(this, arguments);
- }
- },
- writable: true,
- configurable: true,
- enumerable: false
- });
-};
+ var namespaces = Object.create(null);
+ var count = 0;
+ var reDefineValueOf = function (obj) {
+ var privates = Object.create(null);
+ var baseValueOf = obj.valueOf;
+ Object.defineProperty(obj, 'valueOf', {
+ value: function (namespace, n) {
+ if ((this === obj) &&
+ (n in namespaces) &&
+ (namespaces[n] === namespace)) {
+ if (!(n in privates)) {
+ privates[n] = Object.create(null);
+ }
+ return privates[n];
+ }
+ else {
+ return baseValueOf.apply(this, arguments);
+ }
+ },
+ writable: true,
+ configurable: true,
+ enumerable: false
+ });
+ };
-if (!hasWeakMap) {
- global.WeakMap = function WeakMap() {
- var namespace = Object.create(null);
- var n = count++;
- namespaces[n] = namespace;
- var map = function (key) {
- if (key !== Object(key)) throw new Error('value is not a non-null object');
- var privates = key.valueOf(namespace, n);
- if (privates !== key.valueOf()) return privates;
- reDefineValueOf(key);
- return key.valueOf(namespace, n);
- };
- var m = Object.create(WeakMap.prototype, {
- get: {
- value: function (key) {
- return map(key).value;
+ if (!hasWeakMap) {
+ global.WeakMap = function WeakMap() {
+ var namespace = Object.create(null);
+ var n = count++;
+ namespaces[n] = namespace;
+ var map = function (key) {
+ if (key !== Object(key)) {
+ throw new Error('value is not a non-null object');
}
- },
- set: {
- value: function (key, value) {
- map(key).value = value;
+ var privates = key.valueOf(namespace, n);
+ if (privates !== key.valueOf()) {
+ return privates;
}
- },
- has: {
- value: function (key) {
- return 'value' in map(key);
+ reDefineValueOf(key);
+ return key.valueOf(namespace, n);
+ };
+ var m = Object.create(WeakMap.prototype, {
+ get: {
+ value: function (key) {
+ return map(key).value;
+ }
+ },
+ set: {
+ value: function (key, value) {
+ map(key).value = value;
+ }
+ },
+ has: {
+ value: function (key) {
+ return 'value' in map(key);
+ }
+ },
+ 'delete': {
+ value: function (key) {
+ return delete map(key).value;
+ }
+ },
+ clear: {
+ value: function () {
+ delete namespaces[n];
+ n = count++;
+ namespaces[n] = namespace;
+ }
}
- },
- 'delete': {
- value: function (key) {
- return delete map(key).value;
+ });
+ if (arguments.length > 0 && Array.isArray(arguments[0])) {
+ var iterable = arguments[0];
+ for (var i = 0, len = iterable.length; i < len; i++) {
+ m.set(iterable[i][0], iterable[i][1]);
}
- },
- clear: {
- value: function () {
+ }
+ return m;
+ };
+ }
+
+ if (!hasMap) {
+ var objectMap = function () {
+ var namespace = Object.create(null);
+ var n = count++;
+ var nullMap = Object.create(null);
+ namespaces[n] = namespace;
+ var map = function (key) {
+ if (key === null) { return nullMap; }
+ var privates = key.valueOf(namespace, n);
+ if (privates !== key.valueOf()) { return privates; }
+ reDefineValueOf(key);
+ return key.valueOf(namespace, n);
+ };
+ return {
+ get: function (key) { return map(key).value; },
+ set: function (key, value) { map(key).value = value; },
+ has: function (key) { return 'value' in map(key); },
+ 'delete': function (key) { return delete map(key).value; },
+ clear: function () {
delete namespaces[n];
n = count++;
namespaces[n] = namespace;
}
- }
- });
- if (arguments.length > 0 && util.isArray(arguments[0])) {
- var iterable = arguments[0];
- for (var i = 0, len = iterable.length; i < len; i++) {
- m.set(iterable[i][0], iterable[i][1]);
- }
- }
- return m;
- };
-}
-
-if (!hasMap) {
- var objectMap = function () {
- var namespace = Object.create(null);
- var n = count++;
- var nullMap = Object.create(null);
- namespaces[n] = namespace;
- var map = function (key) {
- if (key === null) return nullMap;
- var privates = key.valueOf(namespace, n);
- if (privates !== key.valueOf()) return privates;
- reDefineValueOf(key);
- return key.valueOf(namespace, n);
+ };
};
- return {
- get: function (key) { return map(key).value; },
- set: function (key, value) { map(key).value = value; },
- has: function (key) { return 'value' in map(key); },
- 'delete': function (key) { return delete map(key).value; },
- clear: function () {
- delete namespaces[n];
- n = count++;
- namespaces[n] = namespace;
- }
+ var noKeyMap = function () {
+ var map = Object.create(null);
+ return {
+ get: function () { return map.value; },
+ set: function (_, value) { map.value = value; },
+ has: function () { return 'value' in map; },
+ 'delete': function () { return delete map.value; },
+ clear: function () { map = Object.create(null); }
+ };
};
- };
- var noKeyMap = function () {
- var map = Object.create(null);
- return {
- get: function () { return map.value; },
- set: function (_, value) { map.value = value; },
- has: function () { return 'value' in map; },
- 'delete': function () { return delete map.value; },
- clear: function () { map = Object.create(null); }
- };
- };
- var scalarMap = function () {
- var map = Object.create(null);
- return {
- get: function (key) { return map[key]; },
- set: function (key, value) { map[key] = value; },
- has: function (key) { return key in map; },
- 'delete': function (key) { return delete map[key]; },
- clear: function () { map = Object.create(null); }
+ var scalarMap = function () {
+ var map = Object.create(null);
+ return {
+ get: function (key) { return map[key]; },
+ set: function (key, value) { map[key] = value; },
+ has: function (key) { return key in map; },
+ 'delete': function (key) { return delete map[key]; },
+ clear: function () { map = Object.create(null); }
+ };
};
- };
- global.Map = function Map() {
- var map = {
- 'number': scalarMap(),
- 'string': scalarMap(),
- 'boolean': scalarMap(),
- 'object': objectMap(),
- 'function': objectMap(),
- 'unknown': objectMap(),
- 'undefined': noKeyMap(),
- 'null': noKeyMap()
- };
- var size = 0;
- var keys = [];
- var m = Object.create(Map.prototype, {
- size: {
- get : function () { return size; }
- },
- get: {
- value: function (key) {
- return map[typeof(key)].get(key);
- }
- },
- set: {
- value: function (key, value) {
- if (!this.has(key)) {
- keys.push(key);
- size++;
+ global.Map = function Map() {
+ var map = {
+ 'number': scalarMap(),
+ 'string': scalarMap(),
+ 'boolean': scalarMap(),
+ 'object': objectMap(),
+ 'function': objectMap(),
+ 'unknown': objectMap(),
+ 'undefined': noKeyMap(),
+ 'null': noKeyMap()
+ };
+ var size = 0;
+ var keys = [];
+ var m = Object.create(Map.prototype, {
+ size: {
+ get : function () { return size; }
+ },
+ get: {
+ value: function (key) {
+ return map[typeof(key)].get(key);
}
- map[typeof(key)].set(key, value);
- }
- },
- has: {
- value: function (key) {
- return map[typeof(key)].has(key);
- }
- },
- 'delete': {
- value: function (key) {
- if (this.has(key)) {
- size--;
- keys.splice(keys.indexOf(key), 1);
- return map[typeof(key)]['delete'](key);
+ },
+ set: {
+ value: function (key, value) {
+ if (!this.has(key)) {
+ keys.push(key);
+ size++;
+ }
+ map[typeof(key)].set(key, value);
}
- return false;
- }
- },
- clear: {
- value: function () {
- keys.length = 0;
- for (var key in map) map[key].clear();
- size = 0;
- }
- },
- forEach: {
- value: function (callback, thisArg) {
- for (var i = 0, n = keys.length; i < n; i++) {
- callback.call(thisArg, this.get(keys[i]), keys[i], this);
+ },
+ has: {
+ value: function (key) {
+ return map[typeof(key)].has(key);
+ }
+ },
+ 'delete': {
+ value: function (key) {
+ if (this.has(key)) {
+ size--;
+ keys.splice(keys.indexOf(key), 1);
+ return map[typeof(key)]['delete'](key);
+ }
+ return false;
+ }
+ },
+ clear: {
+ value: function () {
+ keys.length = 0;
+ for (var key in map) { map[key].clear(); }
+ size = 0;
+ }
+ },
+ forEach: {
+ value: function (callback, thisArg) {
+ for (var i = 0, n = keys.length; i < n; i++) {
+ callback.call(thisArg, this.get(keys[i]), keys[i], this);
+ }
}
}
+ });
+ if (arguments.length > 0 && Array.isArray(arguments[0])) {
+ var iterable = arguments[0];
+ for (var i = 0, len = iterable.length; i < len; i++) {
+ m.set(iterable[i][0], iterable[i][1]);
+ }
}
- });
- if (arguments.length > 0 && util.isArray(arguments[0])) {
- var iterable = arguments[0];
- for (var i = 0, len = iterable.length; i < len; i++) {
- m.set(iterable[i][0], iterable[i][1]);
- }
- }
- return m;
- };
-}
+ return m;
+ };
+ }
-if (!hasForEach) {
- var OldMap = global.Map;
- global.Map = function Map() {
- var map = new OldMap();
- var size = 0;
- var keys = [];
- var m = Object.create(Map.prototype, {
- size: {
- get : function () { return size; }
- },
- get: {
- value: function (key) {
- return map.get(key);
- }
- },
- set: {
- value: function (key, value) {
- if (!map.has(key)) {
- keys.push(key);
- size++;
+ if (!hasForEach) {
+ var OldMap = global.Map;
+ global.Map = function Map() {
+ var map = new OldMap();
+ var size = 0;
+ var keys = [];
+ var m = Object.create(Map.prototype, {
+ size: {
+ get : function () { return size; }
+ },
+ get: {
+ value: function (key) {
+ return map.get(key);
}
- map.set(key, value);
- }
- },
- has: {
- value: function (key) {
- return map.has(key);
- }
- },
- 'delete': {
- value: function (key) {
- if (map.has(key)) {
- size--;
- keys.splice(keys.indexOf(key), 1);
- return map['delete'](key);
+ },
+ set: {
+ value: function (key, value) {
+ if (!map.has(key)) {
+ keys.push(key);
+ size++;
+ }
+ map.set(key, value);
}
- return false;
- }
- },
- clear: {
- value: function () {
- if ('clear' in map) {
- map.clear();
+ },
+ has: {
+ value: function (key) {
+ return map.has(key);
}
- else {
+ },
+ 'delete': {
+ value: function (key) {
+ if (map.has(key)) {
+ size--;
+ keys.splice(keys.indexOf(key), 1);
+ return map['delete'](key);
+ }
+ return false;
+ }
+ },
+ clear: {
+ value: function () {
+ if ('clear' in map) {
+ map.clear();
+ }
+ else {
+ for (var i = 0, n = keys.length; i < n; i++) {
+ map['delete'](keys[i]);
+ }
+ }
+ keys.length = 0;
+ size = 0;
+ }
+ },
+ forEach: {
+ value: function (callback, thisArg) {
for (var i = 0, n = keys.length; i < n; i++) {
- map['delete'](keys[i]);
+ callback.call(thisArg, this.get(keys[i]), keys[i], this);
}
}
- keys.length = 0;
- size = 0;
}
- },
- forEach: {
- value: function (callback, thisArg) {
- for (var i = 0, n = keys.length; i < n; i++) {
- callback.call(thisArg, this.get(keys[i]), keys[i], this);
- }
+ });
+ if (arguments.length > 0 && Array.isArray(arguments[0])) {
+ var iterable = arguments[0];
+ for (var i = 0, len = iterable.length; i < len; i++) {
+ m.set(iterable[i][0], iterable[i][1]);
}
}
- });
- if (arguments.length > 0 && util.isArray(arguments[0])) {
- var iterable = arguments[0];
- for (var i = 0, len = iterable.length; i < len; i++) {
- m.set(iterable[i][0], iterable[i][1]);
- }
- }
- return m;
- };
-}
+ return m;
+ };
+ }
+})();
diff --git a/lib/common/Helper.js b/lib/common/Helper.js
new file mode 100644
index 0000000..6a6802d
--- /dev/null
+++ b/lib/common/Helper.js
@@ -0,0 +1,98 @@
+/**********************************************************\
+| |
+| hprose |
+| |
+| Official WebSite: http://www.hprose.com/ |
+| http://www.hprose.org/ |
+| |
+\**********************************************************/
+
+/**********************************************************\
+ * *
+ * hprose/common/Helper.js *
+ * *
+ * Hprose Helper for Node.js. *
+ * *
+ * LastModified: Oct 12, 2016 *
+ * Author: Ma Bingyao *
+ * *
+\**********************************************************/
+
+(function() {
+ 'use strict';
+
+ function generic(method) {
+ if (typeof method !== "function") {
+ throw new TypeError(method + " is not a function");
+ }
+ return function(context) {
+ return method.apply(context, Array.prototype.slice.call(arguments, 1));
+ };
+ }
+
+ var arrayLikeObjectArgumentsEnabled = true;
+
+ try {
+ String.fromCharCode.apply(String, new Uint8Array([1]));
+ }
+ catch (e) {
+ arrayLikeObjectArgumentsEnabled = false;
+ }
+
+ function toArray(arrayLikeObject) {
+ var n = arrayLikeObject.length;
+ var a = new Array(n);
+ for (var i = 0; i < n; ++i) {
+ a[i] = arrayLikeObject[i];
+ }
+ return a;
+ }
+
+ var getCharCodes = arrayLikeObjectArgumentsEnabled ? function(bytes) { return bytes; } : toArray;
+
+ function toBinaryString(bytes) {
+ if (bytes instanceof ArrayBuffer) {
+ bytes = new Uint8Array(bytes);
+ }
+ var n = bytes.length;
+ if (n < 0xFFFF) {
+ return String.fromCharCode.apply(String, getCharCodes(bytes));
+ }
+ var remain = n & 0x7FFF;
+ var count = n >> 15;
+ var a = new Array(remain ? count + 1 : count);
+ for (var i = 0; i < count; ++i) {
+ a[i] = String.fromCharCode.apply(String, getCharCodes(bytes.subarray(i << 15, (i + 1) << 15)));
+ }
+ if (remain) {
+ a[count] = String.fromCharCode.apply(String, getCharCodes(bytes.subarray(count << 15, n)));
+ }
+ return a.join('');
+ }
+
+ function toUint8Array(bs) {
+ var n = bs.length;
+ var data = new Uint8Array(n);
+ for (var i = 0; i < n; i++) {
+ data[i] = bs.charCodeAt(i) & 0xFF;
+ }
+ return data;
+ }
+
+ var isObjectEmpty = function (obj) {
+ if (obj) {
+ var prop;
+ for (prop in obj) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ global.hprose.generic = generic;
+ global.hprose.toBinaryString = toBinaryString;
+ global.hprose.toUint8Array = toUint8Array;
+ global.hprose.toArray = toArray;
+ global.hprose.isObjectEmpty = isObjectEmpty;
+
+})();
diff --git a/lib/common/Polyfill.js b/lib/common/Polyfill.js
new file mode 100644
index 0000000..a636bbf
--- /dev/null
+++ b/lib/common/Polyfill.js
@@ -0,0 +1,413 @@
+/**********************************************************\
+| |
+| hprose |
+| |
+| Official WebSite: http://www.hprose.com/ |
+| http://www.hprose.org/ |
+| |
+\**********************************************************/
+
+/**********************************************************\
+ * *
+ * Polyfill.js *
+ * *
+ * Polyfill for Node.js. *
+ * *
+ * LastModified: Mar 3, 2016 *
+ * Author: Ma Bingyao *
+ * *
+\**********************************************************/
+
+'use strict';
+/* Function */
+if (!Function.prototype.bind) {
+ Object.defineProperty(Function.prototype, 'bind', { value: function(oThis) {
+ if (typeof this !== 'function') {
+ throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
+ }
+ var aArgs = Array.prototype.slice.call(arguments, 1),
+ toBind = this,
+ NOP = function() {},
+ bound = function() {
+ return toBind.apply(this instanceof NOP ? this : oThis,
+ aArgs.concat(Array.prototype.slice.call(arguments)));
+ };
+ if (this.prototype) {
+ NOP.prototype = this.prototype;
+ }
+ bound.prototype = new NOP();
+ return bound;
+ } });
+}
+/* Array */
+if (!Array.prototype.includes) {
+ Object.defineProperty(Array.prototype, 'includes', { value: function(searchElement /*, fromIndex*/ ) {
+ var O = Object(this);
+ var len = parseInt(O.length, 10) || 0;
+ if (len === 0) {
+ return false;
+ }
+ var n = parseInt(arguments[1], 10) || 0;
+ var k;
+ if (n >= 0) {
+ k = n;
+ }
+ else {
+ k = len + n;
+ if (k < 0) { k = 0; }
+ }
+ var currentElement;
+ while (k < len) {
+ currentElement = O[k];
+ if (searchElement === currentElement ||
+ (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN
+ return true;
+ }
+ k++;
+ }
+ return false;
+ } });
+}
+if (!Array.prototype.find) {
+ Object.defineProperty(Array.prototype, 'find', { value: function(predicate) {
+ if (this === null || this === undefined) {
+ throw new TypeError('Array.prototype.find called on null or undefined');
+ }
+ if (typeof predicate !== 'function') {
+ throw new TypeError('predicate must be a function');
+ }
+ var list = Object(this);
+ var length = list.length >>> 0;
+ var thisArg = arguments[1];
+ var value;
+ for (var i = 0; i < length; i++) {
+ value = list[i];
+ if (predicate.call(thisArg, value, i, list)) {
+ return value;
+ }
+ }
+ return undefined;
+ } });
+}
+if (!Array.prototype.findIndex) {
+ Object.defineProperty(Array.prototype, 'findIndex', { value: function(predicate) {
+ if (this === null || this === undefined) {
+ throw new TypeError('Array.prototype.findIndex called on null or undefined');
+ }
+ if (typeof predicate !== 'function') {
+ throw new TypeError('predicate must be a function');
+ }
+ var list = Object(this);
+ var length = list.length >>> 0;
+ var thisArg = arguments[1];
+ var value;
+
+ for (var i = 0; i < length; i++) {
+ value = list[i];
+ if (predicate.call(thisArg, value, i, list)) {
+ return i;
+ }
+ }
+ return -1;
+ } });
+}
+if (!Array.prototype.fill) {
+ Object.defineProperty(Array.prototype, 'fill', { value: function(value) {
+ if (this === null || this === undefined) {
+ throw new TypeError('this is null or not defined');
+ }
+ var O = Object(this);
+ var len = O.length >>> 0;
+ var start = arguments[1];
+ var relativeStart = start >> 0;
+ var k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
+ var end = arguments[2];
+ var relativeEnd = end === undefined ? len : end >> 0;
+ var f = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);
+
+ while (k < f) {
+ O[k] = value;
+ k++;
+ }
+ return O;
+ } });
+}
+if (!Array.prototype.copyWithin) {
+ Object.defineProperty(Array.prototype, 'copyWithin', { value: function(target, start/*, end*/) {
+ if (this === null || this === undefined) {
+ throw new TypeError('this is null or not defined');
+ }
+ var O = Object(this);
+ var len = O.length >>> 0;
+ var relativeTarget = target >> 0;
+ var to = relativeTarget < 0 ? Math.max(len + relativeTarget, 0) : Math.min(relativeTarget, len);
+ var relativeStart = start >> 0;
+ var from = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
+ var end = arguments[2];
+ var relativeEnd = end === undefined ? len : end >> 0;
+ var f = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);
+ var count = Math.min(f - from, len - to);
+ var direction = 1;
+ if (from < to && to < (from + count)) {
+ direction = -1;
+ from += count - 1;
+ to += count - 1;
+ }
+ while (count > 0) {
+ if (from in O) {
+ O[to] = O[from];
+ }
+ else {
+ delete O[to];
+ }
+ from += direction;
+ to += direction;
+ count--;
+ }
+ return O;
+ } });
+}
+if (!Array.from) {
+ Object.defineProperty(Array, 'from', { value: (function() {
+ var toStr = Object.prototype.toString;
+ var isCallable = function(fn) {
+ return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
+ };
+ var toInteger = function(value) {
+ var number = Number(value);
+ if (isNaN(number)) { return 0; }
+ if (number === 0 || !isFinite(number)) { return number; }
+ return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
+ };
+ var maxSafeInteger = Math.pow(2, 53) - 1;
+ var toLength = function(value) {
+ var len = toInteger(value);
+ return Math.min(Math.max(len, 0), maxSafeInteger);
+ };
+
+ return function(arrayLike/*, mapFn, thisArg */) {
+ var C = this;
+ var items = Object(arrayLike);
+ if (arrayLike === null || arrayLike === undefined) {
+ throw new TypeError("Array.from requires an array-like object - not null or undefined");
+ }
+ var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
+ var T;
+ if (typeof mapFn !== 'undefined') {
+ if (!isCallable(mapFn)) {
+ throw new TypeError('Array.from: when provided, the second argument must be a function');
+ }
+ if (arguments.length > 2) {
+ T = arguments[2];
+ }
+ }
+ var len = toLength(items.length);
+ var A = isCallable(C) ? Object(new C(len)) : new Array(len);
+ var k = 0;
+ var kValue;
+ while (k < len) {
+ kValue = items[k];
+ if (mapFn) {
+ A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
+ }
+ else {
+ A[k] = kValue;
+ }
+ k += 1;
+ }
+ A.length = len;
+ return A;
+ };
+ }()) });
+}
+if (!Array.of) {
+ Object.defineProperty(Array, 'of', { value: function() {
+ return Array.prototype.slice.call(arguments);
+ } });
+}
+/* String */
+if (!String.prototype.startsWith) {
+ Object.defineProperty(String.prototype, 'startsWith', { value: function(searchString, position){
+ position = position || 0;
+ return this.substr(position, searchString.length) === searchString;
+ } });
+}
+if (!String.prototype.endsWith) {
+ Object.defineProperty(String.prototype, 'endsWith', { value: function(searchString, position) {
+ var subjectString = this.toString();
+ if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {
+ position = subjectString.length;
+ }
+ position -= searchString.length;
+ var lastIndex = subjectString.indexOf(searchString, position);
+ return lastIndex !== -1 && lastIndex === position;
+ } });
+}
+if (!String.prototype.includes) {
+ Object.defineProperty(String.prototype, 'includes', { value: function() {
+ if (typeof arguments[1] === "number") {
+ if (this.length < arguments[0].length + arguments[1].length) {
+ return false;
+ }
+ else {
+ return this.substr(arguments[1], arguments[0].length) === arguments[0];
+ }
+ }
+ else {
+ return String.prototype.indexOf.apply(this, arguments) !== -1;
+ }
+ } });
+}
+if (!String.prototype.repeat) {
+ Object.defineProperty(String.prototype, 'repeat', { value: function(count) {
+ var str = this.toString();
+ count = +count;
+ if (count !== count) {
+ count = 0;
+ }
+ if (count < 0) {
+ throw new RangeError('repeat count must be non-negative');
+ }
+ if (count === Infinity) {
+ throw new RangeError('repeat count must be less than infinity');
+ }
+ count = Math.floor(count);
+ if (str.length === 0 || count === 0) {
+ return '';
+ }
+ // Ensuring count is a 31-bit integer allows us to heavily optimize the
+ // main part. But anyway, most current (August 2014) browsers can't handle
+ // strings 1 << 28 chars or longer, so:
+ if (str.length * count >= 1 << 28) {
+ throw new RangeError('repeat count must not overflow maximum string size');
+ }
+ var rpt = '';
+ for (;;) {
+ if ((count & 1) === 1) {
+ rpt += str;
+ }
+ count >>>= 1;
+ if (count === 0) {
+ break;
+ }
+ str += str;
+ }
+ // Could we try:
+ // return Array(count + 1).join(this);
+ return rpt;
+ } });
+}
+if (!String.prototype.trim) {
+ Object.defineProperty(String.prototype, 'trim', { value: function() {
+ return this.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
+ } });
+}
+if (!String.prototype.trimLeft) {
+ Object.defineProperty(String.prototype, 'trimLeft', { value: function() {
+ return this.toString().replace(/^[\s\xa0]+/, '');
+ } });
+}
+if (!String.prototype.trimRight) {
+ Object.defineProperty(String.prototype, 'trimRight', { value: function() {
+ return this.toString().replace(/[\s\xa0]+$/, '');
+ } });
+}
+/* Object */
+if (!Object.keys) {
+ Object.defineProperty(Object, 'keys', { value: (function () {
+ var hasOwnProperty = Object.prototype.hasOwnProperty,
+ hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
+ dontEnums = [
+ 'toString',
+ 'toLocaleString',
+ 'valueOf',
+ 'hasOwnProperty',
+ 'isPrototypeOf',
+ 'propertyIsEnumerable',
+ 'constructor'
+ ],
+ dontEnumsLength = dontEnums.length;
+ return function (obj) {
+ if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) {
+ throw new TypeError('Object.keys called on non-object');
+ }
+ var result = [];
+ for (var prop in obj) {
+ if (hasOwnProperty.call(obj, prop)) {
+ result.push(prop);
+ }
+ }
+ if (hasDontEnumBug) {
+ for (var i=0; i < dontEnumsLength; i++) {
+ if (hasOwnProperty.call(obj, dontEnums[i])) {
+ result.push(dontEnums[i]);
+ }
+ }
+ }
+ return result;
+ };
+ })() });
+}
+/* Generic methods */
+var generic = global.hprose.generic;
+
+function genericMethods(obj, properties) {
+ var proto = obj.prototype;
+ for (var i = 0, len = properties.length; i < len; i++) {
+ var property = properties[i];
+ var method = proto[property];
+ if (typeof method === 'function' && typeof obj[property] === 'undefined') {
+ Object.defineProperty(obj, property, { value: generic(method) });
+ }
+ }
+}
+genericMethods(Array, [
+ "pop",
+ "push",
+ "reverse",
+ "shift",
+ "sort",
+ "splice",
+ "unshift",
+ "concat",
+ "join",
+ "slice",
+ "indexOf",
+ "lastIndexOf",
+ "filter",
+ "forEach",
+ "every",
+ "map",
+ "some",
+ "reduce",
+ "reduceRight",
+ "includes",
+ "find",
+ "findIndex"
+]);
+genericMethods(String, [
+ 'quote',
+ 'substring',
+ 'toLowerCase',
+ 'toUpperCase',
+ 'charAt',
+ 'charCodeAt',
+ 'indexOf',
+ 'lastIndexOf',
+ 'include',
+ 'startsWith',
+ 'endsWith',
+ 'repeat',
+ 'trim',
+ 'trimLeft',
+ 'trimRight',
+ 'toLocaleLowerCase',
+ 'toLocaleUpperCase',
+ 'match',
+ 'search',
+ 'replace',
+ 'split',
+ 'substr',
+ 'concat',
+ 'slice'
+]);
diff --git a/lib/common/ResultMode.js b/lib/common/ResultMode.js
index 353c83c..1e49aa9 100644
--- a/lib/common/ResultMode.js
+++ b/lib/common/ResultMode.js
@@ -13,12 +13,11 @@
* *
* Hprose ResultMode for Node.js. *
* *
- * LastModified: May 15, 2015 *
+ * LastModified: Mar 3, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true */
'use strict';
global.hprose.ResultMode = {
diff --git a/lib/common/isError.js b/lib/common/isError.js
new file mode 100644
index 0000000..caacea7
--- /dev/null
+++ b/lib/common/isError.js
@@ -0,0 +1,41 @@
+/**********************************************************\
+| |
+| hprose |
+| |
+| Official WebSite: http://www.hprose.com/ |
+| http://www.hprose.org/ |
+| |
+\**********************************************************/
+
+/**********************************************************\
+ * *
+ * hprose/common/isError.js *
+ * *
+ * isError for Node.js. *
+ * *
+ * LastModified: Sep 11, 2015 *
+ * Author: Ma Bingyao *
+ * *
+\**********************************************************/
+
+var objectToString = Object.prototype.toString;
+var getPrototypeOf = Object.getPrototypeOf;
+var ERROR_TYPE = '[object Error]';
+
+function isError(err) {
+ if (err instanceof Error) {
+ return true;
+ }
+ if (typeof err !== 'object') {
+ return false;
+ }
+ while (err) {
+ if (objectToString.call(err) === ERROR_TYPE) {
+ return true;
+ }
+ err = getPrototypeOf(err);
+ }
+ return false;
+}
+
+module.exports = isError;
diff --git a/lib/common/setImmediate.js b/lib/common/setImmediate.js
deleted file mode 100644
index 6fe032d..0000000
--- a/lib/common/setImmediate.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/**********************************************************\
-| |
-| hprose |
-| |
-| Official WebSite: http://www.hprose.com/ |
-| http://www.hprose.org/ |
-| |
-\**********************************************************/
-
-/**********************************************************\
- * *
- * hprose/common/setImmediate.js *
- * *
- * setImmediate for Node.js. *
- * *
- * LastModified: Jul 19, 2015 *
- * Author: Ma Bingyao *
- * *
-\**********************************************************/
-
-/*jshint node:true, eqeqeq:true */
-'use strict';
-
-if (global.setImmediate) return;
-
-var slice = Function.prototype.call.bind(Array.prototype.slice);
-var nextId = 1;
-var tasks = {};
-var lock = false;
-
-function wrap(handler) {
- var args = slice(arguments, 1);
- return function() {
- handler.apply(undefined, args);
- };
-}
-
-function run(handleId) {
- if (lock) {
- global.setTimeout(wrap(run, handleId), 0);
- }
- else {
- var task = tasks[handleId];
- if (task) {
- lock = true;
- try {
- task();
- }
- finally {
- clear(handleId);
- lock = false;
- }
- }
- }
-}
-
-function create(args) {
- tasks[nextId] = wrap.apply(undefined, args);
- return nextId++;
-}
-
-function clear(handleId) {
- delete tasks[handleId];
-}
-
-global.setImmediate = function() {
- var handleId = create(arguments);
- global.process.nextTick( wrap( run, handleId ) );
- return handleId;
-};
-
-global.clearImmediate = clear;
diff --git a/lib/filter/JSONRPCClientFilter.js b/lib/filter/JSONRPCClientFilter.js
index fccde74..79d9ca4 100644
--- a/lib/filter/JSONRPCClientFilter.js
+++ b/lib/filter/JSONRPCClientFilter.js
@@ -13,18 +13,18 @@
* *
* jsonrpc client filter for Node.js. *
* *
- * LastModified: Jul 17, 2015 *
+ * LastModified: Mar 3, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var Tags = global.hprose.Tags;
var BytesIO = global.hprose.BytesIO;
var Writer = global.hprose.Writer;
var Reader = global.hprose.Reader;
+var JSON = global.JSON;
var s_id = 1;
@@ -32,7 +32,7 @@ function JSONRPCClientFilter(version) {
this.version = version || '2.0';
}
-JSONRPCClientFilter.prototype.inputFilter = function inputFilter(data, context) {
+JSONRPCClientFilter.prototype.inputFilter = function inputFilter(data/*, context*/) {
var json = BytesIO.toString(data);
if (json.charAt(0) === '{') {
json = '[' + json + ']';
@@ -55,7 +55,7 @@ JSONRPCClientFilter.prototype.inputFilter = function inputFilter(data, context)
return stream.bytes;
};
-JSONRPCClientFilter.prototype.outputFilter = function outputFilter(data, context) {
+JSONRPCClientFilter.prototype.outputFilter = function outputFilter(data/*, context*/) {
var requests = [];
var stream = new BytesIO(data);
var reader = new Reader(stream, false, false);
diff --git a/lib/filter/JSONRPCServiceFilter.js b/lib/filter/JSONRPCServiceFilter.js
index d966687..02e6148 100644
--- a/lib/filter/JSONRPCServiceFilter.js
+++ b/lib/filter/JSONRPCServiceFilter.js
@@ -13,18 +13,18 @@
* *
* jsonrpc service filter for Node.js. *
* *
- * LastModified: May 21, 2015 *
+ * LastModified: Mar 3, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var Tags = global.hprose.Tags;
var BytesIO = global.hprose.BytesIO;
var Writer = global.hprose.Writer;
var Reader = global.hprose.Reader;
+var JSON = global.JSON;
var leftbrace = 0x7B; // '{'
var leftbracket = 0x5B; // '['
diff --git a/lib/hprose.js b/lib/hprose.js
index 0e1d19d..d7bdfb7 100644
--- a/lib/hprose.js
+++ b/lib/hprose.js
@@ -13,18 +13,18 @@
* *
* hprose for Node.js. *
* *
- * LastModified: Jun 22, 2015 *
+ * LastModified: Sep 30, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
global.hprose = global.hprose || Object.create(null);
+require('./common/Helper.js');
+require('./common/Polyfill.js');
require('./common/HarmonyMaps.js');
-require('./common/setImmediate.js');
require('./common/Future.js');
require('./common/ResultMode.js');
@@ -52,6 +52,8 @@ require('./server/Server.js');
require('./filter/JSONRPCClientFilter.js');
require('./filter/JSONRPCServiceFilter.js');
+require('./utils/regenerator-runtime.js');
+
global.HproseCompleter = global.hprose.Completer;
global.HproseFuture = global.hprose.Future;
global.HproseResultMode = global.hprose.ResultMode;
diff --git a/lib/io/BytesIO.js b/lib/io/BytesIO.js
index 53e7b7b..381ff99 100644
--- a/lib/io/BytesIO.js
+++ b/lib/io/BytesIO.js
@@ -13,31 +13,31 @@
* *
* Hprose BytesIO for Node.js. *
* *
- * LastModified: Aug 21, 2015 *
+ * LastModified: Oct 23, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
+var toBinaryString = global.hprose.toBinaryString;
+
var _EMPTY_BYTES = new Uint8Array(0);
var _INIT_SIZE = 1024;
-var indexof = Function.prototype.call.bind(Array.prototype.indexOf);
function writeInt32BE(bytes, p, i) {
- bytes[p++] = i >>> 24 & 0xff;
- bytes[p++] = i >>> 16 & 0xff;
- bytes[p++] = i >>> 8 & 0xff;
- bytes[p++] = i & 0xff;
+ bytes[p++] = i >>> 24 & 0xFF;
+ bytes[p++] = i >>> 16 & 0xFF;
+ bytes[p++] = i >>> 8 & 0xFF;
+ bytes[p++] = i & 0xFF;
return p;
}
function writeInt32LE(bytes, p, i) {
- bytes[p++] = i & 0xff;
- bytes[p++] = i >>> 8 & 0xff;
- bytes[p++] = i >>> 16 & 0xff;
- bytes[p++] = i >>> 24 & 0xff;
+ bytes[p++] = i & 0xFF;
+ bytes[p++] = i >>> 8 & 0xFF;
+ bytes[p++] = i >>> 16 & 0xFF;
+ bytes[p++] = i >>> 24 & 0xFF;
return p;
}
@@ -52,7 +52,7 @@ function writeString(bytes, p, str) {
bytes[p++] = 0xC0 | (codeUnit >> 6);
bytes[p++] = 0x80 | (codeUnit & 0x3F);
}
- else if (codeUnit < 0xD800 || codeUnit > 0xDfff) {
+ else if (codeUnit < 0xD800 || codeUnit > 0xDFFF) {
bytes[p++] = 0xE0 | (codeUnit >> 12);
bytes[p++] = 0x80 | ((codeUnit >> 6) & 0x3F);
bytes[p++] = 0x80 | (codeUnit & 0x3F);
@@ -97,21 +97,17 @@ function readShortString(bytes, n) {
if (off < len) {
charCodes[i] = ((unit & 0x1F) << 6) |
(bytes[off++] & 0x3F);
+ break;
}
- else {
- throw new Error('Unfinished UTF-8 octet sequence');
- }
- break;
+ throw new Error('Unfinished UTF-8 octet sequence');
case 14:
if (off + 1 < len) {
charCodes[i] = ((unit & 0x0F) << 12) |
((bytes[off++] & 0x3F) << 6) |
(bytes[off++] & 0x3F);
+ break;
}
- else {
- throw new Error('Unfinished UTF-8 octet sequence');
- }
- break;
+ throw new Error('Unfinished UTF-8 octet sequence');
case 15:
if (off + 2 < len) {
var rune = (((unit & 0x07) << 18) |
@@ -121,15 +117,11 @@ function readShortString(bytes, n) {
if (0 <= rune && rune <= 0xFFFFF) {
charCodes[i++] = (((rune >> 10) & 0x03FF) | 0xD800);
charCodes[i] = ((rune & 0x03FF) | 0xDC00);
+ break;
}
- else {
- throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16));
- }
- }
- else {
- throw new Error('Unfinished UTF-8 octet sequence');
+ throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16));
}
- break;
+ throw new Error('Unfinished UTF-8 octet sequence');
default:
throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16));
}
@@ -142,7 +134,7 @@ function readShortString(bytes, n) {
function readLongString(bytes, n) {
var buf = [];
- var charCodes = new Uint16Array(0xffff);
+ var charCodes = new Uint16Array(0x8000);
var i = 0, off = 0;
for (var len = bytes.length; i < n && off < len; i++) {
var unit = bytes[off++];
@@ -162,21 +154,17 @@ function readLongString(bytes, n) {
if (off < len) {
charCodes[i] = ((unit & 0x1F) << 6) |
(bytes[off++] & 0x3F);
+ break;
}
- else {
- throw new Error('Unfinished UTF-8 octet sequence');
- }
- break;
+ throw new Error('Unfinished UTF-8 octet sequence');
case 14:
if (off + 1 < len) {
charCodes[i] = ((unit & 0x0F) << 12) |
((bytes[off++] & 0x3F) << 6) |
(bytes[off++] & 0x3F);
+ break;
}
- else {
- throw new Error('Unfinished UTF-8 octet sequence');
- }
- break;
+ throw new Error('Unfinished UTF-8 octet sequence');
case 15:
if (off + 2 < len) {
var rune = (((unit & 0x07) << 18) |
@@ -186,19 +174,15 @@ function readLongString(bytes, n) {
if (0 <= rune && rune <= 0xFFFFF) {
charCodes[i++] = (((rune >> 10) & 0x03FF) | 0xD800);
charCodes[i] = ((rune & 0x03FF) | 0xDC00);
+ break;
}
- else {
- throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16));
- }
- }
- else {
- throw new Error('Unfinished UTF-8 octet sequence');
+ throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16));
}
- break;
+ throw new Error('Unfinished UTF-8 octet sequence');
default:
throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16));
}
- if (i >= 65534) {
+ if (i >= 0x7FFF - 1) {
var size = i + 1;
buf.push(String.fromCharCode.apply(String, charCodes.subarray(0, size)));
n -= size;
@@ -212,16 +196,16 @@ function readLongString(bytes, n) {
}
function readString(bytes, n) {
- if (n === undefined || n === null || (n < 0)) n = bytes.length;
- if (n === 0) return ['', 0];
- return ((n < 100000) ?
+ if (n === undefined || n === null || (n < 0)) { n = bytes.length; }
+ if (n === 0) { return ['', 0]; }
+ return ((n < 0xFFFF) ?
readShortString(bytes, n) :
readLongString(bytes, n));
}
function readStringAsBytes(bytes, n) {
- if (n === undefined) n = bytes.length;
- if (n === 0) return _EMPTY_BYTES;
+ if (n === undefined) { n = bytes.length; }
+ if (n === 0) { return [_EMPTY_BYTES, 0]; }
var i = 0, off = 0;
for (var len = bytes.length; i < n && off < len; i++) {
var unit = bytes[off++];
@@ -239,19 +223,15 @@ function readStringAsBytes(bytes, n) {
case 13:
if (off < len) {
off++;
+ break;
}
- else {
- throw new Error('Unfinished UTF-8 octet sequence');
- }
- break;
+ throw new Error('Unfinished UTF-8 octet sequence');
case 14:
if (off + 1 < len) {
off += 2;
+ break;
}
- else {
- throw new Error('Unfinished UTF-8 octet sequence');
- }
- break;
+ throw new Error('Unfinished UTF-8 octet sequence');
case 15:
if (off + 2 < len) {
var rune = (((unit & 0x07) << 18) |
@@ -260,15 +240,11 @@ function readStringAsBytes(bytes, n) {
(bytes[off++] & 0x3F)) - 0x10000;
if (0 <= rune && rune <= 0xFFFFF) {
i++;
+ break;
}
- else {
- throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16));
- }
- }
- else {
- throw new Error('Unfinished UTF-8 octet sequence');
+ throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16));
}
- break;
+ throw new Error('Unfinished UTF-8 octet sequence');
default:
throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16));
}
@@ -385,9 +361,9 @@ Object.defineProperties(BytesIO.prototype, {
throw new TypeError('value is out of bounds');
} },
writeUInt32BE: { value: function(i) {
- if ((i === (i | 0)) && (i >= 0)) {
+ if (((i & 0x7FFFFFFF) + 0x80000000 === i) && (i >= 0)) {
this._grow(4);
- this._length = writeInt32BE(this._bytes, this._length, i);
+ this._length = writeInt32BE(this._bytes, this._length, i | 0);
return;
}
throw new TypeError('value is out of bounds');
@@ -401,16 +377,16 @@ Object.defineProperties(BytesIO.prototype, {
throw new TypeError('value is out of bounds');
} },
writeUInt32LE: { value: function(i) {
- if ((i === (i | 0)) && (i >= 0)) {
+ if (((i & 0x7FFFFFFF) + 0x80000000 === i) && (i >= 0)) {
this._grow(4);
- this._length = writeInt32LE(this._bytes, this._length, i);
+ this._length = writeInt32LE(this._bytes, this._length, i | 0);
return;
}
throw new TypeError('value is out of bounds');
} },
write: { value: function(data) {
var n = data.byteLength || data.length;
- if (n === 0) return;
+ if (n === 0) { return; }
this._grow(n);
var bytes = this._bytes;
var length = this._length;
@@ -434,7 +410,7 @@ Object.defineProperties(BytesIO.prototype, {
} },
writeAsciiString: { value: function(str) {
var n = str.length;
- if (n === 0) return;
+ if (n === 0) { return; }
this._grow(n);
var bytes = this._bytes;
var l = this._length;
@@ -445,7 +421,7 @@ Object.defineProperties(BytesIO.prototype, {
} },
writeString: { value: function(str) {
var n = str.length;
- if (n === 0) return;
+ if (n === 0) { return; }
// A single code unit uses at most 3 bytes.
// Two code units at most 4.
this._grow(n * 3);
@@ -473,7 +449,7 @@ Object.defineProperties(BytesIO.prototype, {
readUInt32BE: { value: function() {
var value = this.readInt32BE();
if (value < 0) {
- return (value & 0x7fffffff) + 0x80000000;
+ return (value & 0x7FFFFFFF) + 0x80000000;
}
return value;
} },
@@ -493,7 +469,7 @@ Object.defineProperties(BytesIO.prototype, {
readUInt32LE: { value: function() {
var value = this.readInt32LE();
if (value < 0) {
- return (value & 0x7fffffff) + 0x80000000;
+ return (value & 0x7FFFFFFF) + 0x80000000;
}
return value;
} },
@@ -501,7 +477,7 @@ Object.defineProperties(BytesIO.prototype, {
if (this._off + n > this._length) {
n = this._length - this._off;
}
- if (n === 0) return _EMPTY_BYTES;
+ if (n === 0) { return _EMPTY_BYTES; }
return this._bytes.subarray(this._off, this._off += n);
} },
skip: { value: function(n) {
@@ -516,7 +492,7 @@ Object.defineProperties(BytesIO.prototype, {
} },
// the result is an Uint8Array, and includes tag.
readBytes: { value: function(tag) {
- var pos = indexof(this._bytes, tag, this._off);
+ var pos = Array.indexOf(this._bytes, tag, this._off);
var buf;
if (pos === -1) {
buf = this._bytes.subarray(this._off, this._length);
@@ -531,7 +507,7 @@ Object.defineProperties(BytesIO.prototype, {
// the result is a String, and doesn't include tag.
// but the position is the same as readBytes
readUntil: { value: function(tag) {
- var pos = indexof(this._bytes, tag, this._off);
+ var pos = Array.indexOf(this._bytes, tag, this._off);
var str = '';
if (pos === this._off) {
this._off++;
@@ -550,21 +526,8 @@ Object.defineProperties(BytesIO.prototype, {
if (this._off + n > this._length) {
n = this._length - this._off;
}
- if (n === 0) return '';
- var bytes = this._bytes.subarray(this._off, this._off += n);
- if (n < 100000) {
- return String.fromCharCode.apply(String, bytes);
- }
- var remain = n & 0xffff;
- var count = n >> 16;
- var a = new Array(remain ? count + 1 : count);
- for (var i = 0; i < count; ++i) {
- a[i] = String.fromCharCode.apply(String, bytes.subarray(i << 16, (i + 1) << 16));
- }
- if (remain) {
- a[count] = String.fromCharCode.apply(String, bytes.subarray(count << 16, n));
- }
- return a.join('');
+ if (n === 0) { return ''; }
+ return toBinaryString(this._bytes.subarray(this._off, this._off += n));
} },
// n is the UTF16 length
readStringAsBytes: { value: function(n) {
@@ -615,7 +578,7 @@ Object.defineProperties(BytesIO.prototype, {
function toString(data) {
/* jshint -W086 */
- if (data.length === 0) return '';
+ if (data.length === 0) { return ''; }
switch(data.constructor) {
case String: return data;
case Buffer: return data.toString();
diff --git a/lib/io/ClassManager.js b/lib/io/ClassManager.js
index 042d538..a237588 100644
--- a/lib/io/ClassManager.js
+++ b/lib/io/ClassManager.js
@@ -13,12 +13,11 @@
* *
* hprose ClassManager for Node.js. *
* *
- * LastModified: May 15, 2015 *
+ * LastModified: Mar 3, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var WeakMap = global.WeakMap;
diff --git a/lib/io/Formatter.js b/lib/io/Formatter.js
index 271ddb2..00fb11a 100644
--- a/lib/io/Formatter.js
+++ b/lib/io/Formatter.js
@@ -13,12 +13,11 @@
* *
* Hprose Formatter for Node.js. *
* *
- * LastModified: May 15, 2015 *
+ * LastModified: Mar 3, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var BytesIO = global.hprose.BytesIO;
diff --git a/lib/io/Reader.js b/lib/io/Reader.js
index 5422ab6..9755aff 100644
--- a/lib/io/Reader.js
+++ b/lib/io/Reader.js
@@ -13,13 +13,11 @@
* *
* Hprose Reader for Node.js. *
* *
- * LastModified: Aug 3, 2015 *
+ * LastModified: Mar 3, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
-/*jshint unused:false */
'use strict';
var Map = global.Map;
@@ -656,12 +654,12 @@ Reader.prototype.constructor = Reader;
Object.defineProperties(Reader.prototype, {
useHarmonyMap: { value: false, writable: true },
checkTag: { value: function(expectTag, tag) {
- if (tag === undefined) tag = this.stream.readByte();
- if (tag !== expectTag) unexpectedTag(tag, expectTag);
+ if (tag === undefined) { tag = this.stream.readByte(); }
+ if (tag !== expectTag) { unexpectedTag(tag, expectTag); }
} },
checkTags: { value: function(expectTags, tag) {
- if (tag === undefined) tag = this.stream.readByte();
- if (expectTags.indexOf(tag) >= 0) return tag;
+ if (tag === undefined) { tag = this.stream.readByte(); }
+ if (expectTags.indexOf(tag) >= 0) { return tag; }
unexpectedTag(tag, expectTags);
} },
unserialize: { value: function() {
diff --git a/lib/io/Tags.js b/lib/io/Tags.js
index a00bb62..73ff467 100644
--- a/lib/io/Tags.js
+++ b/lib/io/Tags.js
@@ -13,12 +13,11 @@
* *
* Hprose Tags for Node.js. *
* *
- * LastModified: May 15, 2015 *
+ * LastModified: Mar 3, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true */
'use strict';
global.hprose.Tags = {
diff --git a/lib/io/Writer.js b/lib/io/Writer.js
index 284e0e7..b881e7c 100644
--- a/lib/io/Writer.js
+++ b/lib/io/Writer.js
@@ -13,15 +13,13 @@
* *
* Hprose Writer for Node.js. *
* *
- * LastModified: Aug 2, 2015 *
+ * LastModified: Feb 13, 2017 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true, unused:false */
'use strict';
-var util = require('util');
var Map = global.Map;
var BytesIO = global.hprose.BytesIO;
var Tags = global.hprose.Tags;
@@ -29,8 +27,11 @@ var ClassManager = global.hprose.ClassManager;
function getClassName(obj) {
var cls = obj.constructor;
+ if (!cls) {
+ return 'Object';
+ }
var classname = ClassManager.getClassAlias(cls);
- if (classname) return classname;
+ if (classname) { return classname; }
if (cls.name) {
classname = cls.name;
}
@@ -125,12 +126,16 @@ function serialize(writer, value) {
case Date:
writer.writeDateWithRef(value);
return;
+ case Array:
+ writer.writeListWithRef(value);
+ return;
case Map:
writer.writeMapWithRef(value);
return;
case ArrayBuffer:
case Uint8Array:
case BytesIO:
+ case Buffer:
writer.writeBytesWithRef(value);
return;
case Int8Array:
@@ -145,12 +150,9 @@ function serialize(writer, value) {
writeDoubleListWithRef(writer, value);
return;
default:
- if (util.isArray(value)) {
+ if (Array.isArray(value)) {
writer.writeListWithRef(value);
}
- else if (util.isDate(value)) {
- writer.writeDateWithRef(value);
- }
else if (Buffer.isBuffer(value)) {
writer.writeBytesWithRef(value);
}
@@ -309,9 +311,14 @@ function writeBytes(writer, bytes) {
var stream = writer.stream;
stream.writeByte(Tags.TagBytes);
var n = bytes.byteLength || bytes.length;
- if (n > 0) stream.writeAsciiString('' + n);
- stream.writeByte(Tags.TagQuote);
- if (n > 0) stream.write(bytes);
+ if (n > 0) {
+ stream.writeAsciiString('' + n);
+ stream.writeByte(Tags.TagQuote);
+ stream.write(bytes);
+ }
+ else {
+ stream.writeByte(Tags.TagQuote);
+ }
stream.writeByte(Tags.TagQuote);
}
@@ -320,9 +327,14 @@ function writeString(writer, str) {
var stream = writer.stream;
var n = str.length;
stream.writeByte(Tags.TagString);
- if (n > 0) stream.writeAsciiString('' + n);
- stream.writeByte(Tags.TagQuote);
- if (n > 0) stream.writeString(str);
+ if (n > 0) {
+ stream.writeAsciiString('' + n);
+ stream.writeByte(Tags.TagQuote);
+ stream.writeString(str);
+ }
+ else {
+ stream.writeByte(Tags.TagQuote);
+ }
stream.writeByte(Tags.TagQuote);
}
@@ -331,10 +343,15 @@ function writeArray(writer, array, writeElem) {
var stream = writer.stream;
var n = array.length;
stream.writeByte(Tags.TagList);
- if (n > 0) stream.writeAsciiString('' + n);
- stream.writeByte(Tags.TagOpenbrace);
- for (var i = 0; i < n; i++) {
- writeElem(writer, array[i]);
+ if (n > 0) {
+ stream.writeAsciiString('' + n);
+ stream.writeByte(Tags.TagOpenbrace);
+ for (var i = 0; i < n; i++) {
+ writeElem(writer, array[i]);
+ }
+ }
+ else {
+ stream.writeByte(Tags.TagOpenbrace);
}
stream.writeByte(Tags.TagClosebrace);
}
@@ -363,11 +380,16 @@ function writeMap(writer, map) {
}
var n = fields.length;
stream.writeByte(Tags.TagMap);
- if (n > 0) stream.writeAsciiString('' + n);
- stream.writeByte(Tags.TagOpenbrace);
- for (var i = 0; i < n; i++) {
- serialize(writer, fields[i]);
- serialize(writer, map[fields[i]]);
+ if (n > 0) {
+ stream.writeAsciiString('' + n);
+ stream.writeByte(Tags.TagOpenbrace);
+ for (var i = 0; i < n; i++) {
+ serialize(writer, fields[i]);
+ serialize(writer, map[fields[i]]);
+ }
+ }
+ else {
+ stream.writeByte(Tags.TagOpenbrace);
}
stream.writeByte(Tags.TagClosebrace);
}
@@ -377,12 +399,17 @@ function writeHarmonyMap(writer, map) {
var stream = writer.stream;
var n = map.size;
stream.writeByte(Tags.TagMap);
- if (n > 0) stream.writeAsciiString('' + n);
- stream.writeByte(Tags.TagOpenbrace);
- map.forEach(function(value, key) {
- serialize(writer, key);
- serialize(writer, value);
- });
+ if (n > 0) {
+ stream.writeAsciiString('' + n);
+ stream.writeByte(Tags.TagOpenbrace);
+ map.forEach(function(value, key) {
+ serialize(writer, key);
+ serialize(writer, value);
+ });
+ }
+ else {
+ stream.writeByte(Tags.TagOpenbrace);
+ }
stream.writeByte(Tags.TagClosebrace);
}
@@ -423,10 +450,15 @@ function writeClass(writer, classname, fields) {
stream.writeByte(Tags.TagQuote);
stream.writeString(classname);
stream.writeByte(Tags.TagQuote);
- if (n > 0) stream.writeAsciiString('' + n);
- stream.writeByte(Tags.TagOpenbrace);
- for (var i = 0; i < n; i++) {
- writeString(writer, fields[i]);
+ if (n > 0) {
+ stream.writeAsciiString('' + n);
+ stream.writeByte(Tags.TagOpenbrace);
+ for (var i = 0; i < n; i++) {
+ writeString(writer, fields[i]);
+ }
+ }
+ else {
+ stream.writeByte(Tags.TagOpenbrace);
}
stream.writeByte(Tags.TagClosebrace);
var index = writer._fieldsref.length;
diff --git a/lib/server/HttpServer.js b/lib/server/HttpServer.js
index 5334b5c..fd030d4 100644
--- a/lib/server/HttpServer.js
+++ b/lib/server/HttpServer.js
@@ -13,12 +13,11 @@
* *
* Hprose Http Server for Node.js. *
* *
- * LastModified: Aug 9, 2015 *
+ * LastModified: Mar 3, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var util = require('util');
diff --git a/lib/server/HttpService.js b/lib/server/HttpService.js
index bf8626b..54920e4 100644
--- a/lib/server/HttpService.js
+++ b/lib/server/HttpService.js
@@ -13,12 +13,11 @@
* *
* Hprose Http Service for Node.js. *
* *
- * LastModified: Aug 10, 2015 *
+ * LastModified: Jun 6, 2018 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var fs = require('fs');
@@ -100,6 +99,7 @@ function HttpService() {
function sendHeader(context) {
var resp = context.response;
+ resp.statusCode = 200;
resp.setHeader('Content-Type', 'text/plain');
if (_P3P) {
resp.setHeader('P3P',
@@ -178,7 +178,7 @@ function HttpService() {
function setCrossDomainXmlContent(value) {
_crossDomainXmlFile = null;
- if (typeof(value) === 'string') value = new Buffer(value);
+ if (typeof(value) === 'string') { value = new Buffer(value); }
_crossDomainXmlContent = value;
}
@@ -197,7 +197,7 @@ function HttpService() {
function setClientAccessPolicyXmlContent(value) {
_clientAccessPolicyXmlFile = null;
- if (typeof(value) === 'string') value = new Buffer(value);
+ if (typeof(value) === 'string') { value = new Buffer(value); }
_clientAccessPolicyXmlContent = value;
}
@@ -226,15 +226,17 @@ function HttpService() {
};
request.socket.setTimeout(self.timeout);
var bytes = new BytesIO();
+ var done = new Future();
request.on('data', function(data) { bytes.write(data); });
request.on('end', function() {
- if (_clientAccessPolicyXmlContent !== null && clientAccessPolicyXmlHandler(request, response)) return;
- if (_crossDomainXmlContent !== null && crossDomainXmlHandler(request, response)) return;
+ if (_clientAccessPolicyXmlContent !== null && clientAccessPolicyXmlHandler(request, response)) { return; }
+ if (_crossDomainXmlContent !== null && crossDomainXmlHandler(request, response)) { return; }
try {
sendHeader(context);
}
catch (e) {
send(self.endError(e, context), response);
+ done.resolve(true);
return;
}
var result = '';
@@ -245,18 +247,20 @@ function HttpService() {
result = self.defaultHandle(bytes.bytes, context);
}
send(result, response);
+ done.resolve(result);
});
+ return done;
}
Object.defineProperties(this, {
onSendHeader: { get: getSendHeader, set: setSendHeader },
crossDomain: { get: isCrossDomainEnabled, set: setCrossDomainEnabled },
p3p: { get: isP3PEnabled, set: setP3PEnabled },
- get: { get: isGetEnabled, set: isGetEnabled },
+ get: { get: isGetEnabled, set: setGetEnabled },
crossDomainXmlFile: { get: getCrossDomainXmlFile, set: setCrossDomainXmlFile },
crossDomainXmlContent: { get: getCrossDomainXmlContent, set: setCrossDomainXmlContent },
- clientAccessPolicyXmlFile: { get: getClientAccessPolicyXmlFile, set: getClientAccessPolicyXmlFile },
- clientAccessPolicyXmlContent: { get: getClientAccessPolicyXmlContent, set: getClientAccessPolicyXmlContent },
+ clientAccessPolicyXmlFile: { get: getClientAccessPolicyXmlFile, set: setClientAccessPolicyXmlFile },
+ clientAccessPolicyXmlContent: { get: getClientAccessPolicyXmlContent, set: setClientAccessPolicyXmlContent },
addAccessControlAllowOrigin: { value: addAccessControlAllowOrigin },
removeAccessControlAllowOrigin: { value: removeAccessControlAllowOrigin },
handle: { value: handle }
diff --git a/lib/server/Server.js b/lib/server/Server.js
index 14802db..6b65c42 100644
--- a/lib/server/Server.js
+++ b/lib/server/Server.js
@@ -13,12 +13,11 @@
* *
* Hprose Server for Node.js. *
* *
- * LastModified: Jun 20, 2015 *
+ * LastModified: Aug 20, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var parse = require('url').parse;
@@ -26,14 +25,14 @@ var HttpServer = global.hprose.HttpServer;
var SocketServer = global.hprose.SocketServer;
var WebSocketServer = global.hprose.WebSocketServer;
-function create(uri, tlsOptions) {
+function create(uri, tlsOptions, handler) {
var parser = parse(uri);
var protocol = parser.protocol;
var options = {};
var port;
if (protocol === 'http:' ||
protocol === 'https:') {
- port = parseInt(parser.port);
+ port = parseInt(parser.port, 10);
if (!port) {
port = (protocol === 'http:' ? 80 : 443);
}
@@ -50,7 +49,7 @@ function create(uri, tlsOptions) {
options.host = parser.hostname;
}
if (parser.port) {
- options.port = parseInt(parser.port);
+ options.port = parseInt(parser.port, 10);
}
return new SocketServer(options, tlsOptions);
}
@@ -60,7 +59,7 @@ function create(uri, tlsOptions) {
}
if (protocol === 'ws:' ||
protocol === 'wss:') {
- port = parseInt(parser.port);
+ port = parseInt(parser.port, 10);
if (!port) {
port = (protocol === 'http:' ? 80 : 443);
}
@@ -69,13 +68,13 @@ function create(uri, tlsOptions) {
if (parser.path) {
options.path = parser.path;
}
- return new WebSocketServer(options, tlsOptions);
+ return new WebSocketServer(options, tlsOptions, handler);
}
throw new Error('The ' + protocol + ' server isn\'t implemented.');
}
-function Server(uri, tlsOptions) {
- return create(uri, tlsOptions);
+function Server(uri, tlsOptions, handler) {
+ return create(uri, tlsOptions, handler);
}
Object.defineProperty(Server, 'create', { value: create });
diff --git a/lib/server/Service.js b/lib/server/Service.js
index 4b90e12..35337a0 100644
--- a/lib/server/Service.js
+++ b/lib/server/Service.js
@@ -13,19 +13,19 @@
* *
* Hprose Service for Node.js. *
* *
- * LastModified: Aug 9, 2015 *
+ * LastModified: Apr 12, 2018 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var util = require('util');
var EventEmitter = require('events').EventEmitter;
+var isError = require('../common/isError');
var TimeoutError = require('../common/TimeoutError');
+var crypto = require('crypto');
-var setImmediate = global.setImmediate;
var Future = global.hprose.Future;
var ResultMode = global.hprose.ResultMode;
var Tags = global.hprose.Tags;
@@ -35,31 +35,42 @@ var Writer = global.hprose.Writer;
function callService(args, context) {
if (context.oneway) {
- setImmediate(function() {
- context.method.apply(context.scope, args);
+ process.nextTick(function() {
+ try {
+ Future.toPromise(context.method.apply(context.scope, args));
+ }
+ catch (e) {}
});
if (context.async) {
args[args.length - 1](null);
}
return null;
}
- return context.method.apply(context.scope, args);
+ return Future.toPromise(context.method.apply(context.scope, args));
}
function getFuncName(func, obj) {
var f = func.toString();
- var funcname = f.substr(0, f.indexOf('(')).replace(/(^\s*function\s*)|(\s*$)/ig, '');
+ var funcname = f.substr(0, f.indexOf('(')).replace(/(^\s*(async)?\s*function\*?\s*)|(\s*$)/ig, '');
if ((funcname === '') && obj) {
for (var name in obj) {
- if (obj[name] === func) return name;
+ if (obj[name] === func) { return name; }
}
}
return funcname;
}
-var nextid = 0;
function getNextId() {
- return (nextid < 0x7fffffff) ? ++nextid : nextid = 0;
+ var result = new Future();
+ crypto.randomBytes(16, function(err, buf) {
+ if (err) {
+ result.reject(err);
+ }
+ else {
+ result.resolve(buf.toString('hex'));
+ }
+ });
+ return result;
}
function Service() {
@@ -142,14 +153,14 @@ function Service() {
}
function sendError(error, context) {
- if (!util.isError(error)) {
+ if (!isError(error)) {
error = new Error(error);
}
try {
self.emit('sendError', error, context);
if (_onSendError !== null) {
var e = _onSendError(error, context);
- if (util.isError(e)) {
+ if (isError(e)) {
error = e;
}
}
@@ -175,17 +186,19 @@ function Service() {
self.emit('beforeInvoke', name, args, context.byref, context);
if (_onBeforeInvoke !== null) {
var value = _onBeforeInvoke(name, args, context.byref, context);
- if (util.isError(value)) throw value;
+ if (isError(value)) { throw value; }
if (Future.isPromise(value)) {
return value.then(function(e) {
- if (util.isError(e)) throw e;
+ if (isError(e)) { throw e; }
return invoke(name, args, context);
- }).catch(function(e) {
+ }).then(null, function(e) {
return sendError(e, context);
});
}
}
- return invoke(name, args, context);
+ return invoke(name, args, context).then(null, function(e) {
+ return sendError(e, context);
+ });
}
catch (e) {
return sendError(e, context);
@@ -202,33 +215,51 @@ function Service() {
}
if (context.async) {
return Future.promise(function(resolve, reject) {
- if (passContext) args.push(context);
- args.push(function(result) {
- if (util.isError(result)) {
- reject(result);
- }
- else {
- resolve(result);
+ if (passContext) { args.push(context); }
+ args.push(function() {
+ var args = arguments;
+ switch (args.length) {
+ case 0: resolve(undefined); break;
+ case 1: {
+ var result = args[0];
+ if (isError(result)) {
+ reject(result);
+ }
+ else {
+ resolve(result);
+ }
+ break;
+ }
+ default: {
+ var err = args[0];
+ var result = args[1];
+ if (err == null) {
+ resolve(result);
+ }
+ else if (isError(err)) {
+ reject(err);
+ }
+ else {
+ resolve(err);
+ }
+ break;
+ }
}
});
callService(args, context);
});
}
else {
- if (passContext) args.push(context);
- return callService(args, context);
+ if (passContext) { args.push(context); }
+ return Future.toPromise(callService(args, context));
}
}
function invoke(name, args, context) {
- var result = _invokeHandler(name, args, context);
- if (Future.isPromise(result)) {
- return result.then(function(result) {
- if (util.isError(result)) throw result;
- return afterInvoke(name, args, context, result);
- });
- }
- return afterInvoke(name, args, context, result);
+ return _invokeHandler(name, args, context).then(function(result) {
+ if (isError(result)) { throw result; }
+ return afterInvoke(name, args, context, result);
+ });
}
function afterInvoke(name, args, context, result) {
@@ -242,10 +273,10 @@ function Service() {
self.emit('afterInvoke', name, args, context.byref, result, context);
if (_onAfterInvoke !== null) {
var value = _onAfterInvoke(name, args, context.byref, result, context);
- if (util.isError(value)) throw value;
+ if (isError(value)) { throw value; }
if (Future.isPromise(value)) {
return value.then(function(e) {
- if (util.isError(e)) throw e;
+ if (isError(e)) { throw e; }
return doOutput(args, context, result);
});
}
@@ -288,20 +319,23 @@ function Service() {
reader.reset();
var name = reader.readString();
var alias = name.toLowerCase();
+ var cc = {};
+ var key;
+ for (key in context) { cc[key] = context[key]; }
var call = _calls[alias] || _calls['*'];
if (call) {
- for (var key in call) context[key] = call[key];
+ for (key in call) { cc[key] = call[key]; }
}
var args = [];
- context.byref = false;
+ cc.byref = false;
tag = input.readByte();
if (tag === Tags.TagList) {
- reader.useHarmonyMap = context.useHarmonyMap;
+ reader.useHarmonyMap = cc.useHarmonyMap;
reader.reset();
args = reader.readListWithoutTag();
tag = input.readByte();
if (tag === Tags.TagTrue) {
- context.byref = true;
+ cc.byref = true;
tag = input.readByte();
}
}
@@ -311,10 +345,10 @@ function Service() {
'with following data: ' + input.toString());
}
if (call) {
- results.push(beforeInvoke(name, args, context));
+ results.push(beforeInvoke(name, args, cc));
}
else {
- results.push(sendError(new Error('Can\'t find this function ' + name + '().'), context));
+ results.push(sendError(new Error('Can\'t find this function ' + name + '().'), cc));
}
} while (tag === Tags.TagCall);
return Future.reduce(results, function(output, result) {
@@ -326,7 +360,7 @@ function Service() {
});
}
- function doFunctionList(context) {
+ function doFunctionList() {
var stream = new BytesIO();
var writer = new Writer(stream, true);
stream.writeByte(Tags.TagFunctions);
@@ -335,34 +369,43 @@ function Service() {
return stream.bytes;
}
+ function delayError(e, context) {
+ var err = endError(e, context);
+ if (_errorDelay > 0) {
+ return Future.delayed(_errorDelay, err);
+ }
+ else {
+ return Promise.value(err);
+ }
+ }
+
function beforeFilterHandler(request, context) {
var response;
try {
request = inputFilter(request, context);
- response = _afterFilterHandler(request, context);
- }
- catch (e) {
- response = endError(e, context);
- if (_errorDelay > 0) {
- response = Future.delayed(_errorDelay, response);
- }
- }
- if (Future.isPromise(response)) {
- return response.then(function(response) {
- return outputFilter(response, context);
+ response = _afterFilterHandler(request, context).then(null, function(e) {
+ return delayError(e, context);
});
}
- else {
- return outputFilter(response, context);
+ catch (e) {
+ response = delayError(e, context);
}
+ return response.then(function(value) {
+ return outputFilter(value, context);
+ });
}
function afterFilterHandler(request, context) {
- var input = new BytesIO(request);
- switch (input.readByte()) {
- case Tags.TagCall: return doInvoke(input, context);
- case Tags.TagEnd: return doFunctionList(context);
- default: throw new Error('Wrong Request: \r\n' + BytesIO.toString(request));
+ try {
+ var input = new BytesIO(request);
+ switch (input.readByte()) {
+ case Tags.TagCall: return doInvoke(input, context);
+ case Tags.TagEnd: return Future.value(doFunctionList(context));
+ default: throw new Error('Wrong Request: \r\n' + BytesIO.toString(request));
+ }
+ }
+ catch (e) {
+ return Future.error(e);
}
}
@@ -473,6 +516,17 @@ function Service() {
return true;
}
+ function remove(alias) {
+ var name = alias.toLowerCase();
+ if (_calls[name]) {
+ var index = _names.indexOf(alias);
+ if (index >= 0) {
+ _names.splice(index, 1);
+ }
+ delete _calls[name];
+ }
+ }
+
function addFunction(func, alias, options) {
if (typeof(func) !== 'function') {
throw new Error('Argument func must be a function');
@@ -705,7 +759,7 @@ function Service() {
else if (typeof(args[0]) === 'string') {
addFunction(global[args[0]], args[0]);
}
- else if (util.isArray(args[0])) {
+ else if (Array.isArray(args[0])) {
addFunctions(args[0]);
}
else {
@@ -722,8 +776,8 @@ function Service() {
typeof(args[1]) === 'string') {
addFunction(global[args[0]], args[1]);
}
- else if (util.isArray(args[0])) {
- if (util.isArray(args[1])) {
+ else if (Array.isArray(args[0])) {
+ if (Array.isArray(args[1])) {
addFunctions(args[0], args[1]);
}
else {
@@ -750,8 +804,8 @@ function Service() {
addFunction(global[args[0]], args[2]);
}
}
- else if (util.isArray(args[0])) {
- if (util.isArray(args[2]) && !args[1]) {
+ else if (Array.isArray(args[0])) {
+ if (Array.isArray(args[2]) && !args[1]) {
addFunctions(args[0], args[2]);
}
else {
@@ -777,7 +831,7 @@ function Service() {
else if (typeof(args[0]) === 'string') {
addAsyncFunction(global[args[0]], args[0]);
}
- else if (util.isArray(args[0])) {
+ else if (Array.isArray(args[0])) {
addAsyncFunctions(args[0]);
}
else {
@@ -794,8 +848,8 @@ function Service() {
typeof(args[1]) === 'string') {
addAsyncFunction(global[args[0]], args[1]);
}
- else if (util.isArray(args[0])) {
- if (util.isArray(args[1])) {
+ else if (Array.isArray(args[0])) {
+ if (Array.isArray(args[1])) {
addAsyncFunctions(args[0], args[1]);
}
else {
@@ -822,8 +876,8 @@ function Service() {
addAsyncFunction(global[args[0]], args[2]);
}
}
- else if (util.isArray(args[0])) {
- if (util.isArray(args[2]) && !args[1]) {
+ else if (Array.isArray(args[0])) {
+ if (Array.isArray(args[2]) && !args[1]) {
addAsyncFunctions(args[0], args[2]);
}
else {
@@ -839,15 +893,20 @@ function Service() {
throw new Error('Wrong arguments');
}
+ function getTopics(topic) {
+ if (!(topic in _topics)) {
+ throw new Error('topic "' + topic + '" is not published.');
+ }
+ return _topics[topic];
+ }
function delTimer(topics, id) {
- if ('timer' in topics[id]) {
- global.clearTimeout(topics[id].timer);
- delete topics[id].timer;
+ var t = topics[id];
+ if ('timer' in t) {
+ global.clearTimeout(t.timer);
+ delete t.timer;
}
}
-
- function offline(topic, id) {
- var topics = getTopics(topic);
+ function offline(topics, topic, id) {
delTimer(topics, id);
var messages = topics[id].messages;
delete topics[id];
@@ -861,12 +920,17 @@ function Service() {
self.emit('unsubscribe', topic, id, self);
}
}
- function resetTimer(topic, id) {
- var topics = getTopics(topic);
+ function setTimer(topics, topic, id) {
+ var t = topics[id];
+ if (!('timer' in t)) {
+ t.timer = global.setTimeout(function() {
+ offline(topics, topic, id);
+ }, t.heartbeat);
+ }
+ }
+ function resetTimer(topics, topic, id) {
delTimer(topics, id);
- topics[id].timer = global.setTimeout(function() {
- offline(topic, id);
- }, topics[id].heartbeat);
+ setTimer(topics, topic, id);
}
function setRequestTimer(topic, id, request, timeout) {
var topics = getTopics(topic);
@@ -874,30 +938,28 @@ function Service() {
return request.timeout(timeout).catchError(function(e) {
if (e instanceof TimeoutError) {
var checkoffline = function() {
- topics[id].timer = global.setTimeout(
+ var t = topics[id];
+ t.timer = global.setTimeout(
checkoffline,
- topics[id].heartbeat
+ t.heartbeat
);
- if (topics[id].count < 0) {
- offline(topic, id);
+ if (t.count < 0) {
+ offline(topics, topic, id);
}
else {
- topics[id].count--;
+ t.count--;
}
};
checkoffline();
}
- else {
- topics[id].count--;
- }
});
}
return request;
}
function publish(topic, options) {
- if (util.isArray(topic)) {
+ if (Array.isArray(topic)) {
topic.forEach(function(t) {
- publish(t, timeout);
+ publish(t, options);
});
return;
}
@@ -909,7 +971,7 @@ function Service() {
_topics[topic] = {};
_events[topic] = events;
addFunction(function(id) {
- var topics = _topics[topic];
+ var topics = getTopics(topic);
if (id in topics) {
if (topics[id].count < 0) {
topics[id].count = 0;
@@ -918,7 +980,7 @@ function Service() {
if (messages.length > 0) {
var message = messages.shift();
message.detector.resolve(true);
- resetTimer(topic, id);
+ resetTimer(topics, topic, id);
return message.result;
}
else {
@@ -928,7 +990,7 @@ function Service() {
}
else {
topics[id] = { messages: [], count: 1, heartbeat: heartbeat };
- setImmediate(function() {
+ process.nextTick(function() {
if (_events[topic] instanceof EventEmitter) {
_events[topic].emit('subscribe', id, self);
}
@@ -938,7 +1000,7 @@ function Service() {
});
}
if ('request' in topics[id]) {
- topics[id].request.resolve();
+ topics[id].request.resolve(null);
}
var request = new Future();
request.whenComplete(function() { topics[id].count--; });
@@ -946,13 +1008,13 @@ function Service() {
return setRequestTimer(topic, id, request, timeout);
}, topic);
}
- function getTopics(topic) {
- if (!(topic in _topics)) {
- throw new Error('topic "' + topic + '" is not published.');
- }
- return _topics[topic];
- }
function _push(topic, id, result) {
+ if (Future.isPromise(result)) {
+ var __push = function(result) {
+ return _push(topic, id, result);
+ }
+ return result.then(__push, __push);
+ }
var topics = getTopics(topic);
if (!(id in topics)) {
return Future.value(false);
@@ -960,12 +1022,13 @@ function Service() {
if ('request' in topics[id]) {
topics[id].request.resolve(result);
delete topics[id].request;
+ setTimer(topics, topic, id);
return Future.value(true);
}
else {
var detector = new Future();
topics[id].messages.push({ detector: detector, result: result });
- resetTimer(topic, id);
+ setTimer(topics, topic, id);
return detector;
}
}
@@ -1024,7 +1087,7 @@ function Service() {
var args = arguments;
var argc = args.length;
var id, result;
- if (argc < 2 && argc > 3) {
+ if (argc < 2 || argc > 3) {
throw new Error('Wrong number of arguments');
}
if (argc === 2) {
@@ -1038,7 +1101,7 @@ function Service() {
var topics = getTopics(topic);
for (id in topics) { _push(topic, id, result); }
}
- else if (util.isArray(id)) {
+ else if (Array.isArray(id)) {
id.forEach(function(id) { _push(topic, id, result); });
}
else {
@@ -1050,7 +1113,7 @@ function Service() {
_beforeFilterHandler = _beforeFilterHandlers.reduceRight(
function(next, handler) {
return function(request, context) {
- return handler(request, context, next);
+ return Future.toPromise(handler(request, context, next));
};
}, beforeFilterHandler);
}
@@ -1059,7 +1122,7 @@ function Service() {
_afterFilterHandler = _afterFilterHandlers.reduceRight(
function(next, handler) {
return function(request, context) {
- return handler(request, context, next);
+ return Future.toPromise(handler(request, context, next));
};
}, afterFilterHandler);
}
@@ -1068,7 +1131,7 @@ function Service() {
_invokeHandler = _invokeHandlers.reduceRight(
function(next, handler) {
return function(name, args, context) {
- return handler(name, args, context, next);
+ return Future.toPromise(handler(name, args, context, next));
};
}, invokeHandler);
}
@@ -1076,6 +1139,10 @@ function Service() {
addInvokeHandler(handler);
return self;
}
+ function getNames() {
+ return _names;
+ }
+
var beforeFilter = Object.create(null, {
use: { value: function(handler) {
addBeforeFilterHandler(handler);
@@ -1102,6 +1169,7 @@ function Service() {
debug: { get: isDebugEnabled, set: setDebugEnabled },
simple: { get: getSimpleMode, set: setSimpleMode },
passContext: { get: getPassContext, set: setPassContext },
+ errorDelay: { get: getErrorDelay, set: setErrorDelay },
filter: { get: getFilter, set: setFilter },
addFilter: { value: addFilter },
removeFilter: { value: removeFilter },
@@ -1129,6 +1197,7 @@ function Service() {
idlist: { value: idlist },
exist: { value: exist },
use: { value: use },
+ getNames: { value: getNames },
beforeFilter: { value: beforeFilter },
afterFilter: { value: afterFilter }
});
diff --git a/lib/server/SocketServer.js b/lib/server/SocketServer.js
index c09dbe6..41d638e 100644
--- a/lib/server/SocketServer.js
+++ b/lib/server/SocketServer.js
@@ -13,12 +13,11 @@
* *
* Hprose Socket Server for Node.js. *
* *
- * LastModified: Aug 9, 2015 *
+ * LastModified: Mar 3, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var util = require('util');
diff --git a/lib/server/SocketService.js b/lib/server/SocketService.js
index 841f13a..6859e6a 100644
--- a/lib/server/SocketService.js
+++ b/lib/server/SocketService.js
@@ -13,21 +13,21 @@
* *
* Hprose Socket Service for Node.js. *
* *
- * LastModified: Aug 9, 2015 *
+ * LastModified: Sep 17, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var util = require('util');
-var setImmediate = global.setImmediate;
var Service = global.hprose.Service;
var BytesIO = global.hprose.BytesIO;
var Future = global.hprose.Future;
+function noop() {}
+
function SocketService() {
Service.call(this);
@@ -139,7 +139,7 @@ function SocketService() {
};
try {
self.emit('accept', context);
- if (_onAccept) _onAccept(context);
+ if (_onAccept) { _onAccept(context); }
}
catch(e) {
socket.end();
@@ -148,16 +148,18 @@ function SocketService() {
socket.on('close', function() {
try {
self.emit('close', context);
- if (_onClose) _onClose(context);
+ if (_onClose) { _onClose(context); }
}
catch(e) {}
});
- socket.on('end', function(e) { });
+ socket.on('end', noop);
socket.on('error', function(e) {
try {
- self.emit('sendError', e, context);
- if (self.onSendError) {
- self.onSendError(e, context);
+ if (e.code != "EPIPE") {
+ self.emit('sendError', e, context);
+ if (self.onSendError) {
+ self.onSendError(e, context);
+ }
}
}
catch(e) {}
diff --git a/lib/server/WebSocketServer.js b/lib/server/WebSocketServer.js
index ae1d74c..4513e32 100644
--- a/lib/server/WebSocketServer.js
+++ b/lib/server/WebSocketServer.js
@@ -13,12 +13,11 @@
* *
* Hprose WebSocket Server for Node.js. *
* *
- * LastModified: Aug 9, 2015 *
+ * LastModified: Aug 20, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var util = require('util');
@@ -27,12 +26,13 @@ var http = require('http');
var https = require('https');
var WebSocketService = global.hprose.WebSocketService;
-function WebSocketServer(options, tlsOptions) {
+function WebSocketServer(options, tlsOptions, handler) {
WebSocketService.call(this);
var self = this;
- var httpserver = (tlsOptions ?
- https.createServer(tlsOptions, self.handle) :
- http.createServer(self.handle));
+ if (!handler) handler = this.handle;
+ var httpserver = tlsOptions ?
+ https.createServer(tlsOptions, handler) :
+ http.createServer(handler);
var host = options.host;
var port = options.port;
delete options.host;
@@ -47,7 +47,7 @@ function WebSocketServer(options, tlsOptions) {
server: self.server,
userdata:{}
};
- if (socket) context.socket = socket;
+ if (socket) { context.socket = socket; }
try {
self.emit('sendError', e, context);
if (self.onSendError) {
diff --git a/lib/server/WebSocketService.js b/lib/server/WebSocketService.js
index 28faf3e..0779cee 100644
--- a/lib/server/WebSocketService.js
+++ b/lib/server/WebSocketService.js
@@ -13,17 +13,15 @@
* *
* Hprose WebSocket Service for Node.js. *
* *
- * LastModified: Aug 9, 2015 *
+ * LastModified: Sep 30, 2016 *
* Author: Ma Bingyao *
* *
\**********************************************************/
-/*jshint node:true, eqeqeq:true */
'use strict';
var util = require('util');
-var setImmediate = global.setImmediate;
var HttpService = global.hprose.HttpService;
var BytesIO = global.hprose.BytesIO;
var Future = global.hprose.Future;
@@ -101,7 +99,7 @@ function WebSocketService() {
};
try {
self.emit('accept', context);
- if (_onAccept) _onAccept(context);
+ if (_onAccept) { _onAccept(context); }
}
catch(e) {
ws.close();
@@ -110,12 +108,10 @@ function WebSocketService() {
ws.on('close', function() {
try {
self.emit('close',context);
- if (_onClose) _onClose(context);
+ if (_onClose) { _onClose(context); }
}
catch(e) {}
});
- var bytes = new BytesIO();
- var dataLength = -1;
ws.on('error', function(e) {
try {
self.emit('sendError', e, context);
@@ -129,7 +125,7 @@ function WebSocketService() {
var bytes = new BytesIO(data);
var id = bytes.readInt32BE();
var request = bytes.read(bytes.length - 4);
- setImmediate(function() {
+ process.nextTick(function() {
var context = {
httpserver: self.httpserver,
server: self.server,
diff --git a/lib/utils/regenerator-runtime.js b/lib/utils/regenerator-runtime.js
new file mode 100644
index 0000000..4ec72f1
--- /dev/null
+++ b/lib/utils/regenerator-runtime.js
@@ -0,0 +1,669 @@
+/**
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * https://raw.github.com/facebook/regenerator/master/LICENSE file. An
+ * additional grant of patent rights can be found in the PATENTS file in
+ * the same directory.
+ */
+
+!(function(global) {
+ "use strict";
+
+ var hasOwn = Object.prototype.hasOwnProperty;
+ var undefined; // More compressible than void 0.
+ var $Symbol = typeof Symbol === "function" ? Symbol : {};
+ var iteratorSymbol = $Symbol.iterator || "@@iterator";
+ var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
+
+ var inModule = typeof module === "object";
+ var runtime = global.regeneratorRuntime;
+ if (runtime) {
+ if (inModule) {
+ // If regeneratorRuntime is defined globally and we're in a module,
+ // make the exports object identical to regeneratorRuntime.
+ module.exports = runtime;
+ }
+ // Don't bother evaluating the rest of this file if the runtime was
+ // already defined globally.
+ return;
+ }
+
+ // Define the runtime globally (as expected by generated code) as either
+ // module.exports (if we're in a module) or a new, empty object.
+ runtime = global.regeneratorRuntime = inModule ? module.exports : {};
+
+ function wrap(innerFn, outerFn, self, tryLocsList) {
+ // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
+ var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
+ var generator = Object.create(protoGenerator.prototype);
+ var context = new Context(tryLocsList || []);
+
+ // The ._invoke method unifies the implementations of the .next,
+ // .throw, and .return methods.
+ generator._invoke = makeInvokeMethod(innerFn, self, context);
+
+ return generator;
+ }
+ runtime.wrap = wrap;
+
+ // Try/catch helper to minimize deoptimizations. Returns a completion
+ // record like context.tryEntries[i].completion. This interface could
+ // have been (and was previously) designed to take a closure to be
+ // invoked without arguments, but in all the cases we care about we
+ // already have an existing method we want to call, so there's no need
+ // to create a new function object. We can even get away with assuming
+ // the method takes exactly one argument, since that happens to be true
+ // in every case, so we don't have to touch the arguments object. The
+ // only additional allocation required is the completion record, which
+ // has a stable shape and so hopefully should be cheap to allocate.
+ function tryCatch(fn, obj, arg) {
+ try {
+ return { type: "normal", arg: fn.call(obj, arg) };
+ } catch (err) {
+ return { type: "throw", arg: err };
+ }
+ }
+
+ var GenStateSuspendedStart = "suspendedStart";
+ var GenStateSuspendedYield = "suspendedYield";
+ var GenStateExecuting = "executing";
+ var GenStateCompleted = "completed";
+
+ // Returning this object from the innerFn has the same effect as
+ // breaking out of the dispatch switch statement.
+ var ContinueSentinel = {};
+
+ // Dummy constructor functions that we use as the .constructor and
+ // .constructor.prototype properties for functions that return Generator
+ // objects. For full spec compliance, you may wish to configure your
+ // minifier not to mangle the names of these two functions.
+ function Generator() {}
+ function GeneratorFunction() {}
+ function GeneratorFunctionPrototype() {}
+
+ var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype;
+ GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
+ GeneratorFunctionPrototype.constructor = GeneratorFunction;
+ GeneratorFunctionPrototype[toStringTagSymbol] = GeneratorFunction.displayName = "GeneratorFunction";
+
+ // Helper for defining the .next, .throw, and .return methods of the
+ // Iterator interface in terms of a single ._invoke method.
+ function defineIteratorMethods(prototype) {
+ ["next", "throw", "return"].forEach(function(method) {
+ prototype[method] = function(arg) {
+ return this._invoke(method, arg);
+ };
+ });
+ }
+
+ runtime.isGeneratorFunction = function(genFun) {
+ var ctor = typeof genFun === "function" && genFun.constructor;
+ return ctor
+ ? ctor === GeneratorFunction ||
+ // For the native GeneratorFunction constructor, the best we can
+ // do is to check its .name property.
+ (ctor.displayName || ctor.name) === "GeneratorFunction"
+ : false;
+ };
+
+ runtime.mark = function(genFun) {
+ if (Object.setPrototypeOf) {
+ Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
+ } else {
+ genFun.__proto__ = GeneratorFunctionPrototype;
+ if (!(toStringTagSymbol in genFun)) {
+ genFun[toStringTagSymbol] = "GeneratorFunction";
+ }
+ }
+ genFun.prototype = Object.create(Gp);
+ return genFun;
+ };
+
+ // Within the body of any async function, `await x` is transformed to
+ // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
+ // `value instanceof AwaitArgument` to determine if the yielded value is
+ // meant to be awaited. Some may consider the name of this method too
+ // cutesy, but they are curmudgeons.
+ runtime.awrap = function(arg) {
+ return new AwaitArgument(arg);
+ };
+
+ function AwaitArgument(arg) {
+ this.arg = arg;
+ }
+
+ function AsyncIterator(generator) {
+ function invoke(method, arg, resolve, reject) {
+ var record = tryCatch(generator[method], generator, arg);
+ if (record.type === "throw") {
+ reject(record.arg);
+ } else {
+ var result = record.arg;
+ var value = result.value;
+ if (value instanceof AwaitArgument) {
+ return Promise.resolve(value.arg).then(function(value) {
+ invoke("next", value, resolve, reject);
+ }, function(err) {
+ invoke("throw", err, resolve, reject);
+ });
+ }
+
+ return Promise.resolve(value).then(function(unwrapped) {
+ // When a yielded Promise is resolved, its final value becomes
+ // the .value of the Promise<{value,done}> result for the
+ // current iteration. If the Promise is rejected, however, the
+ // result for this iteration will be rejected with the same
+ // reason. Note that rejections of yielded Promises are not
+ // thrown back into the generator function, as is the case
+ // when an awaited Promise is rejected. This difference in
+ // behavior between yield and await is important, because it
+ // allows the consumer to decide what to do with the yielded
+ // rejection (swallow it and continue, manually .throw it back
+ // into the generator, abandon iteration, whatever). With
+ // await, by contrast, there is no opportunity to examine the
+ // rejection reason outside the generator function, so the
+ // only option is to throw it from the await expression, and
+ // let the generator function handle the exception.
+ result.value = unwrapped;
+ resolve(result);
+ }, reject);
+ }
+ }
+
+ if (typeof process === "object" && process.domain) {
+ invoke = process.domain.bind(invoke);
+ }
+
+ var previousPromise;
+
+ function enqueue(method, arg) {
+ function callInvokeWithMethodAndArg() {
+ return new Promise(function(resolve, reject) {
+ invoke(method, arg, resolve, reject);
+ });
+ }
+
+ return previousPromise =
+ // If enqueue has been called before, then we want to wait until
+ // all previous Promises have been resolved before calling invoke,
+ // so that results are always delivered in the correct order. If
+ // enqueue has not been called before, then it is important to
+ // call invoke immediately, without waiting on a callback to fire,
+ // so that the async generator function has the opportunity to do
+ // any necessary setup in a predictable way. This predictability
+ // is why the Promise constructor synchronously invokes its
+ // executor callback, and why async functions synchronously
+ // execute code before the first await. Since we implement simple
+ // async functions in terms of async generators, it is especially
+ // important to get this right, even though it requires care.
+ previousPromise ? previousPromise.then(
+ callInvokeWithMethodAndArg,
+ // Avoid propagating failures to Promises returned by later
+ // invocations of the iterator.
+ callInvokeWithMethodAndArg
+ ) : callInvokeWithMethodAndArg();
+ }
+
+ // Define the unified helper method that is used to implement .next,
+ // .throw, and .return (see defineIteratorMethods).
+ this._invoke = enqueue;
+ }
+
+ defineIteratorMethods(AsyncIterator.prototype);
+
+ // Note that simple async functions are implemented on top of
+ // AsyncIterator objects; they just return a Promise for the value of
+ // the final result produced by the iterator.
+ runtime.async = function(innerFn, outerFn, self, tryLocsList) {
+ var iter = new AsyncIterator(
+ wrap(innerFn, outerFn, self, tryLocsList)
+ );
+
+ return runtime.isGeneratorFunction(outerFn)
+ ? iter // If outerFn is a generator, return the full iterator.
+ : iter.next().then(function(result) {
+ return result.done ? result.value : iter.next();
+ });
+ };
+
+ function makeInvokeMethod(innerFn, self, context) {
+ var state = GenStateSuspendedStart;
+
+ return function invoke(method, arg) {
+ if (state === GenStateExecuting) {
+ throw new Error("Generator is already running");
+ }
+
+ if (state === GenStateCompleted) {
+ if (method === "throw") {
+ throw arg;
+ }
+
+ // Be forgiving, per 25.3.3.3.3 of the spec:
+ // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
+ return doneResult();
+ }
+
+ while (true) {
+ var delegate = context.delegate;
+ if (delegate) {
+ if (method === "return" ||
+ (method === "throw" && delegate.iterator[method] === undefined)) {
+ // A return or throw (when the delegate iterator has no throw
+ // method) always terminates the yield* loop.
+ context.delegate = null;
+
+ // If the delegate iterator has a return method, give it a
+ // chance to clean up.
+ var returnMethod = delegate.iterator["return"];
+ if (returnMethod) {
+ var record = tryCatch(returnMethod, delegate.iterator, arg);
+ if (record.type === "throw") {
+ // If the return method threw an exception, let that
+ // exception prevail over the original return or throw.
+ method = "throw";
+ arg = record.arg;
+ continue;
+ }
+ }
+
+ if (method === "return") {
+ // Continue with the outer return, now that the delegate
+ // iterator has been terminated.
+ continue;
+ }
+ }
+
+ var record = tryCatch(
+ delegate.iterator[method],
+ delegate.iterator,
+ arg
+ );
+
+ if (record.type === "throw") {
+ context.delegate = null;
+
+ // Like returning generator.throw(uncaught), but without the
+ // overhead of an extra function call.
+ method = "throw";
+ arg = record.arg;
+ continue;
+ }
+
+ // Delegate generator ran and handled its own exceptions so
+ // regardless of what the method was, we continue as if it is
+ // "next" with an undefined arg.
+ method = "next";
+ arg = undefined;
+
+ var info = record.arg;
+ if (info.done) {
+ context[delegate.resultName] = info.value;
+ context.next = delegate.nextLoc;
+ } else {
+ state = GenStateSuspendedYield;
+ return info;
+ }
+
+ context.delegate = null;
+ }
+
+ if (method === "next") {
+ // Setting context._sent for legacy support of Babel's
+ // function.sent implementation.
+ context.sent = context._sent = arg;
+
+ } else if (method === "throw") {
+ if (state === GenStateSuspendedStart) {
+ state = GenStateCompleted;
+ throw arg;
+ }
+
+ if (context.dispatchException(arg)) {
+ // If the dispatched exception was caught by a catch block,
+ // then let that catch block handle the exception normally.
+ method = "next";
+ arg = undefined;
+ }
+
+ } else if (method === "return") {
+ context.abrupt("return", arg);
+ }
+
+ state = GenStateExecuting;
+
+ var record = tryCatch(innerFn, self, context);
+ if (record.type === "normal") {
+ // If an exception is thrown from innerFn, we leave state ===
+ // GenStateExecuting and loop back for another invocation.
+ state = context.done
+ ? GenStateCompleted
+ : GenStateSuspendedYield;
+
+ var info = {
+ value: record.arg,
+ done: context.done
+ };
+
+ if (record.arg === ContinueSentinel) {
+ if (context.delegate && method === "next") {
+ // Deliberately forget the last sent value so that we don't
+ // accidentally pass it on to the delegate.
+ arg = undefined;
+ }
+ } else {
+ return info;
+ }
+
+ } else if (record.type === "throw") {
+ state = GenStateCompleted;
+ // Dispatch the exception by looping back around to the
+ // context.dispatchException(arg) call above.
+ method = "throw";
+ arg = record.arg;
+ }
+ }
+ };
+ }
+
+ // Define Generator.prototype.{next,throw,return} in terms of the
+ // unified ._invoke helper method.
+ defineIteratorMethods(Gp);
+
+ Gp[iteratorSymbol] = function() {
+ return this;
+ };
+
+ Gp[toStringTagSymbol] = "Generator";
+
+ Gp.toString = function() {
+ return "[object Generator]";
+ };
+
+ function pushTryEntry(locs) {
+ var entry = { tryLoc: locs[0] };
+
+ if (1 in locs) {
+ entry.catchLoc = locs[1];
+ }
+
+ if (2 in locs) {
+ entry.finallyLoc = locs[2];
+ entry.afterLoc = locs[3];
+ }
+
+ this.tryEntries.push(entry);
+ }
+
+ function resetTryEntry(entry) {
+ var record = entry.completion || {};
+ record.type = "normal";
+ delete record.arg;
+ entry.completion = record;
+ }
+
+ function Context(tryLocsList) {
+ // The root entry object (effectively a try statement without a catch
+ // or a finally block) gives us a place to store values thrown from
+ // locations where there is no enclosing try statement.
+ this.tryEntries = [{ tryLoc: "root" }];
+ tryLocsList.forEach(pushTryEntry, this);
+ this.reset(true);
+ }
+
+ runtime.keys = function(object) {
+ var keys = [];
+ for (var key in object) {
+ keys.push(key);
+ }
+ keys.reverse();
+
+ // Rather than returning an object with a next method, we keep
+ // things simple and return the next function itself.
+ return function next() {
+ while (keys.length) {
+ var key = keys.pop();
+ if (key in object) {
+ next.value = key;
+ next.done = false;
+ return next;
+ }
+ }
+
+ // To avoid creating an additional object, we just hang the .value
+ // and .done properties off the next function object itself. This
+ // also ensures that the minifier will not anonymize the function.
+ next.done = true;
+ return next;
+ };
+ };
+
+ function values(iterable) {
+ if (iterable) {
+ var iteratorMethod = iterable[iteratorSymbol];
+ if (iteratorMethod) {
+ return iteratorMethod.call(iterable);
+ }
+
+ if (typeof iterable.next === "function") {
+ return iterable;
+ }
+
+ if (!isNaN(iterable.length)) {
+ var i = -1, next = function next() {
+ while (++i < iterable.length) {
+ if (hasOwn.call(iterable, i)) {
+ next.value = iterable[i];
+ next.done = false;
+ return next;
+ }
+ }
+
+ next.value = undefined;
+ next.done = true;
+
+ return next;
+ };
+
+ return next.next = next;
+ }
+ }
+
+ // Return an iterator with no values.
+ return { next: doneResult };
+ }
+ runtime.values = values;
+
+ function doneResult() {
+ return { value: undefined, done: true };
+ }
+
+ Context.prototype = {
+ constructor: Context,
+
+ reset: function(skipTempReset) {
+ this.prev = 0;
+ this.next = 0;
+ // Resetting context._sent for legacy support of Babel's
+ // function.sent implementation.
+ this.sent = this._sent = undefined;
+ this.done = false;
+ this.delegate = null;
+
+ this.tryEntries.forEach(resetTryEntry);
+
+ if (!skipTempReset) {
+ for (var name in this) {
+ // Not sure about the optimal order of these conditions:
+ if (name.charAt(0) === "t" &&
+ hasOwn.call(this, name) &&
+ !isNaN(+name.slice(1))) {
+ this[name] = undefined;
+ }
+ }
+ }
+ },
+
+ stop: function() {
+ this.done = true;
+
+ var rootEntry = this.tryEntries[0];
+ var rootRecord = rootEntry.completion;
+ if (rootRecord.type === "throw") {
+ throw rootRecord.arg;
+ }
+
+ return this.rval;
+ },
+
+ dispatchException: function(exception) {
+ if (this.done) {
+ throw exception;
+ }
+
+ var context = this;
+ function handle(loc, caught) {
+ record.type = "throw";
+ record.arg = exception;
+ context.next = loc;
+ return !!caught;
+ }
+
+ for (var i = this.tryEntries.length - 1; i >= 0; --i) {
+ var entry = this.tryEntries[i];
+ var record = entry.completion;
+
+ if (entry.tryLoc === "root") {
+ // Exception thrown outside of any try block that could handle
+ // it, so set the completion value of the entire function to
+ // throw the exception.
+ return handle("end");
+ }
+
+ if (entry.tryLoc <= this.prev) {
+ var hasCatch = hasOwn.call(entry, "catchLoc");
+ var hasFinally = hasOwn.call(entry, "finallyLoc");
+
+ if (hasCatch && hasFinally) {
+ if (this.prev < entry.catchLoc) {
+ return handle(entry.catchLoc, true);
+ } else if (this.prev < entry.finallyLoc) {
+ return handle(entry.finallyLoc);
+ }
+
+ } else if (hasCatch) {
+ if (this.prev < entry.catchLoc) {
+ return handle(entry.catchLoc, true);
+ }
+
+ } else if (hasFinally) {
+ if (this.prev < entry.finallyLoc) {
+ return handle(entry.finallyLoc);
+ }
+
+ } else {
+ throw new Error("try statement without catch or finally");
+ }
+ }
+ }
+ },
+
+ abrupt: function(type, arg) {
+ for (var i = this.tryEntries.length - 1; i >= 0; --i) {
+ var entry = this.tryEntries[i];
+ if (entry.tryLoc <= this.prev &&
+ hasOwn.call(entry, "finallyLoc") &&
+ this.prev < entry.finallyLoc) {
+ var finallyEntry = entry;
+ break;
+ }
+ }
+
+ if (finallyEntry &&
+ (type === "break" ||
+ type === "continue") &&
+ finallyEntry.tryLoc <= arg &&
+ arg <= finallyEntry.finallyLoc) {
+ // Ignore the finally entry if control is not jumping to a
+ // location outside the try/catch block.
+ finallyEntry = null;
+ }
+
+ var record = finallyEntry ? finallyEntry.completion : {};
+ record.type = type;
+ record.arg = arg;
+
+ if (finallyEntry) {
+ this.next = finallyEntry.finallyLoc;
+ } else {
+ this.complete(record);
+ }
+
+ return ContinueSentinel;
+ },
+
+ complete: function(record, afterLoc) {
+ if (record.type === "throw") {
+ throw record.arg;
+ }
+
+ if (record.type === "break" ||
+ record.type === "continue") {
+ this.next = record.arg;
+ } else if (record.type === "return") {
+ this.rval = record.arg;
+ this.next = "end";
+ } else if (record.type === "normal" && afterLoc) {
+ this.next = afterLoc;
+ }
+ },
+
+ finish: function(finallyLoc) {
+ for (var i = this.tryEntries.length - 1; i >= 0; --i) {
+ var entry = this.tryEntries[i];
+ if (entry.finallyLoc === finallyLoc) {
+ this.complete(entry.completion, entry.afterLoc);
+ resetTryEntry(entry);
+ return ContinueSentinel;
+ }
+ }
+ },
+
+ "catch": function(tryLoc) {
+ for (var i = this.tryEntries.length - 1; i >= 0; --i) {
+ var entry = this.tryEntries[i];
+ if (entry.tryLoc === tryLoc) {
+ var record = entry.completion;
+ if (record.type === "throw") {
+ var thrown = record.arg;
+ resetTryEntry(entry);
+ }
+ return thrown;
+ }
+ }
+
+ // The context.catch method must only be called with a location
+ // argument that corresponds to a known catch block.
+ throw new Error("illegal catch attempt");
+ },
+
+ delegateYield: function(iterable, resultName, nextLoc) {
+ this.delegate = {
+ iterator: values(iterable),
+ resultName: resultName,
+ nextLoc: nextLoc
+ };
+
+ return ContinueSentinel;
+ }
+ };
+})(
+ // Among the various tricks for obtaining a reference to the global
+ // object, this seems to be the most reliable technique that does not
+ // use indirect eval (which violates Content Security Policy).
+ typeof global === "object" ? global :
+ typeof window === "object" ? window :
+ typeof self === "object" ? self : this
+);
diff --git a/package.json b/package.json
index 158b26f..0266944 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "hprose",
- "version": "2.0.5",
+ "version": "2.0.51",
"homepage": "https://github.com/hprose/hprose-nodejs",
"description": "hprose for node.js",
"keywords": [
@@ -50,9 +50,9 @@
"lib": "lib/"
},
"main": "lib/hprose.js",
- "optionalDependencies": { "ws": "*" },
+ "optionalDependencies": { "ws": ">=4.0.0" },
"devDependencies": {
- "promises-plus-tests": "*"
+ "promises-aplus-tests": "*"
},
"scripts": {
"aplus-tests": "promises-aplus-tests lib/hprose"