This commit is contained in:
Oliver 2018-07-18 04:44:04 +02:00
parent 5f7eaaabf2
commit bd33ef8499
16 changed files with 667 additions and 60 deletions

View File

@ -1,29 +1,49 @@
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.commands.CommandManager;
import de.mrbesen.telegram.event.Event;
import de.mrbesen.telegram.event.EventManager;
import de.mrbesen.telegram.event.events.UserSendAudioEvent;
import de.mrbesen.telegram.event.events.UserSendMessageEvent;
import objects.TMessage;
import objects.TUser;
import objects.JSONBased.Member;
import objects.TAudio;
public class TelegramAPI implements Runnable {
private int delay = 1500;
private static final String API_URL = "https://api.telegram.org/bot";
private static final String TOKENREGEX = "^\\d{4,9}:[\\w-]{12,64}$";
private int msg_offset = 0;
private int updateInterval = 1500;
private String apikey;
private Thread thread;
private boolean run = true;
private static final String api_url = "https://api.telegram.org/bot";
private String helpmessage = "generic helppage\nuse TelegramAPI.setHelpText(java.lang.String) to change this.";
private LinkedList<TUser> users = new LinkedList<>();
private CommandManager cmdmgr = new CommandManager();
private EventManager evntmgr = new EventManager();
public TelegramAPI(String apikey) {
if (!apikey.matches(TOKENREGEX) ) {
throw new IllegalArgumentException("Invalid API key");
}
this.apikey = apikey;
}
public void setDelay(int d) {
if(d < 0)
throw new IllegalArgumentException("delay is not allowed to be negative.");
delay = d;
}
public int getDelay() {
return delay;
}
public void start() {
if(thread == null) {
run = true;
@ -33,12 +53,29 @@ public class TelegramAPI implements Runnable {
throw new IllegalStateException("Still Running.");
}
}
JSONObject request(String request) {
String url = api_url + apikey + "/" + request;
public JSONObject request(String request, String parameter) throws IOException {
//do https stuff
return null;//error
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();
System.out.println( this.getClass().getSimpleName() + ": request: " + request + " -> " + con.getResponseCode() + ", " + con.getResponseMessage());
if(con.getResponseCode() == 200) {
Scanner s = new Scanner(con.getInputStream());
StringBuilder sb_apianswer = new StringBuilder();
while(s.hasNextLine()) {
sb_apianswer.append(s.nextLine()).append('\n');
}
s.close();
return new JSONObject(sb_apianswer.toString());
} else {
throw new IOException("API request returned HTTP " + con.getResponseCode() + " (" + con.getResponseMessage() + ") for action " + request );
}
}
public void stop() {
@ -55,19 +92,182 @@ public class TelegramAPI implements Runnable {
thread = null;
}
public boolean isRunning() {
return thread.isAlive();
}
@Override
public void run() {
while(run) {
//do stuff
fetchUpdates();
try {
Thread.sleep(delay);
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) {
System.err.println("error getting updates.");
e.printStackTrace();
}
}
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;
}
return null;
}
/**
* 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);
}
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());
} 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);
}
}
}
}
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;
}
}
}

View File

@ -1,18 +0,0 @@
package de.mrbesen.telegram;
public class TelegramUser {
private int chatid;
private String uname;
private TelegramAPI api;
public TelegramUser(int chatid, String uname, TelegramAPI api) {
this.chatid = chatid;
this.uname = uname;
this.api = api;
}
public void sendMessage(String msg) {
}
}

View File

@ -1,6 +1,6 @@
package de.mrbesen.telegram.commands;
import de.mrbesen.telegram.TelegramUser;
import objects.TUser;
public interface CommandHandler {
@ -11,6 +11,6 @@ public interface CommandHandler {
* @param args
* @return
*/
public boolean onCommand(TelegramUser sender, String cmd, String[] args);
public boolean onCommand(TUser sender, String cmd, String[] args);
}

View File

@ -3,29 +3,31 @@ package de.mrbesen.telegram.commands;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import de.mrbesen.telegram.TelegramUser;
import objects.TUser;
public class CommandManager {
private static String CMDPATTERN = "^[\\w-]+$";
private final static String CMDPATTERN = "^[\\w-]+$";
private Multimap<String, CommandHandler> handlerlist = ArrayListMultimap.create();//list of all registered CommandHandler
public CommandManager() { }
void onCommand(String line, TelegramUser sender) {//called by the api (/-prefix allready removed)
public void onCommand(String line, TUser sender) {//called by the api (/-prefix already removed)
line = line.trim();
String[] split = line.split(" ",2);
String cmd = split[0].toLowerCase();
boolean result = false;
if(cmd.matches(CMDPATTERN)) {
String[] args = new String[0];
if(split.length == 2) {
args = split[1].split(" ");
}
//call
// System.out.println("cmd " + cmd + " args: " + args.length);
for(CommandHandler cmdhand : handlerlist.get(cmd)) {
try {
boolean result = cmdhand.onCommand(sender, cmd, args);
result = cmdhand.onCommand(sender, cmd, args);
if(result)
break;
} catch(Throwable t) {
@ -33,8 +35,10 @@ public class CommandManager {
t.printStackTrace();
}
}
} else {
//unknown cmd!
}
//do smth. with result
if(!result) {
sender.sendHelpPage();
}
}
@ -54,7 +58,7 @@ public class CommandManager {
}
if(cmd.matches(CMDPATTERN)) {
handlerlist.put(cmd.toLowerCase(), handler);
//registered successfull!
//registered successfully!
} else {
throw new IllegalArgumentException("cmd contains unallowed characters. Allowed: a-zA-Z0-9_-");
}

View File

@ -1,16 +1,16 @@
package de.mrbesen.telegram.event;
import de.mrbesen.telegram.TelegramUser;
import objects.TUser;
public class Event {
private TelegramUser user;
private TUser user;
public Event(TelegramUser u) {
public Event(TUser u) {
user = u;
}
public TelegramUser getUser() {
public TUser getUser() {
return user;
}

View File

@ -2,8 +2,11 @@ package de.mrbesen.telegram.event;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventHandler {
}

View File

@ -8,9 +8,7 @@ public class EventManager {
private ArrayList<EventListener> listeners = new ArrayList<EventListener>();
private ArrayList<EventMethod> handler = new ArrayList<EventMethod>();
public EventManager() {
}
public EventManager() {}
@SuppressWarnings("unchecked")
public void registerEvent(EventListener listener) {
@ -22,13 +20,20 @@ public class EventManager {
}
listeners.add(listener);
//scanning handler
int found = 0;
for(Method met : listener.getClass().getMethods()) {
EventHandler h = met.getAnnotation(EventHandler.class);
if(h != null) {//handler annotation vorhanden
if(met.getParameterCount() == 1) {//only one parameter required
Class<?> parameterclass = met.getParameters()[0].getClass();
if(Event.class.isAssignableFrom(parameterclass) && !parameterclass.equals(Event.class)) {//the needed parameter is a Event-subclass)
handler.add(new EventMethod((Class<? extends Event>) parameterclass, met, listener));
Class<?> parameterclass = met.getParameters()[0].getType();
if(Event.class.isAssignableFrom(parameterclass) ) {//the needed parameter is a Event-subclass)
if(met.getReturnType().equals(void.class)) {
if((met.getModifiers() & Method.PUBLIC) == Method.PUBLIC) {
handler.add(new EventMethod((Class<? extends Event>) parameterclass, met, listener));
found ++;
}
}
} else {
//warn / error?
}
@ -37,9 +42,14 @@ public class EventManager {
}
}
}
if(found == 0) {
System.err.println("no @EventHandler found!");
}
}
public Event callEvent(Event e) {
if(e == null)
throw new NullPointerException("event is not allowed to be null!");
for(EventMethod met : handler) {
try {
e = met.callEvent(e);
@ -67,7 +77,9 @@ public class EventManager {
try {
met.invoke(listener, e);
} catch(Throwable t) {
System.err.println("Failed to invoke event! at " + listener.getClass().getSimpleName());
t.printStackTrace();
t.getCause().printStackTrace();
}
}
return e;

View File

@ -0,0 +1,19 @@
package de.mrbesen.telegram.event.events;
import de.mrbesen.telegram.event.Event;
import objects.TAudio;
import objects.TUser;
public class UserSendAudioEvent extends Event {
private TAudio audio;
public UserSendAudioEvent(TUser u, TAudio a) {
super(u);
audio = a;
}
public TAudio getAudio() {
return audio;
}
}

View File

@ -0,0 +1,23 @@
package de.mrbesen.telegram.event.events;
import de.mrbesen.telegram.event.Event;
import objects.TMessage;
import objects.TUser;
public class UserSendMessageEvent extends Event {
private TMessage m;
public UserSendMessageEvent(TMessage m) {
super(m.getFrom());
this.m = m;
}
public TMessage getMessage() {
return m;
}
public TUser getUser() {
return m.getFrom();
}
}

View File

@ -0,0 +1,61 @@
package de.mrbesen.test;
import java.util.Random;
import java.util.Scanner;
import de.mrbesen.telegram.TelegramAPI;
import de.mrbesen.telegram.commands.CommandHandler;
import de.mrbesen.telegram.event.EventHandler;
import de.mrbesen.telegram.event.EventListener;
import de.mrbesen.telegram.event.events.UserSendMessageEvent;
import objects.TInlineKeyboardMarkup;
import objects.TUser;
import objects.TUser.Status;
public class Main implements CommandHandler, Runnable, EventListener {
TelegramAPI api;
public static void main(String[] args) {
new Main().run();
}
public Main() {
api = new TelegramAPI("577609137:AAGrlfMHAOQPzN6w9ceNSgFZZCbaiK4gAnw");
api.getCommandManager().registerCommand("test", this);
api.getEventManager().registerEvent(this);
}
@EventHandler
public void eventbla(UserSendMessageEvent e) {
e.getUser().sendMessage(e.getMessage().getText().replace(' ', '-'));
int i = new Random().nextInt(Status.values().length);
e.getUser().sendStatus(Status.values()[i]);
}
@Override
public void run() {
api.start();
Scanner s = new Scanner(System.in);
s.nextLine();
s.close();
api.stop();
System.out.println("Terminated.");
}
@Override
public boolean onCommand(TUser sender, String cmd, String[] args) {
if(cmd.equals("test")) {
// sender.sendMessage("Ja moin!");
sender.sendMessage("Links zu antippen:",
new TInlineKeyboardMarkup(2)
.addButton("gg","https://green-gaming.de", 1)
.addButton("ok", "https://oliver-kaestner.de", 1)
.addButton("mrB", "https://mrbesen.de", 2));
return true;
}
return false;
}
}

View File

@ -0,0 +1,70 @@
package objects;
import org.json.JSONObject;
public class JSONBased {
private JSONObject base_json = null;
public JSONBased(JSONObject o) {
base_json = o;
}
public boolean has(Member mem) {
if(base_json == null)
return false;
return base_json.has(mem.name());
}
public Object get(Member mem) {
if(base_json == null)
return null;
return base_json.get(mem.name());
}
public enum Member {
// ===== MESSAGE ====
forward_from_message_id,//int
forward_signature,//String
forward_date,//long
reply_to_message,//Message
edit_date,//long
media_group_id,//String
author_signature, //String
audio, //Audio
document, //Document
game, //Game
photo, //Array of PhotoSize
sticker, //Sticker
video, //Video
voice, //voice
video_note, //videoNote
caption, // String
contact, //Contact
location, //Location
venue, //Venue
new_chat_members, // Array of TUser
left_chat_members, // Array of TUser
new_chat_title, //String
new_chat_photo, //Array of Photosize
delete_chat_photo, // true
group_chat_created, // true
supergroup_chat_created, // true
channel_chat_created, //true
migrate_to_chat_id, // int
migrate_from_chat_id, // int
pinned_message, //TMessage
invoice, //Invoice
successful_payment, //SuccessfulPayment
connected_website, // String
//==== END MESSAGE ====
//==== AUDIO ======
performer, //String
title,//String
mime_type, // String
file_size; // int
//===== END AUDIO ====
}
}

12
src/objects/TAudio.java Normal file
View File

@ -0,0 +1,12 @@
package objects;
import org.json.JSONObject;
public class TAudio extends JSONBased {
private String file_id;
private int duration;
public TAudio(JSONObject o) {
super(o);
}
}

View File

@ -0,0 +1,36 @@
package objects;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONObject;
public class TInlineKeyboardMarkup implements TReplyMarkup {
ArrayList<JSONArray> arr_btn = new ArrayList<>();
public TInlineKeyboardMarkup(int rows) {
if(rows < 1)
throw new IllegalArgumentException("You need at least one row.");
arr_btn = new ArrayList<JSONArray>();
for( int row = 0; row < rows; row++ ) {
arr_btn.add(new JSONArray());
}
System.out.println("break here");
}
public TInlineKeyboardMarkup addButton(String title, String url, int row) {
arr_btn.get(row-1).put(new JSONObject().put("text", title).put("url", url));
return this;
}
@Override
public String toJSONString() {
JSONArray ja = new JSONArray(arr_btn);
JSONObject jo = new JSONObject();
jo.put("inline_keyboard", ja);
return jo.toString();
}
}

51
src/objects/TMessage.java Normal file
View File

@ -0,0 +1,51 @@
package objects;
import org.json.JSONObject;
import de.mrbesen.telegram.TelegramAPI;
public class TMessage extends JSONBased {
private int message_id;
private TUser from = null;//optional
private long date = -1;
private TUser forward_from = null; //optional
private String text = null;//optional
protected TelegramAPI api;
public void sendTo(TUser u) {
//if this message already exists forward, if not send directly.
}
public TMessage(JSONObject json, TelegramAPI api) {
super(json);
this.api = api;
message_id = json.getInt("message_id");
date = json.getLong("date");
if(json.has("from"))
from = api.getUser(json.getJSONObject("from"));
if(json.has("forward_from"))
forward_from = api.getUser(json.getJSONObject("forward_from"));
if(json.has("text") )
text = json.getString("text");
}
public TUser getFrom() {
return from;
}
public String getText() {
return text;
}
public long getDate() {
return date;
}
public TUser getForward_from() {
return forward_from;
}
}

View File

@ -0,0 +1,15 @@
package objects;
public interface TReplyMarkup {
public static enum RelayMarkup {
InlineKeyboardMarkup,
ReplyKeyboardMarkup,
ReplyKeyboardRemove,
ForceReply;
}
public String toJSONString();
}

119
src/objects/TUser.java Normal file
View File

@ -0,0 +1,119 @@
package objects;
import java.io.IOException;
import java.net.URLEncoder;
import org.json.JSONObject;
import de.mrbesen.telegram.TelegramAPI;
public class TUser {
private int id;
private String uname;//optional
private String firstname;
private String lastname;//optional
private String langcode; // optional
private boolean isBot = false;
private TelegramAPI api = null;
TUser(int chatid, String uname, TelegramAPI api) {
this.id = chatid;
this.uname = uname;
this.api = api;
}
public TUser(JSONObject o, TelegramAPI api) {
this.api = api;
firstname = o.getString("first_name");
isBot = o.getBoolean("is_bot");
id = o.getInt("id");
if(o.has("last_name"))
lastname = o.getString("last_name");
if(o.has("username"))
uname = o.getString("username");
if(o.has("language_code"))
langcode = o.getString("language_code");
}
public String getFirstName() {
return firstname;
}
public String getLastName() {
return lastname;
}
public String getLangcode() {
return langcode;
}
public boolean isBot() {
return isBot;
}
public int getID() {
return id;
}
public String getName() {
return uname;
}
public void sendHelpPage() {
sendMessage(api.getHelpMessage());
}
public void sendMessage(String text) {
if(api == null) {
System.err.println("api == null!");
return;
}
try {
api.request("sendMessage", "chat_id=" + id + "&text=" + URLEncoder.encode(text, "UTF-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessage(String text, TReplyMarkup rm) {
if(api == null) {
System.err.println("api == null!");
return;
}
try {
api.request("sendMessage", "chat_id=" + id
+ "&text=" + URLEncoder.encode(text, "UTF-8")
+ "&reply_markup=" + URLEncoder.encode(rm.toJSONString(), "UTF-8") );
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendStatus(Status status) {
try {
api.request("sendChatAction", "chat_id="+id+"&action=" + status.getAPIName());
} catch (Exception e) {
System.err.println("Failed to send status.");
}
}
public enum Status {
Typing,
Upload_Photo,
Record_Video,
Upload_Video,
Record_Audio,
Upload_Audio,
Upload_Document,
Find_Location,
Record_Video_Note,
Upload_Video_Note;
String getAPIName() {
return name().toLowerCase();
}
}
}