This repository has been archived on 2022-12-14. You can view files and clone it, but cannot push or open issues or pull requests.
geiserpbot/src/main/Geiserbot.java

478 lines
No EOL
17 KiB
Java

package main;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import elements.Chat;
import elements.Persistence;
import elements.exceptions.*;
import elements.messages.ChannelMessage;
import elements.messages.GroupMessage;
import elements.messages.Message;
import elements.messages.PrivateMessage;
import org.json.JSONArray;
import org.json.JSONObject;
import java.time.LocalDate;
import java.util.*;
/**
* Created by Guillermo Serrahima on 4/1/16.
*/
public class Geiserbot {
private static final String TOKEN = "267229954:AAHx49MXLmT1nT0QkccrSIzgmRVCQbjbJaQ";
private static final String USERNAME = "gserbot";
private static final String BASE_URL = "https://api.telegram.org/bot" + TOKEN;
private static final String PARSE_MARKDOWN = "Markdown";
private static final String PARSE_HTML = "HTML";
private static final int WARNING_COUNT_START = 0;
private static final int START_MESSAGE = WARNING_COUNT_START;
private static final int HELP_MESSAGE = START_MESSAGE + 1;
private static final int WARNING_UNKNOWN_ERROR = HELP_MESSAGE + 1;
private static final int WARNING_NO_USERNAME = WARNING_UNKNOWN_ERROR + 1;
private static final int WARNING_NOT_IMPLEMENTED = WARNING_NO_USERNAME + 1;
private static final int WARNING_NO_GROUP = WARNING_NOT_IMPLEMENTED + 1;
private static final int WARNING_COUNT_END = WARNING_NO_GROUP + 1;
//private List<String> commands;
private Map<Long, Chat> chats;
public Geiserbot() throws ReadErrorListException, ReadErrorChatException {
chats = Persistence.getInstance().readChats();
}
public String getUsername() {
return USERNAME;
}
public String getToken() {
return TOKEN;
}
public String myName() {
return "R. Geiser Pont";
}
//--- Http handling
public HttpResponse<JsonNode> sendMessage(Long chatId, String text) throws UnirestException {
System.out.println("Sending message: \n" + text + "\n");
return Unirest.post(BASE_URL + "/sendMessage")
.field("chat_id", chatId)
.field("text", text)
.asJson();
}
public HttpResponse<JsonNode> sendMessage(Long chatId, String text, String parseMode) throws UnirestException {
System.out.println("Sending message: \n" + text + "\n");
return Unirest.post(BASE_URL + "/sendMessage")
.field("chat_id", chatId)
.field("text", text)
.field("parse_mode", parseMode)
.asJson();
}
public HttpResponse<JsonNode> sendMessage(String channel, String text) throws UnirestException {
System.out.println("Sending message to " + channel + ": \n" + text + "\n");
return Unirest.post(BASE_URL + "/sendMessage")
.field("chat_id", channel)
.field("text", text)
.asJson();
}
public HttpResponse<JsonNode> sendMessage(String channel, String text, String parseMode) throws UnirestException {
System.out.println("Sending message to " + channel + ": \n" + text + "\n");
return Unirest.post(BASE_URL + "/sendMessage")
.field("chat_id", channel)
.field("text", text)
.field("parse_mode", parseMode)
.asJson();
}
public HttpResponse<JsonNode> replyMessage(Long chatId, Integer repliedMessage, String text) throws UnirestException {
System.out.println("Sending message: \n" + text + "\n");
return Unirest.post(BASE_URL + "/sendMessage")
.field("chat_id", chatId)
.field("text", text)
.field("reply_to_message_id", repliedMessage)
.asJson();
}
public HttpResponse<JsonNode> getUpdates(Integer offset) throws UnirestException {
return Unirest.post(BASE_URL + "/getUpdates")
.field("offset", offset)
.asJson();
}
public HttpResponse<JsonNode> getUpdates(Integer offset, Integer timeout) throws UnirestException {
return Unirest.post(BASE_URL + "/getUpdates")
.field("offset", offset)
.field("timeout", timeout)
.asJson();
}
//--- bot thinking
public void run() throws UnirestException {
int last_upd_id = 0;
HttpResponse<JsonNode> response;
System.out.println("Listening.\n");
while (true) {
response = getUpdates(last_upd_id++);
if (response.getStatus() == 200) {
JSONArray responses = response.getBody().getObject().getJSONArray("result");
if (responses.isNull(0)) continue;
else last_upd_id = responses.getJSONObject(responses.length() - 1).getInt("update_id") + 1;
for (int i = 0; i < responses.length(); i++) {
if(responses.getJSONObject(i).has("message")) {
JSONObject message = responses.getJSONObject(i).getJSONObject("message");
processMessage(message);
}
}
}
}
}
private void processMessage(JSONObject message) throws UnirestException {
//Process message into a nice and cozy java object
Message m = null;
try {
m = Message.getMessage(message);
} catch (MessageException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
//Console log
printLog(true, m);
//Actually read the message
handleInput(m);
}
private void printLog(boolean full_log, Message m) {
if (full_log) System.out.println("\n" + m);
else {
String log = "\nMessage";
if(m.isPrivate()) log += " received from a private chat";
else log += " received from chat " + m.getChatName();
log += " (chat id: " + m.getCid() + ")";
try {
log += " by user @" + m.getUsername();
} catch (NoUsernameMessageException e) {
log += " by user";
} catch (NoAuthorMessageException ignored) {}
try {
log += " named " + m.getAuthor();
} catch (NoAuthorMessageException ignored) {}
System.out.println(log + ".");
}
}
//--- Command handling
private void handleInput(Message m) throws UnirestException {
if (m.isChannel())
handleInputChannel((ChannelMessage) m);
else if (m.isGroup())
handleInputGroup((GroupMessage) m);
else if (m.isPrivate())
handleInputPrivate((PrivateMessage) m);
}
private boolean isCommand(String m, String command) {
return (m.startsWith(command) &&
(!m.substring(command.length()).startsWith("@") ||
m.substring(command.length()).startsWith("@" + USERNAME)));
}
private String removeCommandHead(String m, String command) {
String m2 = m.substring(command.length()).trim();
String uname = "@" + USERNAME;
if(m2.startsWith(uname)) m2 = m2.substring(uname.length());
return m2;
}
private void handleInputGroup(GroupMessage m) throws UnirestException {
try {
if (m.isEvent()) {
System.out.println("\nDetected group event.");
handleGroupEvent(m);
} else if (isCommand(m.getText(), "/start"))
handleStart(m.getCid());
else if (isCommand(m.getText(), "/help"))
handleHelp(m.getCid());
else if (isCommand(m.getText(), "/whoami"))
handleWhoami(m);
else if (isCommand(m.getText(), "/list"))
handleList(m);
else if (isCommand(m.getText(), "/foldl")) {
if(removeCommandHead(m.getText(), "/foldl").startsWith("-v"))
explainFoldHaskellVerbose(m.getCid());
else explainFoldHaskell(m.getCid());
}
else if (isCommand(m.getText(), "/foldr")) {
if(removeCommandHead(m.getText(), "/foldr").startsWith("-v"))
explainFoldHaskellVerbose(m.getCid());
else explainFoldHaskell(m.getCid());
}
} catch (NoTextMessageException ignored) {}
}
private void handleInputPrivate(PrivateMessage m) throws UnirestException {
try {
if (isCommand(m.getText(), "/start"))
handleStart(m.getCid());
else if (isCommand(m.getText(), "/help"))
handleHelp(m.getCid());
else if (isCommand(m.getText(), "/whoami"))
handleWhoami(m);
else if (isCommand(m.getText(), "/list"))
handleList(m);
else if (isCommand(m.getText(), "/foldl")) {
if(removeCommandHead(m.getText(), "/foldl").startsWith("-v"))
explainFoldHaskellVerbose(m.getCid());
else explainFoldHaskell(m.getCid());
}
else if (isCommand(m.getText(), "/foldr")) {
if(removeCommandHead(m.getText(), "/foldr").startsWith("-v"))
explainFoldHaskellVerbose(m.getCid());
else explainFoldHaskell(m.getCid());
}
} catch (NoTextMessageException ignored) {}
}
private void handleInputChannel(ChannelMessage m) throws UnirestException {
}
private void handleStart(long chat_id) throws UnirestException {
sendMessage(chat_id, "Hola. Soy el bot personal de Guillermo Serrahima.");
return;
}
private void handleHelp(long chat_id) throws UnirestException {
String help = "Aquí tienes una lista de comandos que acepto:\n\n" +
"/start - Repite el saludo inicial\n" +
"/help - Saca esta lista\n" +
"/whoami - Muestra información visible sobre ti mismo\n" +
"/list [nombre de la lista] - Permite crear, mostrar o " +
"modificar una lista\n";
sendMessage(chat_id, help.trim());
sendMessage(chat_id, "_" + myName() + " v1.0.0_", PARSE_MARKDOWN);
}
private void handleWhoami(Message m) throws UnirestException {
String s = "Estamos en";
if(m.isPrivate()) s += " un chat privado";
else s += " el chat " + m.getChatName();
s += " de ID " + m.getCid() + ".\n";
try {
s += "Eres " + m.getAuthor() + ", con";
try {
s += " nombre de usuario @" + m.getUsername() +" e";
} catch (NoUsernameMessageException ignored) {}
s += " ID de usuario " + m.getUid() + ".\n";
} catch (NoAuthorMessageException ignored) {}
s += "En el PC que me mantiene, la fecha actual es " + LocalDate.now() +
" en el formato ISO-8601.\n";
s+= "Tu mensaje tiene hora de " + m.getTimestamp() + "\n";
replyMessage(m.getCid(), m.getMid(), s.trim());
}
private void handleGroupEvent(GroupMessage m) throws NoTextMessageException, UnirestException {
System.out.print("Bot @" + USERNAME + " detects event: ");
if(m.userJoined()) {
System.out.println("JOINING");
System.out.println("New chat participant: " + m.getText());
if(m.getText().equals("@" + USERNAME)) handleStart(m.getCid());
}
else if(m.userLeft()) {
System.out.println("LEAVING");
System.out.println("Leaving chat participant: " + m.getText());
}
else if(m.chatNameChanged()) {
System.out.println("CHANGING CHAT NAME");
System.out.println("New chat name: " + m.getText());
try {
chats.get(m.getCid()).setName(m.getText());
saveChatIndex();
} catch (SaveErrorChatException e) {
sendMessage(m.getCid(), "Ha habido un error guardando el nuevo nombre de este chat.");
}
}
else {
System.out.println("UNKNOWN");
}
}
private void handleList(GroupMessage m) throws UnirestException, NoTextMessageException {
String[] reading = m.getText().split(" ", 2);
if (reading.length < 2) {
sendMessage(m.getCid(), "Formato incorrecto. " +
"Debes poner un espacio entre el comando /list y el nombre de la lista.");
return;
}
String list = reading[1];
if(!exists(m.getCid())) {
try {
chats.put(m.getCid(), new Chat(m.getChatName(), m.getCid()));
saveChatIndex();
} catch (SaveErrorChatException e) {
sendMessage(m.getCid(), "Ha habido un error guardando los datos de este chat.");
return;
}
}
if(!exists(m.getCid(), list)) {
try {
chats.get(m.getCid()).add(list);
saveChat(m.getCid());
} catch (SaveErrorChatException e) {
sendMessage(m.getCid(), "Ha habido un error creando la lista.");
return;
}
}
sendMessage(m.getCid(), getWarning(WARNING_NOT_IMPLEMENTED));
}
private void handleList(PrivateMessage m) throws UnirestException, NoTextMessageException {
String[] reading = m.getText().split(" ", 2);
if(reading.length < 2) {
sendMessage(m.getCid(), "Formato incorrecto. " +
"Debes poner un espacio entre el comando /list y el nombre de la lista.");
return;
}
String list = reading[1];
if(!exists(m.getCid())) {
try {
chats.put(m.getCid(), new Chat(m.getChatName(), m.getCid()));
saveChatIndex();
} catch (SaveErrorChatException e) {
sendMessage(m.getCid(), "Ha habido un error guardando los datos de este chat.");
return;
}
}
if(!exists(m.getCid(), list)) {
try {
chats.get(m.getCid()).add(list);
saveChat(m.getCid());
} catch (SaveErrorChatException e) {
sendMessage(m.getCid(), "Ha habido un error creando la lista.");
return;
}
}
sendMessage(m.getCid(), getWarning(WARNING_NOT_IMPLEMENTED));
}
private void explainFoldHaskell(long chat_id) throws UnirestException {
String fold = "The recursion for `foldr f x ys` where `ys = [y1,y2,...,yk]` looks like\n" +
"\n" +
"`f y1 (f y2 (... (f yk x) ...))`\n" +
"\n" +
"whereas the recursion for `foldl f x ys` looks like\n" +
"\n" +
"`f (... (f (f x y1) y2) ...) yk`";
sendMessage(chat_id, fold, PARSE_MARKDOWN);
}
private void explainFoldHaskellVerbose(long chat_id) throws UnirestException {
String fold = "The recursion for `foldr f x ys` where `ys = [y1,y2,...,yk]` looks like\n" +
"\n" +
"`f y1 (f y2 (... (f yk x) ...))`\n" +
"\n" +
"whereas the recursion for `foldl f x ys` looks like\n" +
"\n" +
"`f (... (f (f x y1) y2) ...) yk`\n" +
"\n" +
"An important difference here is that if the result of `f x y` can be computed using only the value of `x`, then `foldr` doesn't need to examine the entire list. For example:\n" +
"\n" +
"`foldr (&&) False (repeat False)`\n" +
"returns `False` whereas\n" +
"`foldl (&&) False (repeat False)`\n" +
"never terminates. (Note: `repeat False` creates an infinite list where every element is `False`.)\n" +
"\n" +
"On the other hand, `foldl'` is tail recursive and strict. If you know that you'll have to traverse the whole list no matter what (e.g., summing the numbers in a list), then `foldl'` is more space- (and probably time-) efficient than `foldr`.";
sendMessage(chat_id, fold, PARSE_MARKDOWN);
}
private boolean exists(long chat_id) {
return chats.containsKey(chat_id);
}
private boolean exists(long chat_id, String list) {
return chats.containsKey(chat_id) && chats.get(chat_id).exists(list);
}
private void saveChat(long chat_id) throws SaveErrorChatException {
Persistence.getInstance().saveChat(chats.get(chat_id));
}
private void saveChatIndex() throws SaveErrorChatException {
Persistence.getInstance().saveChatIndex(chats);
}
private String getWarning(int warning_id) {
switch (warning_id) {
case WARNING_UNKNOWN_ERROR:
return "Algo ha ido MUY mal.";
case WARNING_NOT_IMPLEMENTED:
return "Aún no está implementado.";
case WARNING_NO_GROUP:
return "Debes estar en un grupo para poder hacer eso.";
case WARNING_NO_USERNAME:
return "No tienes nombre de usuario. Regístrate con uno en la " +
"configuración de Telegram para poder utilizarme.";
default: return "Entrada incorrecta.";
}
}
private String getFormatExample(int command) {
return "Entrada incorrecta.";
}
}