refactor: remove grunt and babel

remove grunt from dependencies, and use transformed code instead using babel/register.
change API a litte
This commit is contained in:
Ali Movahedi
2016-03-28 00:59:00 +04:30
parent 8e14a026df
commit e5c25bd9c1
44 changed files with 576 additions and 1446 deletions

35
src/functions/api.js Normal file
View 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);
};
});

View File

@ -0,0 +1,110 @@
const FORMAT_REQUIRED = /<(\W*)(\w+)\|?(\w+)?>/g;
const FORMAT_OPTIONAL = /\[(\W*)(\w+)\|?(\w+)?\]/g;
const FORMAT_REST = /\.{3}(\w+)/g;
const ESCAPABLE = '.^$*+?()[{\\|}]'.split('');
const REQUIRED = 0;
const OPTIONAL = 1;
const REST = 2;
/**
* 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]+/, '').trim();
format = format.replace(/[^\s]+/, '').trim();
if (!format) return {args: {}, params: {}};
let indexes = [],
params = {};
format = format.replace(/\s/g, '\\s*');
format = format.replace(FORMAT_REQUIRED,
(f, symbols, arg, type = 'word', offset) => {
indexes.push({arg, offset});
params[arg] = REQUIRED;
return (escape(symbols) + getFormat(type, 'required')).trim();
});
format = format.replace(FORMAT_OPTIONAL,
(f, symbols, arg, type = 'word', offset) => {
indexes.push({arg, offset});
params[arg] = OPTIONAL;
return (escape(symbols, '?') + getFormat(type, 'optional')).trim();
});
format = format.replace(FORMAT_REST, (full, arg, offset) => {
indexes.push({offset, arg});
params[arg] = REST;
return getFormat(null, 'rest');
});
if (!string) return {args: {}, params};
indexes = indexes.sort((a, b) => {
return a.offset < b.offset ? -1 : 1;
});
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 {args: object, params};
}
function escape(symbols, append = '') {
return symbols.split('').map(symbol => {
return (ESCAPABLE.indexOf(symbol) ? `\\${symbol}` : symbol) + append;
}).join('');
}
const TYPES = {
'number': '\\d',
'word': '\\S'
};
function getFormat(type = 'word', param = 'required') {
const t = TYPES[type];
switch (param) {
case 'required':
return `(${t}+)`;
case 'optional':
return `(${t}+)?`;
case 'rest':
return `(.*)`;
}
}

42
src/functions/fetch.js Normal file
View File

@ -0,0 +1,42 @@
import unirest from 'unirest';
export default function fetch(path, data = {}) {
return new Promise((resolve, reject) => {
const files = {};
for (let key of Object.keys(data)) {
if (data[key].file) {
files[key] = data[key].file;
delete data[key];
}
}
unirest.post('https://api.telegram.org/bot' + path)
.field(data)
.attach(files)
.end(response => {
if (response.statusType === 4 || response.statusType === 5 ||
!response.body || !response.body.ok) {
reject(response);
} else {
resolve(response.body);
}
});
});
}
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);
});
}

11
src/functions/poll.js Normal file
View File

@ -0,0 +1,11 @@
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);
if (bot._stop) return null;
return poll(bot);
});
}

24
src/functions/webhook.js Normal file
View 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(() => {
bot._webhookServer = https.createServer(options.server, (req, res) => {
return getBody(req).then(data => {
bot.emit('update', qs.parse(data).result);
res.end('OK');
});
}).listen(options.port);
});
}