这是啥

  • 模块加载器兼打包工具
  • 可以使用 require(XXX)来引入各模块
  • 加载器(loader)编译(JSX、sass、、、)
  • 以 commonJS 形式书写
  • 能打包、压缩混淆、图片转base64等
  • 扩展性强,插件机制完善,支持 React 热插拔

安装,配置

  • npm init,npm install webpack –save
  • webpack.config.js配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
var webpack = require('webpack');
module.exports = {
//入口文件配置
entry: {
a: "./a", b: "./b"
},
//出口文件输出配置
output: {
path: 'dist/js/page',//打包文件存放的绝对路径
filename: '[name].js'//打包后的文件名
publicPath:“/js” //网站运行时的访问路径
},
module: {
//加载器配置,需要npm install *-loader
loaders: [
//.css 文件使用 style-loader 和 css-loader 来处理
{ test: /\.css$/, loader: 'style-loader!css-loader' },
//.js 文件使用 jsx-loader 来编译处理
{ test: /\.js$/, loader: 'jsx-loader?harmony',exclude: /node_modules/ },//exclude排除
//.scss 文件使用 style-loader、css-loader 和 sass-loader 来编译处理
{ test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
//图片文件使用 url-loader 来处理,小于8kb的直接转为base64
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'},
{test: /\.json$/,loader: 'json'}
]
}
//插件项
plugins: [new webpack.CommonsChunkPlugin("init.js") ],//这个插件可以将多个打包后的资源中的公共部分打包成单独的文件,这里指定公共文件输出为“init.js” 生成文件:init.js,a.js,b.js
//其它解决方案配置
resolve: {
//查找module的话从这里开始查找
root: 'E:/github/flux-example/src', //绝对路径
//自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
extensions: ['', '.js', '.json', '.scss'],
//模块别名定义,方便后续直接引用别名,无须多写长长的地址
alias: {
AppStore : 'js/stores/AppStores.js',//后续直接 require('AppStore') 即可
ActionType : 'js/actions/ActionType.js',
AppAction : 'js/actions/AppAction.js'
}
}
};

打包

CommonsChunkPlugin 提取多个页面之间的公共模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
entry: {
p1: "./page1",
p2: "./page2",
p3: "./page3",
ap1: "./admin/page1",
ap2: "./admin/page2"
},
output: {
filename: "[name].js"
},
plugins: [
new CommonsChunkPlugin("admin-commons.js", ["ap1", "ap2"]),
new CommonsChunkPlugin("commons.js", ["p1", "p2", "admin-commons.js"])
]
};
// <script>s required:
// page1.html: commons.js, p1.js
// page2.html: commons.js, p2.js
// page3.html: p3.js
// admin-page1.html: commons.js, admin-commons.js, ap1.js
// admin-page2.html: commons.js, admin-commons.js, ap2.js

extract-text-webpack-plugin 独立打包

1
2
3
4
5
6
7
var webpack = require('webpack');
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
plugins: [commonsPlugin, new ExtractTextPlugin("[name].css")],
entry: {};
}

Props

  • properties 使用它把数据传给组件
  • 在挂载组件时设置
  • 只能实例上调用setProps,不许this.setProps
  • 使用this.props访问
1
2
3
4
5
6
7
验证props
propTypes: {
style: View.propTypes.style.isRequired,
elementStyle: View.propTypes.style,
}
//isRequired 可选

State

  • 组件状态
  • this.state 是组件私有的,可以通过调用 this.setState() 来改变它。当状态更新之后,组件重新渲染自己。动态更新的关键点是调用this.setState(),replaceState()使用新对象,替换所有内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var CommentBox = React.createClass({
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
});

实例化

  • 一个实例初次创建

getDefaultProps 只会被调用一次

getInitalState 每个实例调用一次

componentWillMount 首次渲染之前被调用,可以修改state

