package de.mrbesen.telegram; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.URL; import java.util.LinkedList; import java.util.Scanner; import javax.net.ssl.HttpsURLConnection; import org.json.JSONArray; import org.json.JSONObject; import de.mrbesen.telegram.MessageBuilder.SendableMessage; import de.mrbesen.telegram.commands.CommandManager; import de.mrbesen.telegram.event.Event; import de.mrbesen.telegram.event.EventManager; import de.mrbesen.telegram.event.events.UserCallbackEvent; import de.mrbesen.telegram.event.events.UserSendAudioEvent; import de.mrbesen.telegram.event.events.UserSendMessageEvent; import de.mrbesen.telegram.log.Log; import de.mrbesen.telegram.log.Log4JLog; import de.mrbesen.telegram.log.SimpleLog; import de.mrbesen.telegram.objects.JSONBased.Member; import de.mrbesen.telegram.objects.TAudio; import de.mrbesen.telegram.objects.TMessage; import de.mrbesen.telegram.objects.TUser; import de.mrbesen.telegram.objects.TUser.Status; public class TelegramAPI implements Runnable { private static final String API_URL = "https://api.telegram.org/bot"; private static final String TOKENREGEX = "^\\d{4,9}:[\\w-]{12,64}$"; public static final String APIVERSION = "3.6";//February 13, 2018 private int msg_offset = 0; private int updateInterval = 1500; private String apikey; private Thread thread; private boolean run = true; private String helpmessage = "generic helppage\nuse TelegramAPI.setHelpText(java.lang.String) to change this."; private LinkedList users = new LinkedList<>(); private CommandManager cmdmgr = new CommandManager(); private EventManager evntmgr = new EventManager(); Log log = new Log4JLog(); public TelegramAPI(String apikey) { if (!apikey.matches(TOKENREGEX) ) { throw new IllegalArgumentException("Invalid API key"); } this.apikey = apikey; } public void start() { if(thread == null) { run = true; thread = new Thread(this, "TelegramAPI"); thread.start(); } else { throw new IllegalStateException("Still Running."); } } public JSONObject request(String request, String parameter) throws IOException { //do https stuff URL url = new URL(API_URL + apikey + "/" + request); HttpsURLConnection con = (HttpsURLConnection)url.openConnection(); con.setDoInput(true); con.setDoOutput(true); OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream()); wr.write(parameter); wr.flush(); log.log( "request: " + request + " content " + parameter + " -> " + con.getResponseCode() + ", " + con.getResponseMessage()); Scanner s = new Scanner(con.getInputStream()); StringBuilder sb_apianswer = new StringBuilder(); while(s.hasNextLine()) { sb_apianswer.append(s.nextLine()).append('\n'); } s.close(); if(con.getResponseCode() == 200) { return new JSONObject(sb_apianswer.toString()); } else { String errdesc = ""; try { JSONObject returned = new JSONObject(sb_apianswer.toString()); errdesc = returned.getString("description"); } catch(Throwable ignore) { } throw new IOException("API request returned HTTP " + con.getResponseCode() + " (" + con.getResponseMessage() + ") for action " + request + "\nurl: " + url.toString() + "\nparams: " + parameter + "\nerror description: " + errdesc); } } public TMessage sendMessage(TUser user, String text) { MessageBuilder builder = new MessageBuilder(); builder.setReciver(user.getID()); builder.setText(text); return sendMessage(builder.build()); } public TMessage sendMessage(SendableMessage msg) { try { JSONObject o = request("sendMessage", msg.getQ()); return new TMessage(o.getJSONObject("result"), this); } catch(IOException e) { log.log("",e); } return null; } public void sendTypedMessage(final String msg, final TUser user, final int seconds) { new Thread(new Runnable() { @Override public void run() { user.sendStatus(Status.Typing); try { Thread.sleep(seconds*1000); } catch (InterruptedException e) { } sendMessage(new MessageBuilder().setText(msg).setReciver(user.getID()).build()); } }).start(); } public void stop() { run = false; thread.interrupt(); Thread.yield();//try to not get into that loop while(isRunning()) { thread.interrupt(); Thread.yield(); try { Thread.sleep(10); } catch(InterruptedException e) {} } log.log("tapi stoped."); thread = null; } @Override public void run() { while(run) { fetchUpdates(); try { Thread.sleep(updateInterval); } catch (InterruptedException e) { break; } } } public boolean isRunning() { return thread.isAlive(); } private void fetchUpdates() { try { processUpdates(request("getUpdates", "offset=" + msg_offset)); } catch (IOException e) { log.log("error getting updates.", e); } } private void processUpdates(JSONObject object) { if(object == null) return; JSONArray arr_results = object.getJSONArray("result"); for(int i = 0; !arr_results.isNull(i); i++) { JSONObject entry = arr_results.getJSONObject(i); TelegramAPIUpdate upd = new TelegramAPIUpdate(entry, this); msg_offset = (upd.update_id+1 > msg_offset ? upd.update_id+1 : msg_offset); } } public TUser getUser(String name) { for(TUser us : users) { if(us.getName().equals(name)) return us; } return null; } public TUser getUser(int id) { for(TUser us : users) { if(us.getID() == id) return us; } TUser u = new TUser(id, this); users.add(u); return u; } /** * gets a user by id from the known user lists, * if no user found, it creates a new User and adds it to the list. * @param json * @return */ public TUser getUser(JSONObject json) { int id = json.getInt("id"); TUser user = getUser(id); if(user != null) return user; user = new TUser(json, this); users.add(user); return user; } public void setHelpText(String helptext) { helpmessage = ( helptext == null ? "" : helptext); } /** * Set the logging method, use {@link Log4JLog} for usage of LOG4J, * or {@link SimpleLog} for usage of System.out.println(); * use Null t odisable logging the default is {@link SimpleLog} * @param l */ public void setLog(Log l) { if(l == null) log = new Log(); else log = l; } public CommandManager getCommandManager() { return cmdmgr; } public EventManager getEventManager() { return evntmgr; } public void setUpdateInterval(int d) { if(d < 0) throw new IllegalArgumentException("UpdateInterval is not allowed to be negative."); updateInterval = d; } public String getHelpMessage() { return helpmessage; } public int getupdateInterval() { return updateInterval; } protected class TelegramAPIUpdate { protected int update_id = 0; private TMessage msg = null; private boolean isCommand = false; protected TelegramAPIUpdate(JSONObject json, TelegramAPI api) { update_id = json.getInt("update_id"); if(json.has("message")) { msg = new TMessage(json.getJSONObject("message"), api); String text = msg.getText(); if(text != null) { if(text.startsWith("/" )) { text = text.substring(1);//remove '/' isCommand = true; cmdmgr.onCommand(text, msg.getFrom(), json.getJSONObject("message")); } else { Event e = null; if(getMsg().has(Member.audio)) { e = new UserSendAudioEvent(getUser(), new TAudio((JSONObject) getMsg().get(Member.audio))); } else if(getMsg().has(Member.video)) { } else if(getMsg().has(Member.document)) { } else if(getMsg().has(Member.invoice)) { } else if(getMsg().has(Member.location)) { } else if(getMsg().has(Member.video_note)) { } else if(getMsg().has(Member.game)) { } else if(getMsg().has(Member.contact)) { } else if(getMsg().has(Member.sticker)) { } else { e = new UserSendMessageEvent(getMsg()); } getEventManager().callEvent(e); } } } else if(json.has("callback_query")) { JSONObject cbq = json.getJSONObject("callback_query"); TUser from = api.getUser(cbq.getJSONObject("from")); String data = cbq.getString("data"); getEventManager().callEvent(new UserCallbackEvent(from, data)); } } protected int getUpdate_id() { return update_id; } protected TMessage getMsg() { return msg; } protected TUser getUser() { return msg.getFrom(); } protected boolean isCommand() { return isCommand; } } public enum JSONObjectType { User, Chat, Message, MessageEntity, Audio, Document, Game, Sticker, Video, Voice, Videonote, Location, Venue, Contact; boolean isArray = false; void setArray(boolean b) { isArray = b; } } }