Skip to content

Commit e0c9bb2

Browse files
Merge pull request #620 from cloudinary/cached-search-support
Cached search support
2 parents 19b8cff + 78b3da1 commit e0c9bb2

File tree

10 files changed

+569
-159
lines changed

10 files changed

+569
-159
lines changed

lib-es5/utils/index.js

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ function build_eager(transformations) {
466466
return format == null ? transformationString : `${transformationString}/${format}`;
467467
}).join('|');
468468
}
469+
469470
/**
470471
* Build the custom headers for the request
471472
* @private
@@ -791,6 +792,24 @@ function patchFetchFormat() {
791792
}
792793
}
793794

795+
function build_distribution_domain(options) {
796+
var source = consumeOption(options, 'source', '');
797+
var cloud_name = consumeOption(options, 'cloud_name', config().cloud_name);
798+
799+
if (!cloud_name) {
800+
throw new Error('Must supply cloud_name in tag or in configuration');
801+
}
802+
803+
var secure = consumeOption(options, 'secure', config().secure);
804+
var private_cdn = consumeOption(options, 'private_cdn', config().private_cdn);
805+
var cname = consumeOption(options, 'cname', config().cname);
806+
var secure_distribution = consumeOption(options, 'secure_distribution', config().secure_distribution);
807+
var cdn_subdomain = consumeOption(options, 'cdn_subdomain', config().cdn_subdomain);
808+
var secure_cdn_subdomain = consumeOption(options, 'secure_cdn_subdomain', config().secure_cdn_subdomain);
809+
810+
return unsigned_url_prefix(source, cloud_name, private_cdn, cdn_subdomain, secure_cdn_subdomain, cname, secure, secure_distribution);
811+
}
812+
794813
function url(public_id) {
795814
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
796815

@@ -886,7 +905,7 @@ function url(public_id) {
886905
}
887906
// eslint-disable-next-line no-empty
888907
} catch (error) {}
889-
var hash = computeHash(to_sign + api_secret, signature_algorithm, 'base64');
908+
var hash = compute_hash(to_sign + api_secret, signature_algorithm, 'base64');
890909
signature = hash.replace(/\//g, '_').replace(/\+/g, '-').substring(0, long_url_signature ? 32 : 8);
891910
signature = `s--${signature}--`;
892911
}
@@ -1002,6 +1021,7 @@ function finalize_resource_type(resource_type, type, url_suffix, use_root_path,
10021021
}
10031022
return [resource_type, type];
10041023
}
1024+
10051025
// cdn_subdomain and secure_cdn_subdomain
10061026
// 1) Customers in shared distribution (e.g. res.cloudinary.com)
10071027
// if cdn_domain is true uses res-[1-5].cloudinary.com for both http and https.
@@ -1092,7 +1112,7 @@ function api_sign_request(params_to_sign, api_secret) {
10921112

10931113
return `${k}=${toArray(v).join(",")}`;
10941114
}).sort().join("&");
1095-
return computeHash(to_sign + api_secret, config().signature_algorithm || DEFAULT_SIGNATURE_ALGORITHM, 'hex');
1115+
return compute_hash(to_sign + api_secret, config().signature_algorithm || DEFAULT_SIGNATURE_ALGORITHM, 'hex');
10961116
}
10971117

10981118
/**
@@ -1103,7 +1123,7 @@ function api_sign_request(params_to_sign, api_secret) {
11031123
* @param {string} encoding type of encoding
11041124
* @return {string} computed hash value
11051125
*/
1106-
function computeHash(input, signature_algorithm, encoding) {
1126+
function compute_hash(input, signature_algorithm, encoding) {
11071127
if (!SUPPORTED_SIGNATURE_ALGORITHMS.includes(signature_algorithm)) {
11081128
throw new Error(`Signature algorithm ${signature_algorithm} is not supported. Supported algorithms: ${SUPPORTED_SIGNATURE_ALGORITHMS.join(', ')}`);
11091129
}
@@ -1132,6 +1152,13 @@ function clear_blank(hash) {
11321152
return filtered_hash;
11331153
}
11341154

1155+
function sort_object_by_key(object) {
1156+
return Object.keys(object).sort().reduce(function (obj, key) {
1157+
obj[key] = object[key];
1158+
return obj;
1159+
}, {});
1160+
}
1161+
11351162
function merge(hash1, hash2) {
11361163
return _extends({}, hash1, hash2);
11371164
}
@@ -1150,11 +1177,14 @@ function sign_request(params) {
11501177
function webhook_signature(data, timestamp) {
11511178
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
11521179

1153-
ensurePresenceOf({ data, timestamp });
1180+
ensurePresenceOf({
1181+
data,
1182+
timestamp
1183+
});
11541184

11551185
var api_secret = ensureOption(options, 'api_secret');
11561186
var signature_algorithm = ensureOption(options, 'signature_algorithm', DEFAULT_SIGNATURE_ALGORITHM);
1157-
return computeHash(data + timestamp + api_secret, signature_algorithm, 'hex');
1187+
return compute_hash(data + timestamp + api_secret, signature_algorithm, 'hex');
11581188
}
11591189

11601190
/**
@@ -1253,7 +1283,9 @@ function download_backedup_asset(asset_id, version_id) {
12531283
* @param options
12541284
*/
12551285
function api_download_url(action, params, options) {
1256-
var download_params = _extends({}, params, { mode: "download" });
1286+
var download_params = _extends({}, params, {
1287+
mode: "download"
1288+
});
12571289
var cloudinary_params = exports.sign_request(download_params, options);
12581290
return exports.api_url(action, options) + "?" + hashToQuery(cloudinary_params);
12591291
}
@@ -1487,6 +1519,7 @@ function process_video_params(param) {
14871519
return null;
14881520
}
14891521
}
1522+
14901523
/**
14911524
* Returns a Hash of parameters used to create an archive
14921525
* @private
@@ -1530,7 +1563,10 @@ exports.create_source_tag = function create_source_tag(src, source_type) {
15301563
var codecs_str = isArray(codecs) ? codecs.join(', ') : codecs;
15311564
mime_type += `; codecs=${codecs_str}`;
15321565
}
1533-
return `<source ${utils.html_attrs({ src, type: mime_type })}>`;
1566+
return `<source ${utils.html_attrs({
1567+
src,
1568+
type: mime_type
1569+
})}>`;
15341570
};
15351571

15361572
function build_explicit_api_params(public_id) {
@@ -1726,6 +1762,9 @@ exports.jsonArrayParam = jsonArrayParam;
17261762
exports.download_folder = download_folder;
17271763
exports.base_api_url = base_api_url;
17281764
exports.download_backedup_asset = download_backedup_asset;
1765+
exports.compute_hash = compute_hash;
1766+
exports.build_distribution_domain = build_distribution_domain;
1767+
exports.sort_object_by_key = sort_object_by_key;
17291768

17301769
// was exported before, so kept for backwards compatibility
17311770
exports.DEFAULT_POSTER_OPTIONS = DEFAULT_POSTER_OPTIONS;

lib-es5/v2/search.js

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@ var _createClass = function () { function defineProperties(target, props) { for
55
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
66

77
var api = require('./api');
8+
var config = require('../config');
89

910
var _require = require('../utils'),
1011
isEmpty = _require.isEmpty,
11-
isNumber = _require.isNumber;
12+
isNumber = _require.isNumber,
13+
compute_hash = _require.compute_hash,
14+
build_distribution_domain = _require.build_distribution_domain,
15+
clear_blank = _require.clear_blank,
16+
sort_object_by_key = _require.sort_object_by_key;
17+
18+
var _require2 = require('../utils/encoding/base64Encode'),
19+
base64Encode = _require2.base64Encode;
1220

1321
var Search = function () {
1422
function Search() {
@@ -19,6 +27,7 @@ var Search = function () {
1927
aggregate: [],
2028
with_field: []
2129
};
30+
this._ttl = 300;
2231
}
2332

2433
_createClass(Search, [{
@@ -89,6 +98,16 @@ var Search = function () {
8998

9099
return this;
91100
}
101+
}, {
102+
key: 'ttl',
103+
value: function ttl(newTtl) {
104+
if (isNumber(newTtl)) {
105+
this._ttl = newTtl;
106+
return this;
107+
}
108+
109+
throw new Error('New TTL value has to be a Number.');
110+
}
92111
}, {
93112
key: 'to_query',
94113
value: function to_query() {
@@ -111,6 +130,36 @@ var Search = function () {
111130
options = options || {};
112131
return api.search(this.to_query(), options, callback);
113132
}
133+
}, {
134+
key: 'to_url',
135+
value: function to_url(ttl, next_cursor) {
136+
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
137+
138+
var apiSecret = 'api_secret' in options ? options.api_secret : config().api_secret;
139+
if (!apiSecret) {
140+
throw new Error('Must supply api_secret');
141+
}
142+
143+
var urlTtl = ttl || this._ttl;
144+
145+
var query = this.to_query();
146+
147+
var urlCursor = next_cursor;
148+
if (query.next_cursor && !next_cursor) {
149+
urlCursor = query.next_cursor;
150+
}
151+
delete query.next_cursor;
152+
153+
var dataOrderedByKey = sort_object_by_key(clear_blank(query));
154+
var encodedQuery = base64Encode(JSON.stringify(dataOrderedByKey));
155+
156+
var urlPrefix = build_distribution_domain(options);
157+
158+
var signature = compute_hash(`${urlTtl}${encodedQuery}${apiSecret}`, 'sha256', 'hex');
159+
160+
var urlWithoutCursor = `${urlPrefix}/search/${signature}/${urlTtl}/${encodedQuery}`;
161+
return urlCursor ? `${urlWithoutCursor}/${urlCursor}` : urlWithoutCursor;
162+
}
114163
}], [{
115164
key: 'instance',
116165
value: function instance() {
@@ -148,6 +197,11 @@ var Search = function () {
148197

149198
return this.instance().sort_by(field_name, dir);
150199
}
200+
}, {
201+
key: 'ttl',
202+
value: function ttl(newTtl) {
203+
return this.instance().ttl(newTtl);
204+
}
151205
}]);
152206

153207
return Search;

0 commit comments

Comments
 (0)