render 创建虚拟DOM,表示组件输出,必须要有的方法。只能通过this.props和this.state访问数据。返回null、false、任何React组件。只能有一个顶级组件,不能改变组件的状态或者修改DOM的输出。

componentDidMount 在真实的DOM渲染之后,可以通过this.getDOMNode()访问原生DOM,测量渲染的DOM元素高度,运行jQuery

1
2
3
4
5
6
7
8
9
10
11
12
var datasource=[];
var MyComponent=React.creatClass({
render:function(){
return <input />;
},
componentDidMount: function(){
$(this.getDOMNOde()).autocomplete({
sources: datasource
})
}
})

存在期

  • 组件已渲染好,可以和它交互

componentWillReceiveprops 通过父辈组件修改props、state

1
2
3
4
5
6
7
componentWillReceiveProps: function(nextProps) {
if (nextProps.checked !== undefined) {
this.setState({
checked: nextProps.checked
})
}
}

shouldComponentUpdate 优化组件渲染,确实组件是否要渲染新的props、state

componentWillUpdate 在组件接收到新的props或者state渲染之前调用,不可在此更新state、props,要借助componentWillReceiveprops更新state

componentDidUpdate 类似componentDidMount,在此更新已渲染的DOM

销毁&清理期

componentWillUnmountcomponentDidMount中添加的任务都要在此撤销,如定时器、事件监听

由来

  • Cookie+Session的方式,在用户登录通过验证后,服务端将 数据加密后 通过在响应头(Header)保存到客户端浏览器的Cookie(包含sid或token)中,同时服务器保留相对应的Session(文件或DB)。用户之后发起的请求(Request)都会携带Cookie信息,服 务端需要根据Cookie寻回对应的Session,从而完成验证,确认这是之前登陆过的用户。
  • API应该被设计成无状态的(Stateless)。这意味着没有登陆,注销的方法,也没有sessions,API的设计者同样也不能依赖Cookie,因为不能保证这些request是由浏览器所发出的

JWT介绍

  • 分为三段,通过解码可以得到:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1. Headers
// 包括类别(typ)、加密算法(alg);
{
"alg": "HS256",
"typ": "JWT"
}
// 2. Claims
// 包括需要传递的用户信息;
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
// 3. Signature
// 根据alg算法与私有秘钥进行加密得到的签名字串;
// 这一段是最重要的敏感信息,只能在服务端解密;
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
SECREATE_KEY
)

在使用过程中,服务端通过用户登录验证之后,将Header+Claim信息加密后得到第三段签名,然后将三段签名合并后返回给客户端。客户端获取到token后,应该在每次向服务器请求数据时附带这个token,然后服务端验证token。

  • 因此JWT是用来取代服务端的Session而非客户端Cookie的方案.对于客户端本地存储,不同的选择更多是出于安全性的考虑

  • 客户端在与服务器第一次通信时,通过一些可靠信息(用户名、密码)和服务器交换取token,这个token作为客服端再次请求的权限钥匙。Token通常比密码更加长而且复杂。JWTs通常会长达150个字符。一旦获得了token,在每次调用API的时候都要附加上它。把token想象成一个安全的护照。你在一个安全的前台验证你的身份(通过你的用户名和密码),如果你成功验证了自己,你就可以取得这个。当你走进大楼的时候(试图从调用API获取资源),你会被要求验证你的护照,而不是在前台重新验证。

client

  • client 头部值部分使用Bearer Authorization: Bearer
  • .set(‘Authorization’, ‘Bearer ‘ + token)

encoded

1
jwt.sign(payload, secretOrPrivateKey, options, [callback]);

payload Claims,即传递的用户信息,could be an object literal, buffer or string.if not,it will be coerced into a string using JSON.stringify.

secretOrPrivateKey is a string or buffer containing either the secret for HMAC algorithms, or the PEM encoded private key for RSA and ECDSA.字符串,或着fs.readFileSync读取的证书

