UNPKG

7.17 kBJavaScriptView Raw
1const fs = require('fs');
2const qs = require('querystring');
3const axios = require('axios');
4const FormData = require('form-data');
5
6const Keyboard = require('./interfaces/keyboard');
7const Attachment = require('./interfaces/attachment');
8
9const { ApiError, UploadError, TypeError, NotImplementedError } = require('./exceptions');
10
11/**
12 * Class VkBotSdkClient
13 *
14 * @property {Object} options
15 */
16class VkBotSdkClient {
17 /**
18 * Создает экземпляр
19 * @param {Object} options
20 */
21 constructor(options) {
22 this.options = {
23 v: '5.107',
24 lang: 'ru',
25 debug: true,
26 group_id: 0,
27 secret: '',
28 confirmation: '',
29 access_token: ''
30 };
31
32 if(!options.access_token) {
33 throw new NotImplementedError('options.access_token is required');
34 }
35
36 if('v' in options) this.options.v = options.v;
37 if('lang' in options) this.options.lang = options.lang;
38 if('debug' in options) this.options.debug = options.debug;
39 if('group_id' in options) this.options.group_id = options.group_id;
40 if('secret' in options) this.options.secret = options.secret;
41 if('confirmation' in options) this.options.confirmation = options.confirmation;
42 if('access_token' in options) this.options.access_token = options.access_token;
43
44 this.client = axios.create({
45 baseURL: 'https://api.vk.com/method/'
46 });
47 }
48
49 /**
50 * Логирует информацию при options.debug = true
51 */
52 debug(...args) {
53 if(this.options.debug) console.log('[sdk]', ...args);
54 }
55
56 /**
57 * Отправляет запрос по URL
58 *
59 * @param {string} url
60 * @param {object} params
61 */
62 async get(url, params) {
63 const result = await axios.get(url, {
64 headers: {},
65 params: params
66 });
67
68 return result.data;
69 }
70
71 /**
72 * Отправляет запрос к API
73 *
74 * @throws ApiError
75 * @param {string} method
76 * @param {object} params
77 */
78 async request(method, params) {
79 if(!params.v) params.v = this.options.v;
80 if(!params.lang) params.lang = this.options.lang;
81 if(!params.access_token) params.access_token = this.options.access_token;
82
83 try {
84 const result = await this.client.post(method, qs.encode(params), {
85 headers: { 'content-type': 'application/x-www-form-urlencoded' }
86 });
87
88 if('error' in result.data) {
89 throw new ApiError(
90 result.data['error']['error_code'],
91 result.data['error']['error_msg'],
92 result.data['error']['request_params'],
93 )
94 }
95
96 return result.data['response'];
97 }
98 catch (e) {
99 if(this.options.debug) console.error('[sdk]', e);
100
101 throw new ApiError(0, 'Unknown error', []);
102 }
103 }
104
105 /**
106 * Загружает файл по URL
107 *
108 * @param {string} url
109 * @param {Buffer|PathLike} file
110 * @param {string} key
111 * @param {string} filename
112 */
113 async uploadFile(url, file, key, filename) {
114 if(typeof file === 'string') {
115 file = await fs.readFileSync(file);
116 }
117
118 const formData = new FormData();
119
120 formData.append(key, file, {
121 filename: filename
122 });
123
124 const result = await axios.post(url, formData, {
125 headers: {
126 'content-type': 'multipart/form-data',
127 ...formData.getHeaders()
128 }
129 });
130
131 if(typeof result.data === 'string') {
132 throw new UploadError(result.data);
133 }
134
135 return result.data;
136 }
137
138 /**
139 * Отправляет сообщение с указанными данными
140 *
141 * @async
142 * @param {number|string|number[]|string[]} arguments[0] - Получатель/получатели сообщения
143 * @param {string} arguments[1] - Текст сообщения
144 * @param {string|string[]|Attachment|Attachment[]} arguments[2] - Вложение/вложения
145 * @param {Keyboard} arguments[3] - Клавиатура
146 * @param {Object} arguments[4] - Собственные параметры
147 */
148 sendMessage() {
149 let args = Array.from(arguments);
150 let params = { random_id: 0 };
151
152 let peer, text, attachment, keyboard, props = {};
153
154 /**
155 * Преобразование смешанных аргументов
156 */
157 if(args.length < 1) throw new TypeError('Invalid arguments count');
158
159 if(typeof args[0] === 'object') {
160 const object = args[0];
161
162 if('peer_id' in object) peer = object['peer_id'];
163 else if('peer_ids' in object) peer = args['peer_ids'];
164 else if('user_id' in object) peer = args['user_id'];
165 else if('user_ids' in object) peer = args['user_ids'];
166
167 if('text' in object) text = object['text'];
168 if('attachment' in object) attachment = object['attachment'];
169 if('keyboard' in object) keyboard = object['keyboard'];
170 if('params' in object) props = object['params'];
171 }
172 else {
173 if(args[0]) peer = args[0];
174 if(args[1]) text = args[1];
175 if(args[2]) attachment = args[2];
176 if(args[3]) keyboard = args[3];
177 if(args[4]) props = args[4];
178 }
179
180 /**
181 * Подбор и форматирование текста, получателя, вложения и клавиатуры
182 */
183 if(text !== undefined && text.length > 0) params.message = text;
184
185 if(peer !== undefined && Array.isArray(peer)) params.peer_ids = peer.join(',');
186 else params.peer_id = peer;
187
188 if(attachment !== undefined) {
189 const attachmentList = Array.isArray(attachment) ? attachment : [attachment];
190 const attachmentListResult = [];
191
192 for (let item of attachmentList) {
193 if(typeof item === 'string') attachmentListResult.push(item);
194 else if(item instanceof Attachment) attachmentList.push(item.toString());
195 else throw new TypeError('Invalid attachment type');
196 }
197
198 params.attachment = attachmentListResult.join(',');
199 }
200
201 if(keyboard !== undefined) {
202 if(keyboard instanceof Keyboard) params.keyboard = keyboard.formatToJSON();
203 else throw new TypeError('Invalid keyboard type');
204 }
205
206 /**
207 * Установка кастомных параметров
208 */
209 const propsKeys = Object.keys(props);
210
211 if(propsKeys.length > 0) {
212 for (let key of propsKeys) params[key] = props[key];
213 }
214
215 return this.request('messages.send', params);
216 }
217}
218
219module.exports = VkBotSdkClient;