finish recieve messages

This commit is contained in:
2020-06-15 14:33:49 +05:30
parent 4cb7fddf92
commit c9282c1ab7
6 changed files with 195 additions and 30 deletions

View File

View File

@@ -2,7 +2,11 @@
**indev** - still being made
Telegram bot.
Telegram bot deployed using Heroku.
## Why
A test on async await, and typescript. Since this project is IO-bound(mostly), it makes sense to use Node and Typescript.
## Usage
@@ -20,6 +24,6 @@ JACK_TOKEN="u thought" npm start
## Goals
- [X] Read Name
- [ ] Read msgs
- [ ] Deal with msgs
- [X] Read msgs
- [X] Deal with msgs
- [ ] Implement response bodies

View File

@@ -2,6 +2,8 @@ import delay from './misc/delay'
import {teleargs,envVars,getUpdateBody} from './misc/defs'
import getName from './misc/getName'
import {getMessage,getInit} from './tg/getWrapper';
import { replyStrategy} from './tg/replyStrategy';
import {sendWrapper} from './tg/sendWrapper'
import { assert } from 'console';
const token = process.env['JACK_TOKEN'] as string;
@@ -10,15 +12,15 @@ if(token===undefined){
}
if (require.main === module) {
loop({token}).catch(reason => {
console.error("E:", reason);
console.error('E:', reason);
});
}
//Enable this to see cool viz
// setInterval(()=>console.log("10secs"),10000);
/**
* Main bot loop
* @param args Environment variables
*/
async function loop(args:envVars) {
const requestURL = 'https://api.telegram.org/bot'+token;
let name:string;
@@ -31,19 +33,41 @@ async function loop(args:envVars) {
console.info(`Name: ${selfName}`);
let lastUpdate = 0;
const timeout = 100;
//configurable parameters
const pollingInterval = 100;
const maxArraySize = 64;
const intervalTimerVal = 1000;
const sender = new sendWrapper(requestURL,intervalTimerVal/10,maxArraySize);
const requestArrays:Promise<boolean>[] = [];
try {
while (true) {
//basically, check every second at max
let x = delay(1000);
let x = delay(intervalTimerVal);
//while we await, we can do other stuff
lastUpdate = await main({name:selfName,token,requestURL,lastUpdate,timeout});
const responses= await main({name:selfName,token,requestURL,lastUpdate,timeout: pollingInterval});
//update the last response number
lastUpdate = responses.maxMsgUpdateID;
//push it all in
await sender.pushAll(responses.sendables);
requestArrays.push(sender.popMost());
//~~ makes it an integer
if(requestArrays.length>~~(maxArraySize/10)){
//ensure the request some time ago has completed.
//If it hasnt, it should stall everything
await requestArrays.shift();
}
await x;
}
}catch(e){
console.error("E:",e.msg||e.message||'Error');
setTimeout(loop,timeout*101);
console.error('E:',e.msg||e.message||'Error');
setTimeout(loop,pollingInterval*101);
}
}
@@ -53,7 +77,7 @@ async function loop(args:envVars) {
* @returns the last update we got
*/
async function main(args:teleargs) {
console.debug("Logging Update for:",args.lastUpdate);
// console.debug("Logging Update for:",args.lastUpdate);
const actions = await getMessage(args);
const body = actions.body as unknown as getUpdateBody;
assert(body.ok);
@@ -61,14 +85,15 @@ async function main(args:teleargs) {
//Do something
console.debug(body.result);
// console.debug(body.result);
const sendables = await replyStrategy(body.result);
// const update_id = actions.body.
// return the update number
const getMaxMsgUpdateID:number = body.result.reduce((acc,curr)=>{
const maxMsgUpdateID:number = body.result.reduce((acc,curr)=>{
return curr.update_id>acc?curr.update_id:acc;
},args.lastUpdate);
return getMaxMsgUpdateID;
return {maxMsgUpdateID,sendables};
}

View File

@@ -12,9 +12,24 @@ export interface envVars{
}
export interface userObj{
id:number,
is_bot:boolean,
first_name:string,
last_name?:string,
username?:string
}
export interface messageObj{
message_id:number,
from?:userObj,//TODOF add user
date:number,
chat:any,//TODOF add Chat
audio?:any,
document?:any,
photo?:any,
sticker?:any,
caption?:string,
text?:string
}
export interface getUpdateResultBody{
@@ -26,17 +41,14 @@ export interface getUpdateBody{
result:getUpdateResultBody[]
}
export interface sendMessage{
chat_id:number,
text:string,
disable_notification?:boolean,
reply_to_message_id?: number
}
export interface initBody{
ok:boolean,
result:{
id:number,
is_bot:boolean,
first_name:string,
username:string,
can_join_groups:boolean,
can_read_all_group_messages:boolean,
supports_inline_queries: boolean
}
result:userObj
}

48
src/tg/replyStrategy.ts Normal file
View File

@@ -0,0 +1,48 @@
import { getUpdateResultBody, sendMessage } from '../misc/defs';
/**
* Filter the non-text out
* @param updates set of updates
*/
export async function replyStrategy(updates: getUpdateResultBody[]) {
const nonTextMessages = updates.filter(e => e.message && !e.message.text);
const textMessages = updates.filter(e => e.message && e.message.text);
//Log stats
if (textMessages.length > 0||nonTextMessages.length > 0) {
console.log(`Got: ${textMessages.length} text messages,${nonTextMessages.length} weird stuff`);
}
const textReplies = await replyText(textMessages);
const nonTextReplies = await replyNonText(nonTextMessages);
return [...textReplies,...nonTextReplies];
}
export async function replyText(updates: getUpdateResultBody[]): Promise<sendMessage[]> {
return updates.map(e => {
return {
chat_id: e.message?.from?.id as number,
reply_to_message_id: e.message?.message_id,
text: 'Hello World!'
};
})
}
export async function replyNonText(updates: getUpdateResultBody[]):Promise<sendMessage[]> {
return updates.map(e => {
return {
chat_id: e.message?.from?.id as number,
text: 'This is useless to me :(',
reply_to_message_id: e.message?.message_id
};
})
}

76
src/tg/sendWrapper.ts Normal file
View File

@@ -0,0 +1,76 @@
import { sendMessage } from '../misc/defs'
import got from 'got';
import assert from 'assert';
import delay from '../misc/delay'
/**
* Buffers the output
*/
export class sendWrapper {
queue: sendMessage[];
maxLength: number;
sendURL: string;
minDelay: number;
/**
*
* @param requestURL request URL to send via
* @param minDelay Minimum delay between
* @param maxLength Max length of allowed array
*/
constructor(requestURL: string, minDelay: number = 500, maxLength: number = 100) {
this.queue = [];
this.minDelay = minDelay;
this.sendURL = requestURL + '/sendMessage';
this.maxLength = maxLength;
}
/**
*
* @param message Message to send
* @returns Whether push was successful
*/
public async push(message: sendMessage) {
if (this.queue.length < this.maxLength) {
this.queue.push(message);
return true;
} else {
console.warn("Too many responses");
return false;
}
}
public async pushAll(messages:sendMessage[]){
if (this.queue.length+messages.length < this.maxLength) {
this.queue.push(...messages);
} else {
//best fit
this.queue.push(...messages.slice(0,this.maxLength-messages.length));
console.warn("Too many responses");
}
return this;
}
/**
* Send all required
*/
public async popMost(): Promise<boolean> {
while (this.queue.length > 0) {
//Removing this
const element = this.queue.shift()
if (element) {
const mintimer = delay(this.minDelay);
try {
const answ = await got.post(this.sendURL, { json: element });
}catch(e){
console.error("Failed to send:",element.text);
return false;
}finally{
await mintimer;
}
}
}
return true;
}
}