options:

  • algorithm (default: HS256) 加密算法
  • expiresIn: expressed in seconds or an string describing a time span rauchg/ms. Eg: 60, "2 days", "10h", "7d" 有效期/分钟
  • audience
  • subject
  • issuer
  • noTimestamp
  • headers

Example

1
2
3
4
5
6
7
// sign with default (HMAC SHA256)
var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
// sign with RSA SHA256
var cert = fs.readFileSync('private.key'); // get private key
var token = jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256'});

decoded

1
2
3
4
5
6
7
8
var jwt = require('express-jwt');
app.get('/protected',
jwt({secret: 'shhhhhhared-secret'}),
function(req, res) {
if (!req.user.admin) return res.sendStatus(401);
res.sendStatus(200);
});

you can make some paths unprotected as follows:

1
2
//设置路由/token 不验证
app.use(jwt({ secret: 'shhhhhhared-secret'}).unless({path: ['/token']}));

By default, the decoded token is attached to req.user but can be configured with the requestProperty option.
默认解密后的token Claim内容加到req.user

1
2
//将解密后的token加到req.auth
jwt({ secret: publicKey, requestProperty: 'auth' });

安全性

  • XSS 主要原因是对用户输入信息不加过滤,导致用户 (被误导)恶意输入的Js代码在访问该网页时被执行,而Js可以读取当前网站域名下保存的Cookie信息.对用户输入的所有信息进行过滤即可,CDN服务也有可能引入不安全的Js脚本
  • CSRF,跨站请求伪造 主要利用Cookie是按照域名存储,同时访问某域名时浏览器会自动携带该域名所保存的Cookie信息这一特征.如果执意要将JWT存储在Cookie中,服务端则需要额外验证请求来源.将JWT保存在localStorage中,即将JWT放入Request Header中的Authorization位。

Managed transaction (auto-callback)

  • 事务将自动提交
  • sequelize.transaction
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
return models.sequelize.transaction(function(t) {
// chain all your queries here. make sure you return them.
return User.create({
firstName: 'Abraham',
lastName: 'Lincoln'
}, {
transaction: t
}).then(function(user) {
return user.setShooter({
firstName: 'John',
lastName: 'Boothe'
}, {
transaction: t
});
});
}).then(function(result) {
// Transaction has been committed
// result is whatever the result of the promise chain returned to the transaction callback
}).catch(function(err) {
// Transaction has been rolled back
// err is whatever rejected the promise chain returned to the transaction callback
});

Unmanaged transaction (then-callback)

  • 非自动提交事务
  • sequelize.transaction()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
return sequelize.transaction().then(function (t) {
return User.create({
firstName: 'Homer',
lastName: 'Simpson'
}, {transaction: t}).then(function (user) {
return user.addSibling({
firstName: 'Lisa',
lastName: 'Simpson'
}, {transaction: t});
}).then(function () {
t.commit();
}).catch(function (err) {
t.rollback();
});
});

Automatically pass transactions to all queries

  • 自动添加事务
  • 无需{ transaction: t }
  • require(‘continuation-local-storage’)
1
2
3
4
5
6
7
8
9
10
var cls = require('continuation-local-storage'),
namespace = cls.createNamespace('my-very-own-namespace');
sequelize.transaction(function (t1) {
namespace.get('transaction') === t1; // true
});
sequelize.transaction(function (t2) {
namespace.get('transaction') === t2; // true
});

Array transaction

  • 事务并行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
models.sequelize.transaction(function(t) {
return models.Products.create(args, {
transaction: t
}).then(function(result) {
return Promise.all([models.user.create({
name: 'test'
}, {
transaction: t
}), models.address.create({
id: '1'
}, {
transaction: t
})]).then(function() {})
})
})

