TelegramByLeo/Src/CommandsApi.mqh
2026-09-25 09:59:13 -05:00

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