forked from nique_372/TelegramByLeo
184 lines
5.4 KiB
MQL5
184 lines
5.4 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| CommandsApi.mqh |
| |
//| Copyright 2026, Niquel Mendoza. |
| |
//| https://www.mql5.com |
| |
//+------------------------------------------------------------------+
| |
#property copyright "Copyright 2026, Niquel Mendoza."
| |
#property link "https://www.mql5.com"
| |
#property strict
| |
| |
#ifndef TELEGRAMBYLEO_SRC_COMMANDSAPI_MQH
| |
#define TELEGRAMBYLEO_SRC_COMMANDSAPI_MQH
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
#include "Events.mqh"
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
namespace TSN
| |
{
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
class CTelegramCommandBot : public CTelegramBot
| |
{
| |
protected:
| |
CHashMapFast(ulong, int) m_commands;
| |
// por ahora si quizas luego lista de priridad con un sorted list
| |
| |
//---
| |
bool ResolveCommand(const uchar& in[], int i, int len);
| |
bool IsMyUsername(const uchar& in[], int i, int e);
| |
| |
//--- Cada comando
| |
virtual void OnCommand(int command_idx, long chat_id, CJsonNode& json) {}
| |
| |
public:
| |
CTelegramCommandBot(void) {}
| |
~CTelegramCommandBot(void) {}
| |
| |
//---
| |
void SetCommand(const string& command, int idx);
| |
bool RemoveCommand(const string& command);
| |
| |
//---
| |
void OnMessage(CJsonNode& node) override final;
| |
};
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
bool CTelegramCommandBot::IsMyUsername(const uchar& in[], int i, int e)
| |
{
| |
//---
| |
// 1. e apnta a la posicion "end + 1"
| |
| |
//---
| |
const int my_len = StringLen(m_me.username); // len del user name que tenemos
| |
const int l = (e - i); // len de lo que encontramos
| |
if(l != my_len) // no es igual...
| |
return false;
| |
| |
//---
| |
for(int x = 0; x < l; x++)
| |
if(in[i++] != m_me.username[x])
| |
return false;
| |
| |
//---
| |
return true;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
bool CTelegramCommandBot::ResolveCommand(const uchar &in[], int i, int len)
| |
{
| |
// len = min
| |
len += i;
| |
i++; // salta \
| |
| |
//---
| |
// 1. una sola pasada para veriicar y hash (no dos)
| |
ulong h = FNV_OFFSET_BASIS;
| |
uchar c = in[i];
| |
while(true)
| |
{
| |
if(c == ' ' || c == '@')
| |
break;
| |
| |
//--
| |
h ^= c;
| |
h *= FNV_PRIME;
| |
| |
//--
| |
if(++i >= len)
| |
break;
| |
| |
//---
| |
c = in[i];
| |
}
| |
| |
//---
| |
if(i < len && c == '@')
| |
{
| |
//---
| |
i++; // salta '@'
| |
int bot_start = i;
| |
while(i < len && in[i] != ' ')
| |
i++;
| |
| |
//---
| |
if(!IsMyUsername(in, bot_start, i))
| |
return false;
| |
}
| |
| |
//---
| |
// vol en vez de int (ternario menos par ael TryGet==true? 1 : value)
| |
return m_commands.ContainsKey(h);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CTelegramCommandBot::SetCommand(const string &command, int idx)
| |
{
| |
//--- hash
| |
ulong h = FNV_OFFSET_BASIS;
| |
const int len = StringLen(command);
| |
FNV1A_64_AsM_Str(command, len, h, FNV_PRIME)
| |
| |
//---
| |
if(m_commands.ReserveSlot(h)) // no existe
| |
{
| |
const uint p = m_commands.m_last_pos_tbl;
| |
m_commands.m_table[p].key = h;
| |
m_commands.m_table[p].value = idx;
| |
}
| |
else
| |
{
| |
// Ya existe... modificamos el valor
| |
m_commands.m_table[m_commands.m_last_pos_tbl].value = idx;
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
bool CTelegramCommandBot::RemoveCommand(const string &command)
| |
{
| |
//--- hash
| |
ulong h = FNV_OFFSET_BASIS;
| |
const int len = StringLen(command);
| |
FNV1A_64_AsM_Str(command, len, h, FNV_PRIME)
| |
| |
//---
| |
return m_commands.Remove(h);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CTelegramCommandBot::OnMessage(CJsonNode &node)
| |
{
| |
//---
| |
CJsonNode text = node["text"];
| |
const int start = text.StrStart();
| |
const int len = text.StrLenRaw();
| |
if(!text.IsValid() || len < 1 || text.m_ctx.m_raw[start] != '/')
| |
return;
| |
| |
//---
| |
//parseamos el texto inplace (sobre buffer ucahr) sin copia y conusltmaos el indice del grupo (commmando) via hashmap
| |
if(!ResolveCommand(text.m_ctx.m_raw, start, len))
| |
{
| |
return;
| |
}
| |
| |
//---
| |
const uint p = m_commands.m_last_pos_tbl;
| |
OnCommand(m_commands.m_table[p].value, node["chat"]["id"].ToInt(0), node);
| |
}
| |
}
| |
//+------------------------------------------------------------------+
| |
#endif // TELEGRAMBYLEO_SRC_COMMANDSAPI_MQH
|