telegram.d (4002B)
1 module bastlibridge.interfaces.telegram; 2 static import tg=telegram.telegram; 3 import bastlibridge.base; 4 import bastlibridge.command; 5 import std.conv; 6 import std.format; 7 import core.sync.mutex; 8 import std.array; 9 import std.datetime : SysTime, Clock; 10 import std.json; 11 import std.algorithm; 12 13 final class Telegram: QueuedEndpoint{ 14 private tg.Telegram telegram, telegram_listener; 15 Mutex telegram_lock, listener_lock; 16 17 this(Manager m, string args){ 18 super(m,args); 19 20 telegram=tg.Telegram(args); 21 telegram_listener=tg.Telegram(args); 22 23 telegram_lock=new Mutex(); 24 listener_lock=new Mutex(); 25 26 telegram_listener.onMessage~=(j){ 27 trace("Received Message\n"~j.toPrettyString()); 28 auto jv="text" in j; 29 trace("We have some text"); 30 string msg=""; 31 if(jv){ 32 msg=j["text"].str; 33 } 34 trace("got message ", msg); 35 36 auto chatid=j["chat"]["id"].integer; 37 trace("chatid is ", chatid); 38 auto chan=chatid in telegram_channels; 39 trace("we got the channel ", chan); 40 auto get_msg(){ 41 auto m=new TelegramMessage(j); 42 m.source=this; 43 return m; 44 } 45 void forward_msg(){ 46 if(!chan){ 47 warning("Message to unknown chat ", chatid); 48 } 49 else{ 50 manager.distribute(Port(this, *chan), get_msg()); 51 } 52 } 53 54 if(msg.length>0 && msg.front=='/'){ 55 trace("Bot command received"); 56 try{ 57 auto split=msg.findSplit(" "); 58 auto cmdbot=split[0].findSplit("@"); 59 if(cmdbot[1].length!=0 && cmdbot[2]!=telegram.botName){ 60 trace("Not one of our commands"); 61 forward_msg(); 62 } 63 else{ 64 auto s=msg.findSplit(" "); 65 globalCommands.execute(s[0][1..$], get_msg(), s[2], false); 66 } 67 } 68 catch(Exception e){ 69 warning(e.to!string); 70 } 71 } 72 else{ 73 trace("Normal message"); 74 forward_msg(); 75 } 76 }; 77 } 78 79 override void open(){ 80 telegram.connect(); 81 telegram_listener.connect(); 82 } 83 84 private TelegramChannel[long] telegram_channels; 85 override Channel join(string c){ 86 auto id=c.to!long; 87 auto chan=new TelegramChannel(id); 88 telegram_channels[id]=chan; 89 return chan; 90 } 91 92 override void part(Channel c){ 93 94 } 95 96 override void sendMessageQueueless(Message m, Channel c){ 97 send((cast(TelegramChannel)c).id, "<"~m.userName()~"> "~m.getMessage()); 98 } 99 100 private __gshared bool shutdown=false; 101 102 override void run(){ 103 import ssl.openssl; 104 loadOpenSSL(); //We have to do this once for every thread 105 while(!shutdown){ 106 trace("triggering updates"); 107 synchronized(mtx) 108 telegram_listener.triggerUpdates(); 109 trace("waiting for messages"); 110 telegram_listener.wait(); 111 heartbeat(); 112 synchronized(mtx){ 113 telegram_listener.read(); 114 sendQueue(); 115 } 116 trace("msgloop done"); 117 } 118 } 119 120 override void stop(){ 121 shutdown=true; 122 telegram_listener.disconnect(); 123 synchronized(telegram_lock) 124 telegram.disconnect(); 125 } 126 127 void send(long id, in char[] msg){ 128 synchronized(telegram_lock){ 129 telegram.send(id, msg); 130 } 131 } 132 } 133 134 final class TelegramChannel : Channel{ 135 long id; 136 this(long id){ 137 this.id=id; 138 } 139 } 140 141 final class TelegramMessage : Message{ 142 JSONValue json; 143 144 @property Telegram _source(){ 145 return cast(Telegram)(source); 146 } 147 148 this(JSONValue json){ 149 this.json=json; 150 } 151 static string TelegramUser(JSONValue User){ 152 string username="unknown"; 153 foreach(key; ["username", "first_name", "last_name"]){ 154 if(key in User){ 155 username=User[key].str; 156 break; 157 } 158 } 159 return username; 160 } 161 override const(char)[] userName(){ 162 if(auto from="from" in json){ 163 return TelegramUser(*from); 164 } 165 return ""; 166 } 167 168 override const(char)[] getMessage(){ 169 if(auto t="text" in json){ 170 return t.str; 171 } 172 return ""; 173 } 174 override const(char)[] getChannelName(){ 175 auto chat=json["chat"]; 176 if(auto t="title" in chat){ 177 return t.str; 178 } 179 return json["id"].integer.to!string; 180 } 181 182 override bool auth(){ 183 return false; 184 } 185 186 override SysTime getTime(){ 187 return SysTime(); 188 } 189 190 override void respond(in char[] response){ 191 _source.send(json["chat"]["id"].integer, response); 192 } 193 }