Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ice-node

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ice-node - npm Package Compare versions

Comparing version 0.3.1 to 0.3.2

base.js

193

express_api.js
const lib = require("./lib.js");
const mime = require("mime");
module.exports.ExpressRequest = ExpressRequest;
function ExpressRequest(req) {
if(!(this instanceof ExpressRequest)) return new ExpressRequest(...arguments);
if(!(req instanceof lib.Request)) throw new Error("ExpressRequest must be created with a Request");
module.exports.createApplication = createApplication;
this.app = null;
this.baseUrl = null;
this.body = {};
this.cookies = req.cookies;
this.fresh = true;
this.hostname = req.host;
this.ip = req.remote_addr.split(":")[0];
this.ips = [ this.ip ];
this.method = req.method;
this.originalUrl = req.uri;
this.params = req.params;
this.path = req.url;
this.protocol = "http";
this.query = {};
this.route = {};
this.secure = false;
this.signedCookies = {};
this.stale = false;
this.xhr = req.headers["x-requested-with"] == "XMLHttpRequest";
function createApplication(cfg) {
let app = new lib.Application(cfg);
patchApplication(app);
return app;
}
// TODO: this.accepts
// TODO: this.acceptsCharsets
// TODO: this.acceptsEncodings
// TODO: this.acceptsLanguages
module.exports.patchApplication = patchApplication;
this.header = k => req.headers[k];
this.get = this.header;
function patchApplication(app) {
if(!(app instanceof lib.Application)) {
throw new Error("Application required");
}
// TODO: this.is
const _app_use = app.use.bind(app);
const _app_route = app.route.bind(app);
const _app_prepare = app.prepare.bind(app);
const _app_listen = app.listen.bind(app);
this.param = k => this.params[k] || (this.body ? this.body[k] : null) || this.query[k];
app.use = function(p, fn) {
if(typeof(fn) == "function") {
_app_use(p, function(req, resp, mw) {
patchResponse(resp);
return new Promise((cb, reject) => {
fn(req, resp, function(e) {
if(e) {
reject(e);
} else {
cb();
}
});
});
});
} else {
_app_use(p, fn);
}
};
app.route = function(methods, p, fn) {
_app_route(methods, p, function(req, resp) {
patchResponse(resp);
return fn(req, resp);
});
};
// TODO: this.range
app.listen = function(addr) {
if(typeof(addr) == "number") {
addr = "0.0.0.0:" + addr;
}
_app_prepare();
_app_listen(addr);
};
app.setDefaultHandler((req, resp) => {
resp.detach();
resp.status(404).body("Not found").send();
});
}
module.exports.ExpressResponse = ExpressResponse;
function ExpressResponse(resp) {
if(!(this instanceof ExpressResponse)) return new ExpressResponse(...arguments);
if(!(resp instanceof lib.Response)) throw new Error("ExpressResponse must be created with a Response");
function patchResponse(resp) {
if(!(resp instanceof lib.Response)) {
throw new Error("Response required");
}
this.headers = {};
this.sent = false;
if(resp.patched) return;
resp.patched = true;
this.app = null;
this.headersSent = false;
this.locals = {};
this.append = (k, v) => this.headers[k] = v; // TODO: Handle Set-Cookie and array values
const _send = resp.send.bind(resp);
const _status = resp.status.bind(resp);
const _header = resp.header.bind(resp);
const _file = resp.file.bind(resp);
const _body = resp.body.bind(resp);
const _renderTemplate = resp.renderTemplate.bind(resp);
// TODO: Many...
resp.detach();
resp.send = function(data) {
if(data) _body(data);
_send();
};
resp.end = function(data) {
if(data) _body(data);
_send();
};
resp.json = function(data) {
_header("Content-Type", "application/json");
_body(JSON.stringify(data));
_send();
};
resp.sendFile = function(p) {
_file(p);
_send();
};
resp.sendStatus = function(code) {
_status(code);
_send();
};
resp.redirect = function() {
let path = arguments.pop();
let code = arguments.pop() || 302;
_status(code);
_header("Location", path);
_send();
};
resp.type = function(t) {
_header("Content-Type", mime.lookup(t));
return resp;
};
resp.header = function(k, v) {
if(typeof(k) == "object") {
let obj = k;
for(const k of obj) {
_header(k, obj[k]);
}
} else {
_header(k, v);;
}
};
resp.set = resp.header;
resp.render = function(name, data) {
_renderTemplate(name, data);
_send();
};
}
module.exports.bodyParser = {
json: parseJsonBody,
urlencoded: parseUrlencodedBody
}
function parseJsonBody() {
return function(req, resp, next) {
try {
req.body = req.json();
next();
} catch(e) {
next(e);
}
}
}
function parseUrlencodedBody() {
return function(req, resp, next) {
try {
req.body = req.form();
next();
} catch(e) {
next(e);
}
}
}

@@ -1,334 +0,6 @@

const core = require("./build/Release/ice_node_core");
const base = require("./base.js");
const express = require("./express_api.js");
module.exports.Application = Application;
function Application(cfg) {
if(!(this instanceof Application)) {
return new Application(...arguments);
}
if(!cfg) cfg = {};
this.server = new core.Server(cfg);
this.routes = {};
this.flags = [];
this.middlewares = [];
this.prepared = false;
}
Application.prototype.route = function(methods, p, fn) {
if(typeof(methods) == "string") methods = [ methods ];
let param_mappings = p.split("/").filter(v => v).map(v => v.startsWith(":") ? v.substr(1) : null);
let target;
if(param_mappings.filter(v => v).length) {
target = (req, resp) => {
try {
let params = {};
req.url.split("/").filter(v => v).map((v, index) => [param_mappings[index], v]).forEach(p => {
if (p[0]) {
params[p[0]] = p[1];
}
});
req.params = params;
} catch (e) {
req.params = {};
}
return fn(req, resp);
};
} else {
target = fn;
}
methods.map(v => v.toUpperCase()).forEach(m => {
this.routes[m + " " + p] = target;
});
return this;
}
Application.prototype.get = function(p, fn) {
return this.route("GET", p, fn);
}
Application.prototype.post = function(p, fn) {
this.use(p, new Flag("read_body"));
return this.route("POST", p, fn);
}
Application.prototype.put = function(p, fn) {
this.use(p, new Flag("read_body"));
return this.route("PUT", p, fn);
}
Application.prototype.delete = function(p, fn) {
return this.route("DELETE", p, fn);
}
Application.prototype.use = function(p, fn) {
if(fn instanceof Flag) {
this.flags.push({
prefix: p,
name: fn.name
});
} else {
this.middlewares.push({
prefix: p,
handler: fn
});
}
return this;
}
Application.prototype.addTemplate = function(name, content) {
this.server.addTemplate(name, content);
return this;
}
Application.prototype.loadCervusModule = function(name, data) {
this.server.loadCervusModule(name, data);
}
Application.prototype.prepare = function() {
if(this.prepared) {
throw new Error("Application.prepare: Already prepared");
}
let routes = {};
for(const k in this.routes) {
const p = k.split(" ")[1];
let mws = this.middlewares.filter(v => p.startsWith(v.prefix));
if(!routes[p]) routes[p] = {};
routes[p][k.split(" ")[0]] = generateEndpointHandler(mws, this.routes[k]);
}
for(const p in routes) {
let methodRoutes = routes[p];
let flags = this.flags.filter(v => p.startsWith(v.prefix)).map(v => v.name);
this.server.route(p, function(req) {
let rt = methodRoutes[req.method()];
if(rt) {
rt(req);
} else {
let resp = req.createResponse();
resp.status(405);
resp.send();
}
}, flags);
}
this.server.route("", generateEndpointHandler(this.middlewares, (req, resp) => resp.status(404)));
this.prepared = true;
this.route = null;
this.use = null;
}
Application.prototype.listen = function(addr) {
if(!this.prepared) {
throw new Error("Not prepared");
}
this.server.listen(addr);
}
//module.exports.Request = Request;
function Request(inst) {
if(!(this instanceof Request)) {
return new Request(...arguments);
}
this.inst = inst;
this.cache = {
uri: null,
url: null,
headers: null,
cookies: null
};
this.params = {};
this.session = new Proxy({}, {
get: (t, k) => this.inst.sessionItem(k),
set: (t, k, v) => this.inst.sessionItem(k, v)
});
this.custom = new Proxy({}, {
get: (t, k) => this.inst.customProperty(k)
});
}
Request.prototype.createResponse = function () {
return new Response(this);
}
Request.prototype.body = function() {
return this.inst.body();
}
Request.prototype.json = function() {
let body = this.body();
if(body) {
return JSON.parse(body);
} else {
return null;
}
}
Request.prototype.form = function () {
let body = this.body();
if (!body) return null;
let form = {};
try {
body.toString().split("&").filter(v => v).map(v => v.split("=")).forEach(p => form[p[0]] = p[1]);
return form;
} catch (e) {
throw new Error("Request body is not valid urlencoded form");
}
}
Object.defineProperty(Request.prototype, "uri", {
get: function() {
return this.cache.uri || (this.cache.uri = this.inst.uri())
}
});
Object.defineProperty(Request.prototype, "url", {
get: function() {
return this.cache.url || (this.cache.url = this.uri.split("?")[0])
}
});
Object.defineProperty(Request.prototype, "headers", {
get: function() {
return this.cache.headers || (this.cache.headers = this.inst.headers())
}
});
Object.defineProperty(Request.prototype, "cookies", {
get: function() {
return this.cache.cookies || (this.cache.cookies = this.inst.cookies())
}
});
//module.exports.Response = Response;
function Response(req) {
if(!(this instanceof Response)) {
return new Response(...arguments);
}
if(!(req instanceof Request)) {
throw new Error("Request required");
}
this.inst = req.inst.createResponse();
this.detached = false;
}
Response.from = function(req, data) {
if(typeof(data) == "string" || data instanceof Buffer) {
return new Response(req).body(data);
}
throw new Error("Unable to convert data into Response");
}
Response.prototype.body = function(data) {
if(!(data instanceof Buffer)) {
data = Buffer.from(data);
}
this.inst.body(data);
return this;
}
Response.prototype.json = function(data) {
return this.body(JSON.stringify(data));
}
Response.prototype.file = function(p) {
this.inst.file(p);
return this;
}
Response.prototype.status = function(code) {
this.inst.status(code);
return this;
}
Response.prototype.header = function(k, v) {
this.inst.header(k, v);
return this;
}
Response.prototype.cookie = function(k, v) {
this.inst.cookie(k, v);
return this;
}
Response.prototype.renderTemplate = function(name, data) {
this.inst.renderTemplate(name, JSON.stringify(data));
return this;
}
Response.prototype.stream = function(cb) {
const stream = this.inst.stream();
setImmediate(() => cb(stream));
return this;
}
Response.prototype.send = function() {
this.inst.send();
}
Response.prototype.detach = function() {
this.detached = true;
}
function generateEndpointHandler(mws, fn) {
return async function(req) {
req = new Request(req);
let resp = req.createResponse();
for(const mw of mws) {
// For dynamic dispatch
if(!req.uri.startsWith(mw.prefix)) {
continue;
}
try {
// An exception from a middleware leads to a normal termination of the flow.
await mw.handler(req, resp, mw);
} catch(e) {
resp.send();
return;
}
}
try {
// An exception from an endpoint handler leads to an abnormal termination.
await fn(req, resp);
} catch(e) {
console.log(e);
resp.status(500).send();
return;
}
if(!resp.detached) resp.send();
}
}
module.exports.Flag = Flag;
function Flag(name) {
if(!(this instanceof Flag)) {
return new Flag(...arguments);
}
this.name = name;
}
module.exports.static = require("./static.js");
Object.assign(module.exports, base);
module.exports.express = express.createApplication;
Object.assign(module.exports.express, express);
{
"name": "ice-node",
"version": "0.3.1",
"version": "0.3.2",
"description": "Bindings for the Ice Web Framework",

@@ -28,3 +28,5 @@ "main": "lib.js",

"homepage": "https://github.com/losfair/ice-node#readme",
"dependencies": {},
"dependencies": {
"mime": "^1.3.6"
},
"devDependencies": {

@@ -31,0 +33,0 @@ "randomstring": "^1.1.5",

@@ -0,1 +1,3 @@

**本文档对应的版本为 v0.2.x 。v0.3.x 的最新文档尚未完成。**
Ice-node 是目前**最快的** Node Web 框架,基于 [Ice Core](https://github.com/losfair/IceCore) 核心。

@@ -11,10 +13,8 @@

对于一个 Hello world 服务, Ice-node 比 Node HTTP 库快 10% ,比 Koa 快 80% ,比 Express 快 100% 。
对于一个 Hello world 服务, Ice-node 比 Node HTTP 库快 70% 。
##### 每秒请求数,越高越好
![Benchmark Result](http://i.imgur.com/TkV8IxE.png)
![Benchmark result](https://i.imgur.com/4uBIYMC.png)
[原始数据](https://gist.github.com/losfair/066b04978d6a5b27418d85a6305ecd5c)
对于执行数据库请求和简单逻辑的 Web 应用, Ice-node 比 Express 至少快 30% 。

@@ -21,0 +21,0 @@ 这是一个[测试应用](https://github.com/losfair/ice-node-perf-tests),

@@ -0,1 +1,3 @@

**This documentation is for v0.2.x. The latest documentation for v0.3.x is not ready yet.**
Ice-node is the **fastest** framework for building node web applications, based on [Ice Core](https://github.com/losfair/IceCore).

@@ -11,14 +13,12 @@

Ice-node is based on Ice Core, which is written in Rust and C++ and provides high-performance abstractions for the Web.
Ice-node is based on Ice Core, which is written in Rust and provides high-performance abstractions for the Web.
When serving the "Hello world!" text, Ice-node is about 10% faster than the raw Node.js http implementation, 80% than Koa, and 100% than Express, while providing full routing support.
When serving the "Hello world!" text, Ice-node is about 70% faster than the raw Node.js http implementation, while providing full routing support.
##### Requests per second, higher is better
![Benchmark Result](http://i.imgur.com/TkV8IxE.png)
![Benchmark result](https://i.imgur.com/4uBIYMC.png)
[Raw Results](https://gist.github.com/losfair/066b04978d6a5b27418d85a6305ecd5c)
For practical applications that do database queries and some logic, Ice-node is also at least 30% faster than traditional Node web frameworks like Express.
For practical applications that do database queries and some logic, Ice-node is also at least 30% faster than Express.
We wrote a [test application](https://github.com/losfair/ice-node-perf-tests) that simulates some common API services like login and data fetching and do MongoDB queries when processing requests,

@@ -40,6 +40,7 @@ and fire up 500 concurrent clients, each doing 101 requests:

const ice = require("ice-node");
const app = new ice.Ice();
const app = new ice.Application();
app.get("/", req => "Hello world!");
app.get("/", (req, resp) => resp.body("Hello world!"));
app.prepare();
app.listen("127.0.0.1:3535");

@@ -61,3 +62,3 @@

With `const app = new ice.Ice()`, you creates an Ice-node **Application** - an object describing how requests will be handled and how your data will be presented to users,
With `const app = new ice.Application()`, you creates an Ice-node **Application** - an object describing how requests will be handled and how your data will be presented to users,
containing arrays of `routes`, `middlewares`, key-value mappings of `templates`, and a `config` object.

@@ -72,4 +73,5 @@

app.get("/:text", req => req.params.text);
app.get("/:text", (req, resp) => resp.body(req.params.text));
app.prepare();
app.listen("127.0.0.1:3536");

@@ -86,15 +88,12 @@

- `method` (string): Request method, in upper case (`GET`, `POST` etc.) .
- `host` (string): Alias for `headers.host`.
- `cookies` (proxied object): Key-value mappings of cookies in the `Cookie` header.
- `session` (proxied object): Key-value read and write access to the session of the request.
- `params` (proxied object): Key-value mappings of params in request URL.
- `cookies` (object): Key-value mappings of cookies in the `Cookie` header.
- `session` (object): Key-value read and write access to the session of the request.
- `params` (object): Key-value mappings of params in request URL.
For example, the following code:
app.get("/ip", req => req.remote_addr.split(":")[0]);
app.get("/ip", (req, resp) => resp.body(req.remote_addr.split(":")[0]));
will return the visitor's IP address.
All of the proxied object do lazy load, bringing zero overhead if you don't use them.
### Middlewares and Endpoints

@@ -101,0 +100,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc