node-vk-api-bot
Version:
A library that helps you to create chat-bot for group or user
286 lines (285 loc) • 14.4 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _Bot_token, _Bot_Emitter, _Bot_longPollAbortController, _Bot_stop;
import request from './request.js';
import { EventEmitter } from 'events';
import Methods from './methods.js';
import { GroupUpdates } from './group-updates.js';
var _;
(function (_) {
function getTypedObjectEntries(obj) {
return Object.entries(obj);
}
_.getTypedObjectEntries = getTypedObjectEntries;
})(_ || (_ = {}));
var Entries = _.getTypedObjectEntries;
import { UserUpdates } from './user-updates.js';
class MethodResponse {
constructor(data) {
this.response = null;
this.error = null;
if ('response' in data) {
this.response = data.response;
}
else {
this.error = data.error;
}
}
/**
* Calls callback function if response state is not error
* @returns reference to response so you can chain `ifError` and `ifResponse`
* ```js
* new Bot().method().then(data => data.ifError((e) => console.error(e)).ifResponse((r) => {}));
* ```
*/
ifResponse(cb) {
if (this.response && !this.error)
cb(this.response);
return this;
}
/**
* Calls callback function if response state is error
* @returns reference to response so you can chain `ifError` and `ifResponse`
* ```js
* new Bot().method().then(data => data.ifError((e) => console.error(e)).ifResponse((r) => {}));
* ```
*/
ifError(cb) {
if (this.error && !this.response)
cb(this.error);
return this;
}
}
class Bot {
constructor(options) {
_Bot_token.set(this, void 0);
_Bot_Emitter.set(this, new EventEmitter());
_Bot_longPollAbortController.set(this, null);
_Bot_stop.set(this, false);
this.v = 5.131;
this.on = this.addEventListener;
const { token, type, group_id, } = options;
__classPrivateFieldSet(this, _Bot_token, token !== null && token !== void 0 ? token : (() => {
throw new TypeError('Token is undefined or null');
})(), "f");
this.type = ['group', 'user'].includes(type) ? type : (t => {
throw new TypeError(`"Type" property must be "group" or "user", but it is "${t}"`);
})(type);
this.group_id = group_id !== null && group_id !== void 0 ? group_id : (id => {
if (type === 'group' && !id)
throw new TypeError('"group_id" must exist in group bot');
return null;
})(group_id);
}
/**
* Add a listener to event
*
* If added a listener to `any` event, no one typed event is more returned
*
* If event type is `raw` (for user long poll) adding of listeners for not-`raw` version is ignored
* @param event Event name
* @param listener callback function
* @returns reference to `this`
*/
addEventListener(event, listener) {
__classPrivateFieldGet(this, _Bot_Emitter, "f").addListener(event, listener);
return this;
}
static method(options, cb) {
const { method, token, params } = options;
const url = new URL(`https://api.vk.com/method/${method}`);
[...Entries((params !== null && params !== void 0 ? params : {})), ['access_token', token], ['v', 5.131]].forEach(([key, prop]) => {
url.searchParams.append(key.toString(), prop.toString());
});
const data = request(url, {
method: 'GET',
keepalive: false,
}).then(data => new MethodResponse(data));
if (typeof cb === 'function') {
data.then(cb);
return;
}
return data;
}
method(options, cb) {
const { method, params, overrideToken } = options;
const data = Bot.method({
method,
params: params,
token: overrideToken !== null && overrideToken !== void 0 ? overrideToken : __classPrivateFieldGet(this, _Bot_token, "f"),
});
if (typeof cb === 'function') {
data.then(cb);
return;
}
return data;
}
startPolling(optionsOrCb, cb) {
var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () {
let isUsedCb = false;
const options = typeof optionsOrCb === 'object' ? optionsOrCb : {
wait: 25,
mode: 0,
returnRawData: false,
};
const { wait = 25, } = options;
const callback = typeof optionsOrCb === 'function' ? optionsOrCb : typeof cb === 'function' ? cb : () => void 0;
if (wait > 90 || wait < 0)
throw new RangeError('"wait" must be more than 0 and less than 90 (0 < wait < 90)');
__classPrivateFieldSet(this, _Bot_stop, false, "f");
const connectionData /* {
[T in keyof Methods.MethodResponse[Methods.Groups.getLongPollServer]]: Methods.MethodResponse[Methods.Groups.getLongPollServer][T] | null;
} */ = {
key: null,
server: null,
ts: null
};
const setConnectionData = (data) => {
const { key, server, ts } = data;
connectionData.key = key;
connectionData.server = server;
connectionData.ts = ts;
};
const isGroupBot = (bot) => bot.type === 'group';
const isUserBot = (bot) => bot.type === 'user';
// Outer loop
// Getting data for connection to longpoll server
while (!__classPrivateFieldGet(this, _Bot_stop, "f")) {
if (isGroupBot(this)) {
(yield (this /* as Bot<'group'> */).method({
method: Methods.Groups.getLongPollServer,
params: {
group_id: (_a = this.group_id) !== null && _a !== void 0 ? _a : (() => { throw new TypeError('group_id is null or undefined'); })(),
}
})).ifError(e => console.error(e))
.ifResponse((d) => {
setConnectionData(d);
!isUsedCb && (isUsedCb = true) && (callback === null || callback === void 0 ? void 0 : callback());
});
// Inner loop
// Get updates while connection data is valid
while (!__classPrivateFieldGet(this, _Bot_stop, "f")) {
const { key, server, ts } = connectionData;
const ac = new AbortController();
__classPrivateFieldSet(this, _Bot_longPollAbortController, ac, "f");
const updates = yield request(`${server}?act=a_check&key=${key}&ts=${ts}&wait=${wait}`, {
method: 'GET',
signal: ac.signal,
});
if ('failed' in updates) {
if (updates.failed === 1) {
connectionData.ts = updates.ts;
continue;
}
break;
}
connectionData.ts = updates.ts;
updates.updates.forEach(update => {
if (!__classPrivateFieldGet(this, _Bot_Emitter, "f").emit('any', update))
__classPrivateFieldGet(this, _Bot_Emitter, "f").emit(update.type, update);
});
}
}
else if (isUserBot(this)) {
const mode_enum = UserUpdates.LongPollMode;
const { mode = {
attachment: false,
extraEvents: false,
return$extraInEvent8: false,
returnPTS: false,
returnRandomId: false,
}, } = typeof options.mode === 'number' ? {
mode: (m => ({
attachment: !!(m & mode_enum.attachment),
extraEvents: !!(m & mode_enum.extraEvents),
return$extraInEvent8: !!(m & mode_enum.return$extraInEvent8),
returnPTS: !!(m & mode_enum.returnPTS),
returnRandomId: !!(m & mode_enum.returnRandomId),
}))(options.mode),
} : options;
const mode_num = typeof options.mode === 'number' ? options.mode : (m => {
return Object.entries(m).reduce((res, curr) => {
if (!curr || !curr[0])
throw new TypeError();
return res | mode_enum[curr[0]];
}, 0);
})(mode);
while (!__classPrivateFieldGet(this, _Bot_stop, "f")) {
const connData = yield (this /* as Bot<'user'> */).method({
method: Methods.Messages.getLongPollServer,
params: {
need_pts: (+((_b = mode.returnPTS) !== null && _b !== void 0 ? _b : 0)),
lp_version: 3
}
});
connData.ifError(e => { throw new Error(e.error_msg); }).ifResponse(data => {
setConnectionData(data);
});
while (!__classPrivateFieldGet(this, _Bot_stop, "f")) {
const updates = yield request(`https://${connectionData.server}?act=a_check&key=${connectionData.key}&ts=${connectionData.ts}&wait=${wait}&mode=${mode_num}&version=3`, {
method: 'GET',
signal: (_d = (_c = __classPrivateFieldGet(this, _Bot_longPollAbortController, "f")) === null || _c === void 0 ? void 0 : _c.signal) !== null && _d !== void 0 ? _d : null
});
if ('failed' in updates) {
const { failed } = updates;
if (failed === 1) {
connectionData.ts = updates.ts.toString();
continue;
}
if (failed === 4)
throw new RangeError(`Version must be more than ${updates.min_version} and less than ${updates.max_version}`);
break;
}
connectionData.ts = updates.ts.toString();
updates.updates.forEach(update => {
var _a;
if (!__classPrivateFieldGet(this, _Bot_Emitter, "f").emit('any_raw', update))
if (!__classPrivateFieldGet(this, _Bot_Emitter, "f").emit(UserUpdates.UpdateTypes[(_a = UserUpdates.RawUpdateTypes[update[0]]) !== null && _a !== void 0 ? _a : 'unknown_event'], update)) {
const parsed = UserUpdates.parseRawUpdate(update);
if (!__classPrivateFieldGet(this, _Bot_Emitter, "f").emit('any', parsed)) {
__classPrivateFieldGet(this, _Bot_Emitter, "f").emit(parsed.type, parsed);
}
}
});
}
}
}
}
});
}
/**
* Stops current LongPoll request
* @returns `true` if polling has been stopped otherwise `false`
*/
stopPolling(cb) {
__classPrivateFieldSet(this, _Bot_stop, true, "f");
if (!__classPrivateFieldGet(this, _Bot_longPollAbortController, "f"))
return (cb === null || cb === void 0 ? void 0 : cb(), false);
__classPrivateFieldGet(this, _Bot_longPollAbortController, "f").abort();
__classPrivateFieldSet(this, _Bot_longPollAbortController, null, "f");
typeof cb === 'function' && cb();
return true;
}
}
_Bot_token = new WeakMap(), _Bot_Emitter = new WeakMap(), _Bot_longPollAbortController = new WeakMap(), _Bot_stop = new WeakMap();
export { Methods, GroupUpdates, UserUpdates, };
export default Bot;