Add Argument Parser 💪
This commit is contained in:
35
lib/functions/api.js
Normal file
35
lib/functions/api.js
Normal file
@ -0,0 +1,35 @@
|
||||
// API methods
|
||||
import fetch from './fetch';
|
||||
|
||||
/**
|
||||
* API class, has a function for each method of the Telegram API which take
|
||||
* an object argument, and send request to the API server
|
||||
*
|
||||
* Methods: getMe, sendMessage, forwardMessage, sendPhoto, sendAudio,
|
||||
* sendDocument, sendSticker, sendVideo, sendLocation, sendChatAction,
|
||||
* getUserProfilePhotos, getUpdates
|
||||
*/
|
||||
export default class API {
|
||||
/**
|
||||
* Create a new api object with the given token
|
||||
* @param {string} token
|
||||
*/
|
||||
constructor(token) {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
|
||||
API.prototype.request = function request(method, data) {
|
||||
return fetch(this.token + '/' + method, data);
|
||||
};
|
||||
|
||||
const methods = ['getMe', 'sendMessage', 'forwardMessage', 'sendPhoto',
|
||||
'sendAudio', 'sendDocument', 'sendSticker', 'sendVideo',
|
||||
'sendLocation', 'sendChatAction', 'getUserProfilePhotos',
|
||||
'getUpdates', 'setWebhook'];
|
||||
|
||||
methods.forEach(method => {
|
||||
API.prototype[method] = function(data) {
|
||||
return this.request(method, data);
|
||||
};
|
||||
});
|
98
lib/functions/argument-parser.js
Normal file
98
lib/functions/argument-parser.js
Normal file
@ -0,0 +1,98 @@
|
||||
const FORMAT_REQUIRED = /<(\W*)(\w+)\|?(\w+)?>/g;
|
||||
const FORMAT_OPTIONAL = /\[(\W*)(\w+)\|?(\w+)?\]/g;
|
||||
const FORMAT_REST = /\.{3}(\w+)/g;
|
||||
|
||||
const ESCAPABLE = '.^$*+?()[{\\|}]'.split('');
|
||||
|
||||
/**
|
||||
* Parses a message for arguments, based on format
|
||||
*
|
||||
* The format option may include '<requiredParam>' and '[optionalParam]' and
|
||||
* '...[restParam]'
|
||||
* <requiredParam> indicates a required, single-word argument
|
||||
* [optionalParam] indicates an optinal, single-word argument
|
||||
* ...[restParam] indicates a multi-word argument which records until end
|
||||
*
|
||||
* You can define a type for your arguments using pipe | sign, like this:
|
||||
* [count|number]
|
||||
* Supported Types are: number and word, defaults to word
|
||||
*
|
||||
* Example:
|
||||
* format: '<name> [count|number] ...text'
|
||||
* string 1: 'Someone Hey, wassup'
|
||||
* {name: 'Someone',
|
||||
* count: undefined,
|
||||
* text: 'Hey, wassup'}
|
||||
*
|
||||
* string 2: 'Someone 5 Hey, wassup'
|
||||
* {name: 'Someone',
|
||||
* count: 5,
|
||||
* text: 'Hey, wassup'}
|
||||
* @param {string} format Format, as described above
|
||||
* @param {string} string The message to parse
|
||||
* @return {object} Parsed arguments
|
||||
*/
|
||||
export default function argumentParser(format, string) {
|
||||
string = string.replace(/[^\s]+/, '');
|
||||
format = format.replace(/[^\s]+/, '');
|
||||
let indexes = [];
|
||||
|
||||
format = format.replace(/\s/g, '\\s*');
|
||||
format = format.replace(FORMAT_REQUIRED,
|
||||
(f, symbols, arg, type = 'word', offset) => {
|
||||
indexes.push({arg, offset});
|
||||
return (escape(symbols) + getFormat(type, 'required')).trim();
|
||||
});
|
||||
format = format.replace(FORMAT_OPTIONAL,
|
||||
(f, symbols, arg, type = 'word', offset) => {
|
||||
indexes.push({arg, offset});
|
||||
return (escape(symbols, '?') + getFormat(type, 'optional')).trim();
|
||||
});
|
||||
format = format.replace(FORMAT_REST, (full, arg, offset) => {
|
||||
indexes.push({offset, arg});
|
||||
return getFormat(null, 'rest');
|
||||
});
|
||||
|
||||
indexes = indexes.sort((a, b) => {
|
||||
return a.offset < b.offset ? -1 : 1;
|
||||
});
|
||||
|
||||
console.log(format);
|
||||
const regex = new RegExp(format);
|
||||
|
||||
const matched = regex.exec(string).slice(1);
|
||||
|
||||
const object = {};
|
||||
for (let [index, match] of matched.entries()) {
|
||||
const argument = indexes[index];
|
||||
|
||||
object[argument.arg] = match;
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
function escape(symbols, append = '') {
|
||||
return symbols.split('').map(symbol => {
|
||||
return (ESCAPABLE.indexOf(symbol) ? `\\${symbol}` : symbol) + append;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
|
||||
const TYPES = {
|
||||
'number': '\\d',
|
||||
'word': '\\w'
|
||||
};
|
||||
|
||||
function getFormat(type = 'word', param = 'required') {
|
||||
const t = TYPES[type];
|
||||
|
||||
switch (param) {
|
||||
case 'required':
|
||||
return `(${t}+)`;
|
||||
case 'optional':
|
||||
return `(${t}+)?`;
|
||||
case 'rest':
|
||||
return `(.*)`;
|
||||
}
|
||||
}
|
35
lib/functions/fetch.js
Normal file
35
lib/functions/fetch.js
Normal file
@ -0,0 +1,35 @@
|
||||
import restler from 'restler';
|
||||
|
||||
export default function fetch(path, data = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const method = Object.keys(data).length ? 'POST' : 'GET';
|
||||
const multipart = method === 'POST' ? true : false;
|
||||
|
||||
restler.request('https://api.telegram.org/bot' + path, {
|
||||
data, method, multipart
|
||||
}).on('complete', response => {
|
||||
try {
|
||||
let json = JSON.parse(response);
|
||||
resolve(json);
|
||||
} catch(e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function getBody(stream) {
|
||||
let data = '';
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
stream.on('data', chunk => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
resolve(data);
|
||||
});
|
||||
|
||||
stream.on('error', reject);
|
||||
});
|
||||
}
|
10
lib/functions/poll.js
Normal file
10
lib/functions/poll.js
Normal file
@ -0,0 +1,10 @@
|
||||
export default function poll(bot) {
|
||||
return bot.api.getUpdates(bot.update).then(response => {
|
||||
if (!response.result.length) {
|
||||
return poll(bot);
|
||||
}
|
||||
bot.emit('update', response.result);
|
||||
|
||||
return poll(bot);
|
||||
});
|
||||
}
|
24
lib/functions/webhook.js
Normal file
24
lib/functions/webhook.js
Normal file
@ -0,0 +1,24 @@
|
||||
import https from 'http';
|
||||
import qs from 'qs';
|
||||
import {getBody} from './fetch';
|
||||
|
||||
const DEFAULTS = {
|
||||
server: {},
|
||||
port: 443
|
||||
};
|
||||
|
||||
export default function webhook(options = {}, bot) {
|
||||
options = Object.assign(DEFAULTS, options);
|
||||
|
||||
return bot.api.setWebhook(options.url).then(() => {
|
||||
|
||||
https.createServer(options.server, (req, res) => {
|
||||
return getBody(req).then(data => {
|
||||
bot.emit('update', qs.parse(data).result);
|
||||
|
||||
res.end('OK');
|
||||
});
|
||||
}).listen(options.port);
|
||||
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user