finish recieve messages
This commit is contained in:
10
README.md
10
README.md
@@ -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
|
55
src/index.ts
55
src/index.ts
@@ -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};
|
||||
}
|
||||
|
||||
|
@@ -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
48
src/tg/replyStrategy.ts
Normal 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
76
src/tg/sendWrapper.ts
Normal 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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user