airship-server
Version:
Airship is a framework for Node.JS & TypeScript that helps you to write big, scalable and maintainable API servers.
217 lines (213 loc) • 8.94 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const CallbackQueue_1 = require("../utils/CallbackQueue");
const VKApiError_1 = require("./VKApiError");
const req = require('tiny_request');
const REQUESTS_PER_SECOND = 3;
const API_BASE_URL = 'https://api.vk.com/method/';
const API_VERSION = '5.53';
class VKApi {
constructor(logger, cache) {
this._queues = new Map();
this.appServiceKey = '46d3f43f46d3f43f468d06a38646896cbb446d346d3f43f1e023074e283b74286af81f0';
this._logger = logger;
if (cache)
this._cache = cache;
}
call(method, token, params, useQueue = true) {
return __awaiter(this, void 0, void 0, function* () {
params['v'] = API_VERSION;
params['access_token'] = token;
return new Promise((resolve, reject) => {
let request = () => {
req.post({
url: API_BASE_URL + method,
form: params,
json: true,
timeout: 1000 * 5
}, (body, response, err) => {
if (!err && response.statusCode == 200 && !body.error) {
resolve(body);
return;
}
if (body && body.error) {
reject(VKApiError_1.default.deserialize(body));
this._logger.warn('VK Api error', {
response: JSON.stringify(body, null, 2),
method,
token,
params
});
return;
}
if (err) {
this._logger.error('VK Api:', {
'Networking error:': err,
method,
token,
params
});
reject(err);
return;
}
this._logger.error('VK Api:', {
'api request error: Body:': body,
'Error:': err
});
reject(err);
});
};
if (!useQueue) {
request();
return;
}
this.getQueueForGroup(token).push(request);
});
});
}
callWithAsyncLock(method, token, params) {
return __awaiter(this, void 0, void 0, function* () {
if (!this._cache)
throw new Error('No cache');
if (!this._cache)
throw new Error('No cache');
let canWork = yield this._cache.setnx(`LOCK_${token}`, 1);
if (canWork == 1) {
yield this._cache.cache(`LOCK_${token}`, Date.now() + 338 + 1, 338);
return yield this.call(method, token, params, false);
}
else {
// let g = await this._cache.get(`LOCK_${token}`)
//
// if (Date.now() > (g as number)) {
// g = await this._cache.getset(`LOCK_${token}`, Date.now() + 338 + 1)
//
// if (Date.now() > g) {
// await this._cache.del(`LOCK_${token}`)
//
// return this.call(method, token, params, false)
// }
// }
return new Promise((resolve, reject) => {
setTimeout(() => {
this.callWithAsyncLock(method, token, params)
.then(resolve)
.catch(reject);
}, 100);
});
}
});
}
callWithRetry(method, token, params, useQueue = true) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
let makeCall = (resolve, reject, method, token, params, useQueue = true) => {
this.call(method, token, params, useQueue)
.then(r => {
resolve(r);
})
.catch(e => {
if (e instanceof VKApiError_1.default) {
/**
* 6 - too many requests per second
* 10 - internal server error
*/
if (e.errorCode == 6 || e.errorCode == 10) {
setTimeout(() => {
makeCall(resolve, reject, method, token, params, useQueue);
}, 300);
}
reject(e);
}
else {
/**
* Networking error
*/
setTimeout(() => {
makeCall(resolve, reject, method, token, params, useQueue);
}, 300);
}
});
};
makeCall(resolve, reject, method, token, params, useQueue);
});
});
}
getGroupMembers(groupId, token) {
return __awaiter(this, void 0, void 0, function* () {
let users = [];
let offset = 0;
let code = this.generateGetGroupMembersCode(groupId, offset);
let response = yield this.callWithRetry('execute', token, { code });
let usersCount = response.response.count;
users.push(...response.response.items);
let reqsCount = Math.floor(usersCount / (1000 * 25));
offset = 1000 * 25;
for (let i = 0; i <= reqsCount; i++) {
let resp = yield this.callWithRetry('execute', token, {
code: this.generateGetGroupMembersCode(groupId, offset)
});
users.push(...resp.response.items);
offset += 1000 * 25;
}
return users;
});
}
getQueueForGroup(token) {
if (!this._queues.has(token))
this._queues.set(token, new CallbackQueue_1.default(REQUESTS_PER_SECOND));
return this._queues.get(token);
}
generateGetGroupMembersCode(groupId, offset) {
return `
var Data = [];
var group_id = ${groupId};
var i = 0;
var offset = ${offset};
while(true){
var response = API.groups.getMembers({"offset": offset ,"group_id": group_id, "count":"1000"});
Data = Data + (response.items);
i = i+1;
offset = offset + 1000;
if(i == 25){
return { count: response.count, items: Data };
}
}
`;
}
getGroupPosts(groupId, token) {
return __awaiter(this, void 0, void 0, function* () {
let code = `
var Data = [];
var group_id = ${groupId * -1};
var i = 0;
var offset = 0;
while(true){
var response = API.wall.get({"offset": offset ,"owner_id": group_id, "count":"100"});
Data = Data + (response.items);
i = i+1;
offset = offset + 100;
if(i == 25){
return { count: response.count, items: Data };
}
}
`;
//console.log(code)
let posts = yield this.call('execute', '434910c8434910c8434910c8d04313884c44349434910c81babcebd9850569337cb4498', {
code
});
//console.log(posts)
return [1];
});
}
}
exports.default = VKApi;
//# sourceMappingURL=VKApi.js.map