Skip to content

Commit

Permalink
实现 数字媒体解决方案 的API
Browse files Browse the repository at this point in the history
  • Loading branch information
leeight committed Apr 16, 2015
1 parent 9dcd1a9 commit 36e29d5
Show file tree
Hide file tree
Showing 8 changed files with 484 additions and 11 deletions.
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

exports.Auth = require('./src/auth');
exports.BosClient = require('./src/bos_client');
exports.MediaClient = require('./src/media_client');
exports.HttpClient = require('./src/http_client');
exports.MimeType = require('./src/mime.types');

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"author": "[email protected]",
"license": "MIT",
"dependencies": {
"debug": "^2.1.3",
"q": "^1.1.2",
"underscore": "^1.7.0"
}
Expand Down
6 changes: 6 additions & 0 deletions src/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

var util = require('util');

var debug = require('debug')('auth');


/**
* @constructor
Expand Down Expand Up @@ -57,6 +59,10 @@ Auth.prototype.generateAuthorization = function (method, resource, params,
var rv = this.headersCanonicalization(headers || {}, headersToSign);
var canonicalHeaders = rv[0];
var signedHeaders = rv[1];
debug('canonicalUri = %j', canonicalUri);
debug('canonicalQueryString = %j', canonicalQueryString);
debug('canonicalHeaders = %j', canonicalHeaders);
debug('signedHeaders = %j', signedHeaders);

var rawSignature = util.format('%s\n%s\n%s\n%s',
method, canonicalUri, canonicalQueryString, canonicalHeaders);
Expand Down
16 changes: 9 additions & 7 deletions src/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@

/*eslint-env node*/

exports.CONTENT_TYPE = 'Content-Type';
exports.CONTENT_LENGTH = 'Content-Length';
exports.CONTENT_MD5 = 'Content-MD5';
exports.CONNECTION = 'Connection';
exports.HOST = 'Host';
exports.USER_AGENT = 'User-Agent';

exports.CONTENT_TYPE = 'content-type';
exports.CONTENT_LENGTH = 'content-length';
exports.CONTENT_MD5 = 'content-md5';
exports.CONNECTION = 'connection';
exports.HOST = 'host';
exports.USER_AGENT = 'user-agent';

exports.AUTHORIZATION = 'authorization';
exports.X_BCE_DATE = 'x-bce-date';
exports.X_BCE_ACL = 'x-bce-acl';
exports.X_BCE_REQUEST_ID = 'x-bce-request-id';

exports.X_HTTP_HEADERS = 'http_headers';
exports.X_BODY = 'body';
Expand Down
30 changes: 26 additions & 4 deletions src/http_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var stream = require('stream');

var u = require('underscore');
var Q = require('q');
var debug = require('debug')('http_client');

var H = require('./headers');

