BastliBridge

git clone git://xatko.vsos.ethz.ch/BastliBridge.git
Log | Files | Refs | Submodules | README

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 }