push + promise.all 实现循环读取、写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
models.sequelize.transaction(function(t) {
var tranArray = [];
if (!_.isUndefined(args.categories_id)) {
var categories_idArray = args.categories_id.split(',');
tranArray.push(models.Categories_product.destroy({
where: {
product_id: product_id
}
}, {
transaction: t
}));
categories_idArray.forEach(function(categories_id) {
tranArray.push(models.Categories_product.create({
product_id: product_id,
categories_id: categories_id
}, {
transaction: t
}));
});
}
if (_.isUndefined(areacode)) {
tranArray.push(models.Products.update(args, {
where: {
id: product_id
}
}));
} else {
tranArray.push(models.Product_lang_details.update(args,
where: {
product_id: product_id,
areacode: areacode
}));
tranArray.push(models.Product_shipping_to.update({
freezeTableName: args.freezeTableName
},
where: {
product_id: product_id,
areacode: areacode
}));
}
return Promise.all(tranArray);
}).then(function() {
return utils.response(res, 200, {
'message': 'update product successful!'
});
}).catch(function(error) {
logger.error('product update fall', error);
return utils.responseError(res, 500, {
'message': 'format error'
});
});
###

SELECT、DELETE、UPDATE

sql orm
select findAll,findOne,findById,findOrCreate,findAndCountAll
delete destroy
update update
insert create
sql orm
SELECT foo, bar … Model.findAll({attributes: [‘foo’, ‘bar’]});
SELECT foo, bar AS baz … Model.findAll({attributes: [‘foo’, [‘bar’, ‘baz’]]});
SELECT COUNT(hats) AS no_hats … Model.findAll({attributes: [[sequelize.fn(‘COUNT’, sequelize.col(‘hats’)), ‘no_hats’]]});
SELECT id, foo, bar, quz … Model.findAll({attributes: {exclude: [‘baz’] }});
1
2
3
4
5
6
7
8
9
Model.findAll({
attributes: ['id', 'foo', 'bar', 'baz', 'quz', [sequelize.fn('COUNT', sequelize.col('hats')), 'no_hats']]
});
//等于
Model.findAll({
attributes: { include: [[sequelize.fn('COUNT', sequelize.col('hats')), 'no_hats']] }
});
SELECT id, foo, bar, baz, quz, COUNT(hats) AS no_hats ...

WHERE

sql orm
SELECT * FROM post WHERE authorId = 12 AND status = ‘active’ Post.findAll({where: { authorId: 2,status: ‘active’}});

Operators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Post.update({
updatedAt: null,
}, {
where: {
deletedAt: {
$ne: null
}
}
});
// UPDATE post SET updatedAt = null WHERE deletedAt NOT NULL;
Post.findAll({
where: sequelize.where(sequelize.fn('char_length', sequelize.col('status')), 6)
});
// SELECT * FROM post WHERE char_length(status) = 6;
{
rank: {
$or: {
$lt: 1000,
$eq: null
}
}
}
// rank < 1000 OR rank IS NULL
{
createdAt: {
$lt: new Date(),
$gt: new Date(new Date() - 24 * 60 * 60 * 1000)
}
}
// createdAt < [timestamp] AND createdAt > [timestamp]
{
$or: [
{
title: {
$like: 'Boat%'
}
},
{
description: {
$like: '%boat%'
}
}
]
}
// title LIKE 'Boat%' OR description LIKE '%boat%'
op define
$and: {a: 5} AND (a = 5)
$or: [{a: 5}, {a: 6}] (a = 5 OR a = 6)
$gt: 6, > 6
$gte: 6, >= 6
$lt: 10, < 10
$lte: 10, <= 10
$ne: 20, != 20
$between: [6, 10], BETWEEN 6 AND 10
$notBetween: [11, 15], NOT BETWEEN 11 AND 15
$in: [1, 2], IN [1, 2]
$notIn: [1, 2], NOT IN [1, 2]
$like: ‘%hat’, LIKE ‘%hat’
$notLike: ‘%hat’ NOT LIKE ‘%hat’
$iLike: ‘%hat’ ILIKE ‘%hat’ (case insensitive) (PG only)
$notILike: ‘%hat’ NOT ILIKE ‘%hat’ (PG only)
$like: { $any: [‘cat’, ‘hat’]} LIKE ANY ARRAY[‘cat’, ‘hat’] - also works for iLike and notLike
$overlap: [1, 2] && [1, 2] (PG array overlap operator)
$contains: [1, 2] @> [1, 2] (PG array contains operator)
$contained: [1, 2] <@ [1, 2] (PG array contained by operator)
$any: [2,3] ANY ARRAY[2, 3]::INTEGER (PG only)
$col: ‘user.organization_id’ “user”.”organization_id”, with dialect specific column identifiers, PG in this example –$col取表的字段