Expand Down Expand Up @@ -65,19 +66,25 @@ HttpClient.prototype.sendRequest = function (httpMethod, path, body, headers, pa
defaultHeaders[H.HOST] = options.host;

headers = u.extend({}, defaultHeaders, headers);
if (typeof signFunction === 'function') {
headers.Authorization = signFunction(this.config.credentials,
httpMethod, path, params, headers);
}

// if (!headers.hasOwnProperty(H.X_BCE_REQUEST_ID)) {
// headers[H.X_BCE_REQUEST_ID] = this._generateRequestId();
// }

// Check the content-length
if (!headers.hasOwnProperty(H.CONTENT_LENGTH)) {
headers[H.CONTENT_LENGTH] = this._guessContentLength(body);
}

if (typeof signFunction === 'function') {
headers[H.AUTHORIZATION] = signFunction(this.config.credentials,
httpMethod, path, params, headers);
}

var api = options.protocol === 'https:' ? require('https') : require('http');
options.method = httpMethod;
options.headers = headers;
debug('request headers = %j', headers);

var deferred = Q.defer();

Expand Down Expand Up @@ -109,6 +116,20 @@ HttpClient.prototype.sendRequest = function (httpMethod, path, body, headers, pa
return deferred.promise;
};

HttpClient.prototype._generateRequestId = function () {
function chunk() {
var v = (~~(Math.random() * 0xffff)).toString(16);
if (v.length < 4) {
v += new Array(4 - v.length + 1).join('0');
}
return v;
}

return util.format('%s%s-%s-%s-%s-%s%s%s',
chunk(), chunk(), chunk(), chunk(),
chunk(), chunk(), chunk(), chunk());
};

HttpClient.prototype._guessContentLength = function (data) {
if (data == null) {
return 0;
Expand Down Expand Up @@ -202,6 +223,7 @@ HttpClient.prototype._sendRequest = function (req, data) {
/*eslint-enable*/

if (Buffer.isBuffer(data)) {
debug('send body = %j', data.toString());
req.write(data);
req.end();
}
Expand Down
223 changes: 223 additions & 0 deletions src/media_client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/**
* Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

/*eslint-env node*/
/*eslint max-params:[0,10]*/

var util = require('util');
var path = require('path');
var fs = require('fs');

var u = require('underscore');
var Q = require('q');

var H = require('./headers');
var Auth = require('./auth');
var HttpClient = require('./http_client');
var BceBaseClient = require('./bce_base_client');
var MimeType = require('./mime.types');
var WMStream = require('./wm_stream');

/**
* Media service api.
* @constructor
* @param {Object} config The media client configuration.
* @extends {BceBaseClient}
*/
function MediaClient(config) {
BceBaseClient.call(this, config, 'media', true);
}
util.inherits(MediaClient, BceBaseClient);


// --- B E G I N ---
MediaClient.prototype.createPipeline = function (pipelineName, sourceBucket, targetBucket,
opt_config, opt_description, opt_options) {

var url = '/v3/pipeline';
var options = opt_options || {};
var body = JSON.stringify({
pipelineName: pipelineName,
sourceBucket: sourceBucket,
targetBucket: targetBucket,
config: opt_config || {capacity: 5},
description: opt_description || ''
});

return this._sendRequest('POST', url, {
body: body,
config: options.config,
});
};

MediaClient.prototype.getPipeline = function (pipelineName, opt_options) {
var url = '/v3/pipeline/' + pipelineName;
var options = opt_options || {};

return this._sendRequest('GET', url, {config: options.config});
};

MediaClient.prototype.deletePipeline = function (pipelineName, opt_options) {
var url = '/v3/pipeline/' + pipelineName;
var options = opt_options || {};

return this._sendRequest('DELETE', url, {config: options.config});
};

MediaClient.prototype.getAllPipelines = function (opt_options) {
var url = '/v3/pipeline';
var options = opt_options || {};

return this._sendRequest('GET', url, {config: options.config});
};

MediaClient.prototype.createJob = function (pipelineName, source, target, presetName, opt_options) {
var url = '/v3/job';
var options = opt_options || {};
var body = JSON.stringify({
pipelineName: pipelineName,
source: source,
target: target,
presetName: presetName
});

return this._sendRequest('POST', url, {
body: body,
config: options.config
});
};

MediaClient.prototype.getAllJobs = function (pipelineName, opt_options) {
var url = '/v3/job';
var options = opt_options || {};
var params = {pipelineName: pipelineName};

return this._sendRequest('GET', url, {
params: params,
config: options.config
});
};

MediaClient.prototype.getJob = function (jobId, opt_options) {
var url = '/v3/job/' + jobId;
var options = opt_options || {};

return this._sendRequest('GET', url, {config: options.config});
};

/**
* 创建模板, 不对外部用户开放,仅服务于Console.
* @param {string} presetName 转码模板名称.
* @param {string} container 音视频文件的容器.
* @param {Object=} clip 是否截取音视频片段.
* @param {Object=} audio 音频输出信息的集合,不填写表示只处理视频部分.
* @param {Object=} video 视频输出信息的集合,不填写表示只处理音频部分.
* @param {Object=} opt_encryption HLS加解密信息的集合.
* @param {boolean=} opt_transmux 是否仅执行容器格式转换.
* @param {string=} opt_description 转码模板描述.
* @param {Object=} opt_options Media Client 的配置.
*/
MediaClient.prototype.createPreset = function (presetName, container, clip, audio, video,
opt_encryption, opt_transmux, opt_description, opt_options) {
// container: mp4, flv, hls, mp3, m4a
var url = '/v3/preset';
var options = opt_options || {};
var body = {
presetName: presetName,
container: container
};
clip && (body.clip = clip);
audio && (body.audio = audio);
video && (body.video = video);
opt_encryption && (body.encryption = opt_encryption);
opt_transmux != null && (body.transmux = opt_transmux);
opt_description && (body.description = opt_description);

return this._sendRequest('POST', url, {
body: JSON.stringify(body),
config: options.config
});
};

MediaClient.prototype.getPreset = function (presetName, opt_options) {
var url = '/v3/preset/' + presetName;
var options = opt_options || {};

return this._sendRequest('GET', url, {
config: options.config
});
};

MediaClient.prototype.deletePreset = function (presetName, opt_options) {
var url = '/v3/preset/' + presetName;
var options = opt_options || {};

return this._sendRequest('DELETE', url, {
config: options.config
});
};

MediaClient.prototype.getMediainfo = function (bucket, key, opt_options) {
var url = '/v3/mediainfo';
var options = opt_options || {};
var params = {
bucket: bucket,
key: key
};

return this._sendRequest('GET', url, {
params: params,
config: options.config
});
};

MediaClient.prototype.createSignature = function (credentials, httpMethod, path, params, headers) {
var auth = new Auth(credentials.ak, credentials.sk);
// 不能对content-type,content-length,content-md5进行签名
// 不能对x-bce-request-id进行签名
var headersToSign = ['host'];
return auth.generateAuthorization(httpMethod, path, params, headers, 0, 0, headersToSign);
};
// --- E N D ---


MediaClient.prototype._sendRequest = function (httpMethod, resource, varArgs) {
var defaultArgs = {
bucketName: null,
key: null,
body: null,
headers: {},
params: {},
config: {},
outputStream: null
};
var args = u.extend(defaultArgs, varArgs);

var config = u.extend({}, this.config, args.config);

var httpClient = new HttpClient(config);
return httpClient.sendRequest(httpMethod, resource, args.body,
args.headers, args.params, u.bind(this.createSignature, this),
args.outputStream
);
};

module.exports = MediaClient;







/* vim: set ts=4 sw=4 sts=4 tw=120: */
36 changes: 36 additions & 0 deletions test/media.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

module.exports = {
credentials: {
ak: '46bd9968a6194b4bbdf0341f2286ccce',
sk: 'ec7f4e0174254f6f9020f9680fb1da9f'
},
connection_timeout_in_mills: 5000, // 5 seconds
// region: 'bj',
// region: 'nj',
// 有了 endpoint,region 其实就不生效了
endpoint: 'http://multimedia.bce-testinternal.baidu.com'
};











/* vim: set ts=4 sw=4 sts=4 tw=120: */
Loading

0 comments on commit 36e29d5

Please sign in to comment.