Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
254 changes: 95 additions & 159 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,26 @@
/**
* Created by harel on 15/08/2017.
*/
const request = require("request");
const RateLimiter = require('request-rate-limiter');
const limiter = new RateLimiter(120); //120 requests per minute

var api_key, short_domain;

let api_key, short_domain;
const cm_short = {
auth: function (apiKey, shortDomain) {
api_key = apiKey;
short_domain = shortDomain || "smart.short.cm";
},
domainApi: function (apiKey) {
var options = {
const options = {
method: 'GET',
url: 'https://api.short.cm/api/domains',
headers: {
'Content-Type': 'application/json',
'Authorization': apiKey
}
};
return new Promise(function (resolve, reject) {
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = checkIfJsonStringAndParse(body);
info.error? reject(info) : resolve(info);;
} else {
reject({
msg: "error in domain api request",
error: error,
response: response
});
}
})
});
return makeRateLimitedRequest(options);
},
shorten: function (url) {
var options = {
const options = {
method: 'POST',
url: 'https://api.short.cm/links',
form: {
Expand All @@ -47,20 +32,7 @@ const cm_short = {
'Authorization': api_key
}
};
return new Promise(function (resolve, reject) {
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = checkIfJsonStringAndParse(body);
info.error? reject(info) : resolve(info);;
} else {
reject({
msg: "error in shorten api request",
error: error,
response: response
});
}
})
});
return makeRateLimitedRequest(options);
},
getPathFromUrl: function (url) {
return url.replace(short_domain, '').replace(/(http:\/\/|https:\/\/|\/)/g, '')
Expand All @@ -83,7 +55,7 @@ const cm_short = {
},
delete: function (link_id) {
return new Promise(function (resolve, reject) {
var options = {
const options = {
method: 'DELETE',
url: 'https://api.short.cm/links/' + link_id,
headers: {
Expand All @@ -94,7 +66,8 @@ const cm_short = {
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = checkIfJsonStringAndParse(body);
info.error? reject(info) : resolve(info);;
info.error ? reject(info) : resolve(info);
;
} else {
console.log('Status:', response.statusCode);
console.log('Headers:', JSON.stringify(response.headers));
Expand All @@ -111,135 +84,73 @@ const cm_short = {
},

expand: function (url) {
return new Promise(function (resolve, reject) {
var options = {
method: 'GET',
url: 'https://api.short.cm/links/expand?domain=' + encodeURI(short_domain) + '&path=' + encodeURI(cm_short.getPathFromUrl(url)),
headers: {
'Content-Type': 'application/json',
'Authorization': api_key
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = checkIfJsonStringAndParse(body);
info.error? reject(info) : resolve(info);;
} else {
reject({
msg: "error in expand api request",
error: error,
response: response
});
}
})
});
const options = {
method: 'GET',
url: 'https://api.short.cm/links/expand?domain=' + encodeURI(short_domain) + '&path=' + encodeURI(cm_short.getPathFromUrl(url)),
headers: {
'Content-Type': 'application/json',
'Authorization': api_key
}
};
return makeRateLimitedRequest(options);
},

expandByLongUrl: function (url) {
return new Promise(function (resolve, reject) {
var options = {
method: 'GET',
url: 'https://api.short.cm/links/by-original-url?domain=' + encodeURI(short_domain) + '&originalURL=' + encodeURIComponent(url),
headers: {
'Content-Type': 'application/json',
'Authorization': api_key
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = checkIfJsonStringAndParse(body);
info.error? reject(info) : resolve(info);;
} else {
reject({
msg: "error in expand api request",
error: error,
response: response
});
}
})
});
const options = {
method: 'GET',
url: 'https://api.short.cm/links/by-original-url?domain=' + encodeURI(short_domain) + '&originalURL=' + encodeURIComponent(url),
headers: {
'Content-Type': 'application/json',
'Authorization': api_key
}
};
return makeRateLimitedRequest(options);
},
analyticsById: function (link_id) {
return new Promise(function (resolve, reject) {
var options = {
method: 'GET',
url: 'https://api.short.cm/links/statistics/' + link_id + '?period=total',
// url: 'https://api.short.cm/links/' + link_id + '/statistics',
headers: {
'Content-Type': 'application/json',
'Authorization': api_key
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = checkIfJsonStringAndParse(body);
info.error? reject(info) : resolve(info);;
} else {
reject({
msg: "error in analytics shorten api request",
error: error,
response: response
});
}
})
});
const options = {
method: 'GET',
url: 'https://api.short.cm/links/statistics/' + link_id + '?period=total',
// url: 'https://api.short.cm/links/' + link_id + '/statistics',
headers: {
'Content-Type': 'application/json',
'Authorization': api_key
}
};
return makeRateLimitedRequest(options);
},
updateShortUrlByLinkId: function (link_id, newLongUrl) {
return new Promise(function (resolve, reject) {
var options = {
method: 'POST',
url: 'https://api.short.cm/links/' + link_id,
form: {
originalURL: newLongUrl,
// title: title || "title_placeholder"
},
headers: {
'Content-Type': 'application/json',
'Authorization': api_key
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = checkIfJsonStringAndParse(body);
info.error ? reject(info) : resolve(info);
} else {
reject({
msg: "error in update shorten api request",
error: error,
response: response
});
}
})
});
const options = {
method: 'POST',
url: 'https://api.short.cm/links/' + link_id,
form: {
originalURL: newLongUrl,
// title: title || "title_placeholder"
},
headers: {
'Content-Type': 'application/json',
'Authorization': api_key
}
};
return makeRateLimitedRequest(options);
},

updateLocaleById: function (link_id, country, url) {
return new Promise(function (resolve, reject) {
var options = {
method: 'POST',
url: 'https://api.short.cm/link_country/' + link_id,
form: {
originalURL: url,
country: country
// title: title || "title_placeholder"
},
headers: {
'Content-Type': 'application/json',
'Authorization': api_key
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = checkIfJsonStringAndParse(body);
info.error ? reject(info) : resolve(info);
} else {
reject({
msg: "error in updateLocale api request",
error: error,
response: response
});
}
})
});
const options = {
method: 'POST',
url: 'https://api.short.cm/link_country/' + link_id,
form: {
originalURL: url,
country: country
// title: title || "title_placeholder"
},
headers: {
'Content-Type': 'application/json',
'Authorization': api_key
}
};
return makeRateLimitedRequest(options);
},

updateShortUrl: function (shortUrl, newLongUrl) {
return new Promise(function (resolve, reject) {
cm_short.expand(shortUrl).then(function (expand_res) {
Expand Down Expand Up @@ -284,8 +195,9 @@ const cm_short = {
//helper to test if json can be parsed

function checkIfJsonStringAndParse(str) {
let x;
try {
var x = JSON.parse(str);
x = JSON.parse(str);
} catch (e) {
return {
msg: "error in updateLocale api request",
Expand All @@ -294,8 +206,32 @@ function checkIfJsonStringAndParse(str) {
}
return x;
}
module.exports = cm_short;

function makeRateLimitedRequest(options) {
return new Promise(function (resolve, reject) {
limiter.request()
.then(function (backoff) {
request(options, function (error, response, body) {
if (response.statusCode === 429) {
// we have to back off. this callback will be called again as soon as the remote enpoint
// should accept requests again. no need to queue your callback another time on the limiter.
backoff();
} else if (!error && response.statusCode == 200) {
const info = checkIfJsonStringAndParse(body);
info.error ? reject(info) : resolve(info);
} else {
reject({
msg: "error in domain api request",
error: error,
response: response
});
}
})
}).catch((limiterError) => reject({msg: "limiter error", error: limiterError}));
});
}

module.exports = cm_short;



Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "shortcm-node",
"version": "0.0.8",
"version": "0.0.9",
"description": "",
"main": "app.js",
"scripts": {
Expand All @@ -15,6 +15,7 @@
"author": "Harel Levy",
"license": "ISC",
"dependencies": {
"request": "^2.81.0"
"request": "^2.81.0",
"request-rate-limiter": "^1.0.2"
}
}