WARNING

tabel need primarykey:如果没有,Sequlize会自己加个自增主键,可能引起错误

Node

findOrCreate: 查到一个,查不到就新建

1
2
3
4
5
6
7
8
9
10
models.BrandReview.findOrCreate({
where: {
mem_id: mem_id,
brand_id: brand_id
},
defaults: {
score: score //新建的数据
}
})
//返回值为数组,[json,created] 第一位是查询或创建的数据,第二位标识是否新建

update:返回值为数据,[2],数字代码改动记录数

destroy:返回数字,代表删除记录数

Promise含义

  • Promise 对象,用来传递异步操作的消息。代表了某个未来才会知道结果的事件(通常是一个异步操作)。这个事件提供统一的API,可供进一步处理
  • 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易
  • 无法取消Promise。如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

基本用法

Promise实例:

1
2
3
4
5
6
7
8
9
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});

resolve和reject是两个函数,由JavaScript引擎提供

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function test(object) {
return new Promise((resolve, reject) => {
//resolve("success");
reject("error");
});
}
test().then((value) => {
//resolve
console.log(value);
},function(value){
//reject
console.log(value);
});

then()–Promise.prototype.then()

  • Promise实例有then方法,then方法定义在原型对象Promise.prototype上.返回的是一个新的Promise实例
  • 可以采用链式(chain)写法,即then方法后面再调用另一个then方法,后一个then的回调函数,会等待新Promise对象的状态发生变化,才会被调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL);
}).then(function funcA(comments) {
console.log("Resolved: ", comments);
}, function funcB(err){
console.log("Rejected: ", err);
});
// 第二个then的回调函数,会等待这个新的Promise对象状态发生变化。如果变为Resolved,就调用funcA
function(post) {
return getJSON(post.commentURL);
}
//等于
post => getJSON(post.commentURL)

catch()–Promise.prototype.catch()

建议总是使用catch方法,而不使用then方法的第二个参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});

catch方法返回的还是一个Promise对象,因此后面还可以接着调用then方法。

如果没有使用catch方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应

有必要时,可以在回调链最后加done(),保证抛出任何可能出现的错误

Promise.all()

用于将多个Promise实例,包装成一个新的Promise实例。适合用于事务

p的状态由p1、p2、p3决定,分成两种情况。

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

1
2
3
4
5
6
7
8
9
10
// 生成一个Promise对象的数组
var promises = [2, 3, 5, 7, 11, 13].map(function(id){
return getJSON("/post/" + id + ".json");
});
Promise.all(promises).then(function(posts) {
// ...
}).catch(function(reason){
// ...
});

Promise.race()

同样是将多个Promise实例,包装成一个新的Promise实例。可用于超时判断 setTimeout
超时判断可用bluebird的.timeout(
int ms,
[String message=”operation timed out”]
) -> Promise

只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的回调函数

1
2
3
4
5
6
7
8
var p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
])
p.then(response => console.log(response))
p.catch(error => console.log(error))
  • bluebird Promise.some 可以传入count,来确定返回几个,promise.any则返回一个
1
2
3
4
5
6
7
8
Promise.some([
ping("ns1.example.com"),
ping("ns2.example.com"),
ping("ns3.example.com"),
ping("ns4.example.com")
], 2).spread(function(first, second) {
console.log(first, second);
});

