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

alaska

Package Overview
Dependencies
Maintainers
1
Versions
96
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

alaska - npm Package Compare versions

Comparing version 0.0.5 to 0.1.0

.idea/.name

133

lib/alaska.js

@@ -24,12 +24,11 @@ 'use strict';

*
* alaska.start('blog').then(function(){
* console.log('blog started');
* alaska.launch('blog').then(function(){
* console.log('blog launched');
* });
*
* let other = new alaska.Alaska();
* other.start('shop').then(function(){
* console.log('shop started);
* other.launch('shop').then(function(){
* console.log('shop launched);
* });
* ```
* @extends events.EventEmitter
*/

@@ -41,3 +40,2 @@ class Alaska {

* @constructor
* @fires Alaska#create
*/

@@ -47,3 +45,3 @@

/**
* 允许资源所有者访问接口
* 允许已经认证的用户访问接口
*/

@@ -53,3 +51,4 @@

/**
* 允许所有用户访问接口
* 接口关闭
* @type {number}
*/

@@ -59,3 +58,3 @@

/**
* HTTP状态码422 REST接口create/update数据验证失败
* HTTP状态码405 REST接口HTTP方法不允许
*/

@@ -65,3 +64,3 @@

/**
* HTTP状态码404 REST接口show/list请求的资源不存在
* HTTP状态码403 REST已授权,但是没有权限
*/

@@ -71,3 +70,3 @@

/**
* HTTP状态码401 REST接口未授权
* HTTP状态码400 REST接口create/update请求未识别,错误的请求
*/

@@ -77,9 +76,4 @@

/**
* HTTP状态码204 REST接口remove成功
* HTTP状态码201 REST接口create/update成功
*/
/**
* HTTP状态码200 REST接口show/list方法成功
*/
constructor() {

@@ -99,5 +93,2 @@ this.OK = 200;

this.OWNER = 3;
this._loaded = false;
this._routed = false;
this._started = false;
this._app = null;

@@ -112,2 +103,3 @@ this._services = {};

this.Service = require('./service');
this.Field = require('./field');
this.defaultAlaska = defaultAlaska ? defaultAlaska : this;

@@ -123,3 +115,3 @@ }

/**
* 允许已经认证的用户访问接口
* 允许资源所有者访问接口
*/

@@ -129,4 +121,3 @@

/**
* 接口关闭
* @type {number}
* 允许所有用户访问接口
*/

@@ -136,3 +127,3 @@

/**
* HTTP状态码405 REST接口HTTP方法不允许
* HTTP状态码422 REST接口create/update数据验证失败
*/

@@ -142,3 +133,3 @@

/**
* HTTP状态码403 REST已授权,但是没有权限
* HTTP状态码404 REST接口show/list请求的资源不存在
*/

@@ -148,3 +139,3 @@

/**
* HTTP状态码400 REST接口create/update请求未识别,错误的请求
* HTTP状态码401 REST接口未授权
*/

@@ -154,4 +145,9 @@

/**
* HTTP状态码201 REST接口create/update成功
* HTTP状态码204 REST接口remove成功
*/
/**
* HTTP状态码200 REST接口show/list方法成功
*/
app() {

@@ -191,3 +187,2 @@ if (!this._app) {

* 注册新的Service
* @fires Alaska#registerService
* @param {Service} service Service对象

@@ -221,10 +216,2 @@ */

/**
* 定义或者找回此Alaska实例下的Model
* @param {string} name 模型名称
* @param {Object} [options] 模型定义
* @returns {Model|null}
*/
model(name, options) {}
/**
* 获取当前主配置的数据库链接

@@ -238,6 +225,4 @@ * @returns {mongoose.Connection | null}

/**
* 启动Alaska实例
* @fires Alaska#start
* [async]启动Alaska实例
* @param {string|Object} options 默认Service配置信息,此参数将传递给Service的初始化函数
* @returns {Promise}
*/

@@ -256,3 +241,3 @@ launch(options) {

yield _this._mainService.init();
yield _this._mainService.load();
yield _this._mainService.loadModels();
yield _this._mainService.route();

@@ -267,3 +252,3 @@ yield _this._mainService.launch();

* 输出Alaska实例JSON调试信息
* @returns {Object}
* @returns {object}
*/

@@ -275,2 +260,46 @@ toJSON() {

}
/**
* 抛出严重错误,并输出调用栈
* @param message
* @param code
*/
panic(message, code) {
let error = new defaultAlaska.PanicError(message);
if (code) {
error.code = code;
}
console.error('Panic ' + error.stack);
throw error;
}
/**
* 抛出普通异常
* @param {string|Error} message
* @param {string|number} code
*/
error(message, code) {
let error = new defaultAlaska.NormalError(message);
if (code) {
error.code = code;
}
throw error;
}
/**
* [async]执行一个异步任务,如果失败则抛出NormalError
* @param {Promise} promise
* @returns {*}
*/
try(promise) {
var _this2 = this;
return _asyncToGenerator(function* () {
try {
return yield promise;
} catch (error) {
_this2.error(error);
}
})();
}
}

@@ -281,2 +310,24 @@

/**
* 一般错误
* @class {NormalError}
*/
defaultAlaska.NormalError = class NormalError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
};
/**
* 严重错误
* @class {PanicError}
*/
defaultAlaska.PanicError = class PanicError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
};
module.exports = defaultAlaska;

@@ -15,5 +15,5 @@ 'use strict';

* REST接口默认控制器
* 本控制器默认关闭,开启默认REST接口,需要将PKG配置中的rest项设置为true,并且打开各个模型的设置
* 例如 `UserModel.options.rest=false` 将关闭UserModel模型所有的默认REST接口
* `UserModel.options.rest={list:1,show:1}` 将只打开list和show接口
* 本控制器默认关闭,开启默认REST接口,需要将Service配置中的rest项设置为true,并且打开各个模型的设置
* 例如 `User.rest=false` 将关闭User模型所有的默认REST接口
* `User.rest={list:1,show:1}` 将只打开list和show接口
* 不同的数值代表:

@@ -20,0 +20,0 @@ * > list接口 1:允许匿名调用此接口 2:允许认证后的用户调用 3:只允许用户列出自己的资源

@@ -27,5 +27,8 @@ 'use strict';

* [APP] APP中间件列表
* @type {Array}
* @type {array}
*/
appMiddlewares: [],
appMiddlewares: ['koa-logger', {
name: 'koa-bodyparser',
options: {}
}],

@@ -43,2 +46,14 @@ /**

env: 'development',
/**
* [APP] session
* @type {object|string}
*/
session: {
type: 'alaska-cache-lru',
cookie: {},
store: {
maxAge: 1000 * 60 * 60
}
},
//

@@ -50,3 +65,3 @@ // KOA settings

* [KOA] 代理模式
* @type {Boolean}
* @type {boolean}
*/

@@ -65,8 +80,2 @@ proxy: false,

/**
* [Service] 别名列表
* @type {Array}
*/
alias: [],
/**
* [Service] 域名,如果不指定,子Service将使用主Service的域名

@@ -99,8 +108,23 @@ * 例如 docs.google.com *.58.com

* [Service] 控制器路由接受的HTTP方法列表
* @type {Array}
* @type {array}
*/
methods: ['GET', 'POST'],
/**
* [Service] 静态目录列表
* @type {Array|string|object}
*/
statics: '',
/**
* [Service] 模板引擎
* @type {string}
*/
render: 'swig',
/**
* [Service] 模板目录
* @type {string}
*/
templates: 'templates',
/**
* [Service] 该Service依赖的子Service列表
* @type {Array}
* @type {array}
*/

@@ -110,3 +134,3 @@ services: [],

* [Service] 该Service的路由中间件
* @type {Array}
* @type {array}
*/

@@ -122,4 +146,20 @@ middlewares: [],

/**
* [Service] 数据库collection前缀
* @type {Boolean|string}
*/
dbPrefix: false,
/**
* [Service] 缓存设置或已经实例化的缓存驱动对象
* @type {Object|string}
*/
cache: {
type: 'alaska-cache-lru',
prefix: false,
store: {
maxAge: 3600 * 24 * 1000
}
},
/**
* 是否开启控制器路由
* @type {Boolean}
* @type {boolean}
*/

@@ -129,6 +169,5 @@ controllers: true,

* 是否开启rest api
* @type {Boolean}
* @type {boolean}
*/
api: true
};
'use strict';
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { return step("next", value); }, function (err) { return step("throw", err); }); } } return step("next"); }); }; }
/**

@@ -13,8 +15,30 @@ * @copyright Maichong Software Ltd. 2016 http://maichong.it

const Schema = mongoose.Schema;
const BaseField = require('./field');
const util = require('./util');
function panic() {
throw new Error('Can not call the function after Model register.');
throw new Error('Can not call the function when Model has been registered.');
}
class Model {
/**
* Data
* @type {{pick: (function()), omit: (function())}}
*/
const Data = {
pick() {
let data = _.pick.apply(_, [this].concat(Array.prototype.slice.call(arguments))) || {};
data.__proto__ = Data;
return data;
},
omit() {
let data = _.omit.apply(_, [this].concat(Array.prototype.slice.call(arguments))) || {};
data.__proto__ = Data;
return data;
}
};
/**
* @class Model
*/
class BaseModel {
constructor() {

@@ -27,2 +51,7 @@ throw new Error('Can not initialize a Model before register.');

/**
* 注册前置钩子
* @param {string} action 动作名称,Init|Validate|Save|Remove
* @param {function} fn
*/
static pre(action, fn) {

@@ -34,2 +63,7 @@ this._pre || (this._pre = {});

/**
* 注册后置钩子
* @param {string} action 动作名称,Init|Validate|Save|Remove
* @param {function} fn
*/
static post(action, fn) {

@@ -41,7 +75,33 @@ this._post || (this._post = {});

/**
* 注册underscore方法
* @param {string} field 绑定的字段
* @param {string} name 方法名
* @param {Function} fn 方法
*/
static underscoreMethod(field, name, fn) {
this._underscore || (this._underscore = {});
this._underscore[field] || (this._underscore[field] = {});
this._underscore[field][name] = fn;
}
/**
* 注册
*/
static register() {
let service = __service;
let Model = this;
/**
* 模型所属服务
* @type {alaska.Service}
*/
Model.service = service;
/**
* 标识模型对象
* @type {boolean}
*/
Model.isModel = true;
let MongooseModel;

@@ -53,40 +113,93 @@ let name = Model.name;

//整理字段列表
let fields = {};
for (let key in Model.fields) {
let field = Model.fields[key];
let schema = Model.schema = new Schema({}, {
collection: Model.collection || (Model.prefix || service.dbPrefix) + name.replace(/([a-z])([A-Z])/g, (a, b, c) => b + '_' + c).toLowerCase()
});
function loadFieldConfig(fieldTypeName) {
let config = service.config(true, fieldTypeName);
if (!config) {
return {};
}
if (config.type && config.type != fieldTypeName) {
let otherConfig = loadFieldConfig(config.type);
return _.assign({}, config, otherConfig);
}
return _.clone(config);
}
//将Model字段注册到Mongoose.Schema中
for (let path in Model.fields) {
let field = Model.fields[path];
if (typeof field === 'function') {
Model.fields[path] = field = { type: field };
}
if (!field.type) {
throw new Error(Model.name + '.' + path + ' field type not specified');
}
if (_.isArray(field.type) && field.type.length === 1) {
// type : [ OtherModel ]
let OtherModel = field.type[0];
field.type = 'relationship';
field.ref = OtherModel;
field.multi = true;
}
if (field.type.isModel) {
let OtherModel = field.type;
field.type = 'relationship';
field.ref = OtherModel;
}
field.path = path;
if (!field.type) {
throw new Error('Field type is not specified. ' + name);
}
let FieldType;
if (field.type === String) {
FieldType = require('alaska-field-text');
} else if (field.type === Date) {
FieldType = require('alaska-field-date');
} else if (field.type === Boolean) {
FieldType = require('alaska-field-checkbox');
} else if (field.type === Number) {
FieldType = require('alaska-field-number');
let AlaskaFieldType;
if (typeof field.type === 'object' && field.type.plain) {
AlaskaFieldType = field.type;
} else {
FieldType = field.type;
let fieldTypeName;
if (field.type === String) {
fieldTypeName = 'alaska-field-text';
} else if (field.type === Date) {
fieldTypeName = 'alaska-field-datetime';
} else if (field.type === Boolean) {
fieldTypeName = 'alaska-field-checkbox';
} else if (field.type === Number) {
fieldTypeName = 'alaska-field-number';
} else if (typeof field.type === 'string') {
fieldTypeName = 'alaska-field-' + field.type;
} else {
throw new Error(`Unsupported field type for ${ Model.name }.${ path }`);
}
field.type = fieldTypeName;
_.assign(field, loadFieldConfig(fieldTypeName));
AlaskaFieldType = require(field.type);
}
field.type = FieldType;
let options = {
type: FieldType.plain
};
//将用户定义的选项传给Mongoose
FieldType.update && FieldType.update(field, options);
if (_.has(field, 'default')) {
options.default = field.default;
//console.log(AlaskaFieldType, field);
field.type = AlaskaFieldType;
field.label = field.label || path.toUpperCase();
if (AlaskaFieldType.initSchema) {
AlaskaFieldType.initSchema(field, schema, Model);
} else {
BaseField.initSchema.call(AlaskaFieldType, field, schema, Model);
}
fields[key] = options;
}
let schema = Model.schema = new Schema(fields);
let groups = {};
schema.virtual('_').get(function () {
if (!this.__methods) {
this.__methods = util.bindMethods(Model._underscore, this);
}
return this.__methods;
});
_.defaults(Model, {
title: 'title',
userField: 'user',
api: false,
searchFields: '',
defaultSort: ''
defaultSort: '',
defaultColumns: '',
label: Model.name,
groups: {}
});

@@ -104,2 +217,13 @@ if (Model.api === 1) {

//允许自动缓存
if (Model.cache) {
//保存成功后更新缓存
Model.post('save', function () {
Model.setCache(this);
});
Model.post('remove', function () {
Model.delCache(this);
});
}
Model._pre || (Model._pre = []);

@@ -167,80 +291,224 @@ Model._post || (Model._post = []);

Model.register = panic;
Model.pre = panic;
Model.post = panic;
delete Model._pre;
delete Model._post;
['paginate', 'createCacheKey', 'getCache', 'setCache', 'delCache', 'castCache', 'castCacheArray', 'castModelArray'].forEach(key => {
Model[key] = BaseModel[key];
});
//register
let db = service.db();
MongooseModel = db.model(name, schema);
/**
*
* @param Object options
* @returns {mongoose.Query}
* 原始Mongoose模型
* @type mongoose.Model
*/
Model.paginate = function (options) {
options = options || {};
let page = parseInt(options.page) || 1;
let perPage = parseInt(options.perPage) || 10;
let skip = (page - 1) * perPage;
let search = options.search || '';
Model.MongooseModel = MongooseModel;
Model.__proto__ = MongooseModel;
Model.prototype.__proto__ = MongooseModel.prototype;
//TODO search & filter
let query = this.find(options.filters);
/**
* 返回格式化数据
* @returns {Data}
*/
Model.prototype.data = function () {
//TODO data()
let doc = {};
for (let key in this.schema.tree) {
if (key[0] == '_' || !Model.fields[key] || Model.fields[key].private) {
continue;
}
if (this._[key] && this._[key].data) {
doc[key] = this._[key].data();
} else {
doc[key] = this.get(key);
}
}
doc.id = this.id;
doc.__proto__ = Data;
return doc;
};
}
query.originalExec = query.exec;
/**
* 分页查询
* @param {object} options
* @returns {mongoose.Query}
*/
static paginate(options) {
options = options || {};
let page = parseInt(options.page) || 1;
let perPage = parseInt(options.perPage) || 10;
let skip = (page - 1) * perPage;
let search = options.search || '';
let results = {
total: 0,
page: page,
perPage: perPage,
previous: page <= 1 ? false : page - 1,
next: false,
results: []
};
//TODO search & filter
let query = this.find(options.filters);
query.exec = function (callback) {
callback = callback || _.noop;
query.originalExec = query.exec;
return new Promise(function (resolve, reject) {
query.exec = query.originalExec;
query.count(function (error, total) {
let results = {
total: 0,
page: page,
perPage: perPage,
previous: page <= 1 ? false : page - 1,
next: false,
results: []
};
query.exec = function (callback) {
callback = callback || _.noop;
return new Promise(function (resolve, reject) {
query.exec = query.originalExec;
query.count(function (error, total) {
if (error) {
return reject(error);
}
if (!total) {
callback(null, results);
resolve(results);
return;
}
results.total = total;
results.next = Math.ceil(total / perPage) > page ? page + 1 : false;
query.find().limit(perPage).skip(skip).exec(function (error, res) {
if (error) {
return reject(error);
}
if (!total) {
callback(null, results);
resolve(results);
return;
}
results.total = total;
results.next = Math.ceil(total / perPage) > page ? page + 1 : false;
query.find().limit(perPage).skip(skip).exec(function (error, res) {
if (error) {
return reject(error);
}
results.results = res;
callback(null, results);
resolve(results);
});
results.results = res;
callback(null, results);
resolve(results);
});
});
};
return query;
});
};
//register
return query;
}
let db = service.db();
MongooseModel = db.model(name, schema);
/**
* 依据记录ID,生成数据缓存所使用的cache key
* @param {string} id
* @returns {*}
*/
static createCacheKey(id) {
return `model_cache_${ this.service.name }.${ this.name }_${ id }`;
}
Model.__proto__ = MongooseModel;
Model.prototype.__proto__ = MongooseModel.prototype;
Model.prototype.data = function () {
//TODO data()
let doc = this;
return doc.toObject();
};
/**
* 获取某条记录的缓存,如果没有找到缓存数据,则查询数据库
* @param {string} id
* @returns {Model}
*/
static getCache(id) {
var _this = this;
return _asyncToGenerator(function* () {
let cache;
let cacheKey;
if (_this.cache) {
//模型允许自动缓存
cache = _this.service.cache();
cacheKey = _this.createCacheKey(id);
let data = yield cache.get(cacheKey);
if (data) {
return _this.castCache(data);
}
}
//没有找到缓存数据
let record = yield _this.findById(id);
if (record && cache) {
_this.setCache(record);
}
return record;
})();
}
/**
* 设置模型缓存
* @param {Model} record
*/
static setCache(record) {
var _this2 = this;
return _asyncToGenerator(function* () {
let cacheKey = _this2.createCacheKey(record.id);
let cache = _this2.service.cache();
yield cache.set(cacheKey, cache.noSerialization ? record : record.toObject(), _this2.cache);
})();
}
/**
* 删除模型缓存
* @param {string} id
*/
static delCache(id) {
var _this3 = this;
return _asyncToGenerator(function* () {
let cacheKey = _this3.createCacheKey(id);
let cache = _this3.service.cache();
yield cache.del(cacheKey);
})();
}
/**
* 将object数据转为Model对象
* @param data
* @returns {Model}
*/
static castCache(data) {
let cache = this.service.cache();
if (cache.noSerialization) {
//缓存驱动不需要序列化
return data;
}
//缓存驱动需要序列化
let record = new this(null, null, true);
record.init(data);
return record;
}
/**
* 将object数组转为Model对象数组
* @param {[Object]} array
* @returns {[Model]}
*/
static castCacheArray(array) {
let cache = this.service.cache();
if (cache.noSerialization) {
//缓存驱动不需要序列化
return array;
}
return _.map(array, data => this.castCache(data));
}
/**
* 将模型数组转为plain object数组
* @param {[Model]} array
* @returns {array}
*/
static castModelArray(array) {
let cache = this.service.cache();
if (cache.noSerialization) {
//缓存驱动不需要序列化
return array;
}
return _.map(array, record => record.toObject());
}
}
Model.fields = null;
module.exports = Model;
BaseModel.fields = null;
BaseModel.cache = 0;
BaseModel.prefix = '';
BaseModel.collection = '';
module.exports = BaseModel;

@@ -11,6 +11,4 @@ 'use strict';

const assert = require('assert');
const _ = require('lodash');
const Router = require('koa-router');
const compose = require('koa-compose');
const collie = require('collie');

@@ -34,4 +32,28 @@ const util = require('./util');

*/
/**
* 所依赖的子Service实例对象别名映射表
* @type {object}
* @private
*/
/**
* 本Service的所有额外配置目录
* @type {[string]}
* @private
*/
/**
* 数据库连接实例
* @type {mongoose.Connection}
* @private
*/
/**
* 路由器
* @type {Router}
* @private
*/
constructor(options, alaska) {
this._router = false;
this._router = null;
this._controllers = {};

@@ -42,2 +64,3 @@ this._apiControllers = {};

this._config = {};
this._configDirs = [];
this._services = [];

@@ -49,5 +72,11 @@ this._alias = {};

collie(this, 'init');
collie(this, 'load');
collie(this, 'route');
this.panic = alaska.panic;
collie(this, 'init', require('./service/init'));
collie(this, 'loadModels', require('./service/loadModels'));
collie(this, 'route', require('./service/route'));
collie(this, 'loadAppMiddlewares', require('./service/loadAppMiddlewares'));
collie(this, 'loadMiddlewares', require('./service/loadMiddlewares'));
collie(this, 'loadApi', require('./service/loadApi'));
collie(this, 'loadControllers', require('./service/loadControllers'));
collie(this, 'loadStatics', require('./service/loadStatics'));
collie(this, 'launch');

@@ -64,6 +93,4 @@ collie(this, 'registerModel');

this.debug = require('debug')(this._options.id);
this.debug = debug;
this.debug('init');
if (!this._options.dir) {

@@ -77,3 +104,2 @@ throw new Error('Service dir is not specified.');

}
this.id = this._options.id;
this.alaska = alaska;

@@ -83,3 +109,3 @@

//载入配置
let configFilePath = this._options.dir + '/configs/' + this._options.configFile;
let configFilePath = this._options.dir + '/config/' + this._options.configFile;
let config = util.include(configFilePath);

@@ -99,2 +125,50 @@ if (config) {

/**
* Service id
* @returns {string}
*/
/**
* Model基类
* @type {Model}
*/
/**
* 所依赖的子Service实例对象列表
* @type {[Service]}
* @private
*/
/**
* 本Service的配置项
* @type {object}
* @private
*/
/**
* 本Service数据模型列表
* @type {object}
* @private
*/
get id() {
return this._options.id;
}
/**
* Service 目录
* @returns {string}
*/
get dir() {
return this._options.dir;
}
/**
* 追加配置项
* @param {object} config
*/
applyConfig(config) {
this._config = _.assign({}, this._config, config);
}
/**
* 判断当前Service是否是主Service

@@ -122,338 +196,55 @@ * @returns Boolean

/**
* 初始化
* [async] 初始化
* @method init
*/
init() {
var _this = this;
return _asyncToGenerator(function* () {
debug('%s load', _this.id);
_this.init = util.noop;
/**
* [async] 加载数据模型
* @method loadModels
*/
let services = _this.config('services') || [];
if (typeof services === 'string') {
services = [services];
}
for (let service of services) {
let serviceId = service;
let serviceAlias = '';
if (service.alias) {
//如果Service配置有别名
serviceAlias = service.alias;
serviceId = service.id;
}
assert(typeof serviceId === 'string', 'Sub service id should be string.');
let sub = _this.alaska.service(serviceId);
_this._services.push(sub);
assert(!_this._alias[serviceId], 'Service alias is exists.');
_this._alias[serviceId] = sub;
if (serviceAlias) {
assert(!_this._alias[serviceAlias], 'Service alias is exists.');
_this._alias[serviceAlias] = sub;
}
yield sub.init();
}
})();
}
/**
* 加载
* [async]配置路由
* @method route
*/
load() {
var _this2 = this;
return _asyncToGenerator(function* () {
debug('%s load', _this2.id);
_this2.load = util.noop;
for (let service of _this2._services) {
yield service.load();
}
if (_this2.config('db') !== false) {
global.__service = _this2;
_this2._models = util.include(_this2._options.dir + '/models');
for (let name in _this2._models) {
yield _this2.registerModel(_this2._models[name]);
}
}
})();
}
/**
* 载入APP中间件
* @private
* [async] 载入APP中间件
* @method loadAppMiddlewares
*/
_loadAppMiddlewares() {
this._loadAppMiddlewares = util.noop;
let app = this.alaska.app();
let alaska = this.alaska;
let service = this;
app.use(function (ctx, next) {
ctx.service = service;
ctx.alaska = alaska;
return next();
});
this.config('appMiddlewares', []).forEach(function (name) {
if (typeof name === 'function') {
//数组中直接就是一个中间件函数
app.use(name);
return;
}
let options;
if (typeof name === 'object') {
options = name.options;
name = name.name;
}
if (name.startsWith('.')) {
//如果是一个文件路径
name = this._options.dir + '/' + name;
}
let middleware = require(name);
app.use(middleware(options));
});
}
/**
* 载入Service中间件
* @private
* [async] 载入Service中间件
* @method loadMiddlewares
*/
_loadServiceMiddlewares() {
let router = this.router();
//middlewares for service
this.config('middlewares', []).forEach(function (item) {
if (typeof item === 'string') {
item = {
name: item
};
}
let name = item.name;
if (name.startsWith('.')) {
name = this._options.dir + name;
}
let middleware = require(name);
let path = item.path;
if (!path) {
router.use(path, middleware(item.options));
return;
}
let methods = item.methods || ['GET', 'POST'];
if (methods === 'all') {
router.all(path, middleware(item.options));
return;
}
if (typeof methods === 'string') {
methods = [methods];
}
router.register(path, methods, middleware(item.options));
});
}
/**
* 载入API接口控制器
* @private
* [async] 载入API接口控制器
* @method loadApi
*/
_loadApiControllers() {
let alaska = this.alaska;
let service = this;
let router = this.router();
this._apiControllers = util.include(this._options.dir + '/api');
let defaultApiController = require('./api');
let bodyParser = require('koa-bodyparser')();
//TODO 优化性能
function restApi(action) {
return function (ctx, next) {
function onError(error) {
console.error(service.id + ' API ' + error.stack);
if (!ctx.body) {
if (ctx.status === 404) {
ctx.status = 500;
}
ctx.body = {
error: error.message
};
}
}
try {
if (['show', 'update', 'remove'].indexOf(action) > -1) {
if (!/^[a-f0-9]{24}$/.test(ctx.params.id)) {
ctx.status = alaska.BAD_REQUEST;
return;
}
}
//console.log(ctx.params.model);
//console.log(service);
//console.log(service._models);
let Model = service._models[ctx.params.model];
//console.log(Model);
if (!Model) {
//404
return;
}
let modelId = ctx.params.model.toLowerCase();
let middlewares = [];
// api 目录下定义的中间件
if (service._apiControllers[modelId] && service._apiControllers[modelId][action]) {
middlewares.push(service._apiControllers[modelId][action]);
}
// Model.api参数定义的中间件
if (Model.api && Model.api[action]) {
middlewares.push(defaultApiController[action]);
}
//console.log(middlewares);
if (!middlewares.length) {
//404
return;
}
ctx.Model = Model;
return compose(middlewares)(ctx).catch(onError);
} catch (error) {
onError(error);
return;
}
};
}
router.get('/api/:model/count', restApi('count'));
router.get('/api/:model/:id', restApi('show'));
router.get('/api/:model', restApi('list'));
router.post('/api/:model', bodyParser, restApi('create'));
router.put('/api/:model/:id', bodyParser, restApi('update'));
router.del('/api/:model/:id', restApi('remove'));
}
/**
* 载入控制器
* @private
* [async] 载入控制器
* @method loadControllers
*/
_loadControllers() {
let router = this.router();
let service = this;
this._controllers = util.include(this._options.dir + '/controllers', false);
router.register('/:controller?/:action?', ['GET', 'HEAD', 'POST'], function (ctx, next) {
let controller = ctx.params.controller || service.config('defaultController');
let action = ctx.params.action || service.config('defaultAction');
service.debug('route %s:%s', controller, action);
if (service._controllers[controller] && service._controllers[controller][action] && action[0] !== '_') {
return service._controllers[controller][action](ctx, next);
}
next();
});
}
/**
* 配置路由
* @fires Service#route
* [async] 加载资源服务
* @method loadStatics
*/
route() {
var _this3 = this;
return _asyncToGenerator(function* () {
debug('route %s', _this3.id);
_this3.route = util.noop;
let app = _this3.alaska.app();
let router = _this3.router();
if (_this3.isMain()) {
_this3._loadAppMiddlewares();
}
//配置子Service路由
for (let sub of _this3._services) {
yield sub.route();
}
_this3._loadServiceMiddlewares();
//API 接口
if (_this3.config('api')) {
_this3._loadApiControllers();
}
//控制器
if (_this3.config('controllers')) {
_this3._loadControllers();
}
//路由表
let routes = router.routes();
//精确匹配域名
let exact = true;
//Service域名
let domain = _this3.config('domain', '');
if (domain.startsWith('*.')) {
domain = domain.substr(2);
exact = false;
}
//如果是主域名,匹配失败后的跳转地址
let redirect;
if (_this3.isMain()) {
redirect = _this3.config('redirect', '');
}
let service = _this3;
app.use(function (ctx, next) {
ctx.subdomain = '';
ctx.service = service;
if (domain) {
let hostname = ctx.hostname;
if (exact) {
//如果精确匹配域名
if (hostname !== domain) {
redirect && ctx.redirect(redirect);
return;
}
} else {
//分析子域名
let index = hostname.lastIndexOf(domain);
if (index === -1) {
redirect && ctx.redirect(redirect);
return;
}
ctx.subdomain = hostname.substring(0, index - 1);
}
}
//domain not set
let toJSON = ctx.toJSON;
ctx.toJSON = function () {
let json = toJSON.call(ctx);
json.subdomain = ctx.subdomain;
json.alaska = ctx.alaska.toJSON();
json.service = ctx.service.toJSON();
return json;
};
return routes(ctx, next);
});
})();
}
/**
* 启动Service
* @fires Service#start
* [async] 启动Service
* @method launch
*/
launch() {
var _this4 = this;
var _this = this;
return _asyncToGenerator(function* () {
debug('%s start', _this4.id);
_this4.launch = util.noop;
debug('%s launch', _this.id);
_this.launch = util.noop;
yield _this4.init();
yield _this4.load();
yield _this4.route();
yield _this.init();
yield _this.loadModels();
yield _this.route();
})();

@@ -464,4 +255,4 @@ }

* 获取当前Service配置
* @param {Boolean} [mainAsDefault] 如果当前Service中不存在配置,则获取主Service的配置
* @param {String} path 配置名
* @param {boolean} [mainAsDefault] 如果当前Service中不存在配置,则获取主Service的配置
* @param {string} path 配置名
* @param {*} [defaultValue] 默认值

@@ -514,2 +305,34 @@ */

/**
* 获取缓存驱动
* @returns {LruDriver|*}
*/
cache() {
if (!this._cache) {
let options = this.config('cache');
if (_.isString(options)) {
options = { type: options };
}
if (options.isCacheDriver) {
//已经实例化的缓存驱动
this._cache = options;
} else {
let Driver = require(options.type);
this._cache = new Driver(options.store || {});
}
}
return this._cache;
}
/**
* 获取模板引擎
* @returns {*}
*/
engine() {
if (!this._engine) {
this._engine = require(this.config('render'));
}
return this._engine;
}
/**
* 获取当前Service所依赖的子Service

@@ -524,3 +347,3 @@ * @returns {Service}

* 输出Service实例JSON调试信息
* @returns {Object}
* @returns {object}
*/

@@ -561,7 +384,12 @@ toJSON() {

/**
* 注册模型
* @param {Model} Model
* @returns {Model}
*/
registerModel(Model) {
var _this5 = this;
var _this2 = this;
return _asyncToGenerator(function* () {
global.__service = _this5;
global.__service = _this2;
Model.register();

@@ -568,0 +396,0 @@ return Model;

@@ -10,2 +10,3 @@ 'use strict';

const fs = require('fs');
const _ = require('lodash');

@@ -42,3 +43,3 @@ /**

* @param importDefault
* @returns {Object}
* @returns {object}
*/

@@ -65,5 +66,33 @@ exports.include = function include(path) {

/**
* 判断某路径是否是隐藏的
* @param path
* @returns {boolean}
*/
exports.isHidden = function isHidden(path) {
return (/[\\\/]\.\w/.test(path)
);
};
const resolved = Promise.resolve();
exports.noop = function noop() {
return resolved;
};
/**
* 递归将obj上所有的方法绑定至scope
* @param obj
* @param scope
* @returns {object}
*/
exports.bindMethods = function bindMethods(obj, scope) {
let bound = {};
for (let key in obj) {
if (typeof obj[key] === 'function') {
bound[key] = obj[key].bind(scope);
} else if (_.isObject(obj[key])) {
bound[key] = bindMethods(obj[key], scope);
}
}
return bound;
};
{
"name": "alaska",
"version": "0.0.5",
"version": "0.1.0",
"description": "Modern web framework for Node.js",
"main": "index.js",
"main": "lib/alaska.js",
"dependencies": {
"collie": "^0.2.0",
"alaska-cache-lru": "^0.1.3",
"async-busboy": "0.0.4",
"collie": "^0.2.1",
"koa": "^2.0.0-alpha.3",

@@ -13,11 +15,15 @@ "koa-bodyparser": "^3.0.0",

"lodash": "^4.0.0",
"mongoose": "^4.3.6"
"mime": "^1.3.4",
"mongoose": "^4.4.5",
"mz": "^2.3.1",
"string-random": "^0.1.0",
"swig": "^1.4.2"
},
"devDependencies": {
"babel-plugin-syntax-async-functions": "^6.3.13",
"babel-plugin-syntax-class-properties": "^6.3.13",
"babel-plugin-transform-class-properties": "^6.4.0",
"babel-plugin-transform-es2015-destructuring": "^6.4.0",
"babel-plugin-transform-es2015-parameters": "^6.4.2",
"babel-plugin-transform-object-rest-spread": "^6.3.13",
"babel-plugin-syntax-async-functions": "^6.5.0",
"babel-plugin-syntax-class-properties": "^6.5.0",
"babel-plugin-transform-class-properties": "^6.6.0",
"babel-plugin-transform-es2015-destructuring": "^6.6.5",
"babel-plugin-transform-es2015-parameters": "^6.7.0",
"babel-plugin-transform-object-rest-spread": "^6.6.5",
"rimraf": "*"

@@ -24,0 +30,0 @@ },

@@ -5,4 +5,2 @@ #[alaska](https://github.com/maichong/alaska)

*Warning. This module is not stable yet.*
## Contribute

@@ -9,0 +7,0 @@ [Maichong Software](http://maichong.it)

Sorry, the diff of this file is not supported yet

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