Promise.resolve()

将现有对象转为Promise对象

参数是一个Promise实例,将不做变动的返回

参数是thenable对象 将这个对象转为Promise对象,然后就立即执行thenable对象的then方法

参数是一个原始值,或者是一个不具有then方法的对象 返回一个新的Promise对象,状态为Resolved

不带有任何参数 直接返回一个Resolved状态的Promise对象

1
2
3
4
5
6
7
8
9
10
11
12
13
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
// one
// two
// three

Promise.resolve()在本轮“事件循环”(event loop)结束时执行,setTimeout(fn, 0)在下一轮“事件循环”开始时执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//无论执行失败还是成功 最后都会回调,依照nodejs回调规范,第一个参数error,第二个成功结果。
bluebird .asCallback(
[function(any error, any value) callback],
[Object {spread: boolean=false} options]
) -> this
//spread 用于遍历拆分数组
Promise.resolve([1,2,3]).asCallback(function(err, a, b, c) {
// err == null
// a == 1
// b == 2
// c == 3
}, {spread: true});

Nova的四个核心服务:

  1. API —> 进入Nova的HTTP接口 有Policy保护 可以直接操作数据库
  2. Compute —> 与VMM交互运行和管理虚拟机
  3. Conductor —> 为数据库访问提供安全保障 建议数据库操作都通过Condutor
  4. Scheduler —> 负责挑选合适的计算节点创建虚拟机实例 只读取数据库

创建虚拟机的流程

  • 用户通过执行·client提供的命令,创建虚拟机。client,对原生RESTful Nova API封装、简化用户使用,将用户请求转换成HTTP请求
  • API监听HTTP请求,并将其转换成AMQP消息 然后通过消息队列调用Conductor
  • Conductor汇总参数,再、通过消息队列通知Scheduler去选择一个合适的计算节点,等拿到Scheduler提供的节点后,通知Compute创建虚拟机

删除虚拟机

  • 不需要Scheduler,API通过消息队列通知Compute删除指定虚拟机,Compute通过Condutor更新数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
"use strict";
var net = require('net');
var fs = require('fs');
var name = "",//send-email-address
pwd = "",//email-password
host = "smtp.exmail.qq.com",
port = 25,
to = "";to-email-address
var argx = {
title: "test",
attachment: [{
name: "1.png",
path: "1.png"
}, {
name: "2.txt",
path: "2.txt"
}],
content: '内容'
}
send(argx)
function send(arg) {
var title = "test";
var f = fs.open("1.png");
var buffer = f.readAll();
var content = buffer.base64();
var f1 = fs.open("2.txt");
var content1 = f1.readAll().base64();
var _smtp = new net.Smtp();
_smtp.connect(host, port);
_smtp.hello();
_smtp.login(name, pwd);
_smtp.from(name);
var data = "from:" + name + "\r\n";
data += "to:" + to + "\r\n";
data += "subject:" + arg.title + "\r\n";
data += "MIME-Version: 1.0 \r\nContent-Type: multipart/mixed;\r\n "
data += "boundary=#qwertyuiop#;\r\n"
data += "\r\n--#qwertyuiop#\r\n"
data += "Content-Type: text/plain;charset=utf8\r\nContend˙t-Transfer-Encoding:7bit\r\n"
data += "\r\n" + arg.content + "\r\n"
arg.attachment.forEach(function(o) {
data += "\r\n--#qwertyuiop#\r\n"
data += "Content-Type: application/octet-stream;"
data += "name=" + o.name + "\r\n"
data += "Content-Transfer-Encoding: base64\r\n"
data += "\r\n" + fs.open(o.path).readAll().base64()
})
data += "\r\n--#qwertyuiop#\r\n"
f.dispose();
_smtp.to(to);
_smtp.data(data);
_smtp.quit();
}