aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/juick/api/TelegramBotHook.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/juick/api/TelegramBotHook.java')
-rw-r--r--src/main/java/com/juick/api/TelegramBotHook.java243
1 files changed, 243 insertions, 0 deletions
diff --git a/src/main/java/com/juick/api/TelegramBotHook.java b/src/main/java/com/juick/api/TelegramBotHook.java
new file mode 100644
index 00000000..e1094ff6
--- /dev/null
+++ b/src/main/java/com/juick/api/TelegramBotHook.java
@@ -0,0 +1,243 @@
+package com.juick.api;
+
+import com.juick.User;
+import com.juick.json.MessageSerializer;
+import com.juick.server.MessagesQueries;
+import com.juick.server.UserQueries;
+import com.neovisionaries.ws.client.*;
+import com.pengrad.telegrambot.BotUtils;
+import com.pengrad.telegrambot.Callback;
+import com.pengrad.telegrambot.TelegramBot;
+import com.pengrad.telegrambot.TelegramBotAdapter;
+import com.pengrad.telegrambot.model.Message;
+import com.pengrad.telegrambot.model.request.InlineKeyboardButton;
+import com.pengrad.telegrambot.model.request.InlineKeyboardMarkup;
+import com.pengrad.telegrambot.request.SendMessage;
+import com.pengrad.telegrambot.response.SendResponse;
+import org.json.JSONObject;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Created by vt on 12/05/16.
+ */
+public class TelegramBotHook {
+ private static final Logger logger = Logger.getLogger(TelegramBotHook.class.getName());
+
+ TelegramBot bot;
+ WebSocket ws, wsReply;
+ MessageSerializer ms = new MessageSerializer();
+ JdbcTemplate jdbc;
+
+
+ public TelegramBotHook(JdbcTemplate jdbc, String token) {
+ this.jdbc = jdbc;
+ bot = TelegramBotAdapter.build(token);
+ bot.setWebhook("https://api.juick.com/tlgmbtwbhk");
+ try {
+ ws = new WebSocketFactory().createSocket("wss://ws.juick.com/_all");
+ ws.addHeader("Origin", "ws.juick.com");
+ ws.addHeader("Host", "ws.juick.com"); //TODO: remove from server
+ ws.setPingInterval(60 * 1000);
+ ws.addListener(new WebSocketAdapter() {
+ @Override
+ public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer) throws Exception {
+ logger.info("ws disconnected");
+ ws.connect();
+ }
+
+ @Override
+ public void onConnected(WebSocket websocket, Map<String, List<String>> headers) {
+ logger.info("ws connected");
+ }
+
+ @Override
+ public void onTextMessage(WebSocket websocket, String text) throws Exception {
+ super.onTextMessage(websocket, text);
+ com.juick.Message jmsg = ms.deserialize(new JSONObject(text));
+ logger.info("got jmsg: " + ms.serialize(jmsg).toString());
+ StringBuilder sb = new StringBuilder();
+ sb.append("@").append(jmsg.getUser().getUName()).append(":\n")
+ .append(jmsg.getTagsString()).append("\n").append(jmsg.getText()).append("\n");
+ if (jmsg.Photo != null) {
+ sb.append(jmsg.Photo);
+ }
+ String msg = sb.toString();
+ List<Long> users = getSubscribers(jmsg.getUser().getUID());
+ List<Long> chats = getChats();
+ // registered subscribed users
+ String msgUrl = "https://juick.com/" + jmsg.getMID();
+ users.stream().forEach(c -> telegramNotify(c, msg, msgUrl));
+ // anonymous
+ chats.stream().filter(u -> getUser(u) == 0).forEach(c -> telegramNotify(c, msg, msgUrl));
+ }
+ });
+ ws.connect();
+ wsReply = new WebSocketFactory().createSocket("wss://ws.juick.com/_replies");
+ wsReply.addHeader("Origin", "ws.juick.com");
+ wsReply.addHeader("Host", "ws.juick.com");
+ wsReply.setPingInterval(60 * 1000);
+ wsReply.addListener(new WebSocketAdapter() {
+ @Override
+ public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer) throws Exception {
+ logger.info("ws replies disconnected");
+ ws.connect();
+ }
+
+ @Override
+ public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
+ logger.info("ws replies connected");
+ }
+
+ @Override
+ public void onTextMessage(WebSocket websocket, String text) throws Exception {
+ com.juick.Message jmsg = ms.deserialize(new JSONObject(text));
+ logger.info(String.format("got jmsg: %s", ms.serialize(jmsg).toString()));
+ StringBuilder sb = new StringBuilder();
+ sb.append("Reply by @").append(jmsg.getUser().getUName()).append(":\n")
+ .append(getReplyQuote(jmsg.getMID(), jmsg.ReplyTo)).append("\n").append(jmsg.getText());
+ if (jmsg.getAttachmentURL() != null) {
+ sb.append("\n").append(jmsg.getAttachmentURL());
+ }
+ String msg = sb.toString();
+ String msgUrl = String.format("https://juick.com/%d#%d", jmsg.getMID(), jmsg.getRID());
+ getSubscribersToComments(jmsg.getMID(), jmsg.getUser().getUID()).stream()
+ .forEach(c -> telegramNotify(c, msg, msgUrl));
+ }
+ });
+ wsReply.connect();
+ } catch (IOException | WebSocketException e) {
+ logger.log(Level.SEVERE, "couldn't create ws connection", e);
+ }
+ }
+
+ private void telegramNotify(Long c, String msg, String msgUrl) {
+ bot.execute(new SendMessage(c, msg).replyMarkup(
+ new InlineKeyboardMarkup(
+ new InlineKeyboardButton[]{
+ new InlineKeyboardButton("See on Juick").url(msgUrl)
+ }
+ )), new Callback<SendMessage, SendResponse>() {
+ @Override
+ public void onResponse(SendMessage request, SendResponse response) {
+ logger.info("got response: " + response.message().toString());
+ }
+
+ @Override
+ public void onFailure(SendMessage request, IOException e) {
+ logger.log(Level.WARNING, "telegram failure", e);
+ }
+ });
+ }
+
+ List<Long> getChats() {
+ return jdbc.queryForList("SELECT chat_id FROM telegram_chats", Long.class);
+ }
+
+ void addChat(Long id) {
+ jdbc.update("INSERT IGNORE INTO telegram_chats(chat_id) VALUES(?)", id);
+ }
+
+ public void doPost(HttpServletRequest request) throws IOException {
+ try (BufferedReader reader = request.getReader()) {
+ Message message = BotUtils.parseUpdate(reader).message();
+ User user_from = UserQueries.getUserByUID(jdbc, getUser(message.chat().id())).orElse(new User());
+ logger.info(String.format("got telegram msg %s from juick user %d", message.toString(), user_from.getUID()));
+ List<Long> chats = getChats();
+ String username = message.from().username();
+ if (username == null) {
+ username = message.from().firstName();
+ }
+ if (!chats.contains(message.chat().id())) {
+ addChat(message.chat().id());
+ logger.info("added chat with " + username);
+ createTelegramUser(message.from().id(), username);
+ telegramSignupNotify(message.from().id().longValue(), UserQueries.getSignUpHashByTelegramID(jdbc, message.from().id().longValue(), username));
+ } else {
+ if (user_from.getUID() == 0) {
+ telegramSignupNotify(message.from().id().longValue(), UserQueries.getSignUpHashByTelegramID(jdbc, message.from().id().longValue(), username));
+ } else if (message.text().equalsIgnoreCase("/login")) {
+ String msg = String.format("Hi, %s!\nTap to log in", user_from.getUName());
+ String msgUrl = "http://juick.com/login?" + UserQueries.getHashByUID(jdbc, user_from.getUID());
+ telegramNotify(message.from().id().longValue(), msg, msgUrl);
+ }
+ }
+ }
+ }
+
+ private void telegramSignupNotify(Long telegramId, String hash) {
+ bot.execute(new SendMessage(telegramId,
+ "You are subscribed to all Juick messages. " +
+ "Create or link an existing Juick account to control " +
+ "what do you want to receive").replyMarkup(
+ new InlineKeyboardMarkup(
+ new InlineKeyboardButton[]{
+ new InlineKeyboardButton("SIGNUP").url("http://juick.com/signup?type=durov&hash=" +
+ hash)
+ })), new Callback<SendMessage, SendResponse>() {
+ @Override
+ public void onResponse(SendMessage request, SendResponse response) {
+ logger.info("got response: " + response.message().toString());
+ }
+
+ @Override
+ public void onFailure(SendMessage request, IOException e) {
+ logger.log(Level.WARNING, "telegram failure", e);
+ }
+ });
+ }
+
+ private boolean createTelegramUser(long tgID, String tgName) {
+ return jdbc.update("INSERT INTO telegram(tg_id, tg_name, loginhash) VALUES(?,?,?)",
+ tgID, tgName, UUID.randomUUID().toString()) > 0;
+ }
+
+ private int getUser(long tgId) {
+ try {
+ return jdbc.queryForObject("SELECT id FROM users INNER JOIN telegram " +
+ "ON telegram.user_id = users.id WHERE telegram.tg_id=?", Integer.class, tgId);
+ } catch (EmptyResultDataAccessException e) {
+ return 0;
+ }
+ }
+
+ private List<Long> getSubscribers(int uid) {
+ return jdbc.queryForList("SELECT tg_id FROM telegram INNER JOIN subscr_users " +
+ "ON (subscr_users.user_id=? AND telegram.user_id=subscr_users.suser_id)", Long.class, uid);
+ }
+
+ private List<Long> getSubscribersToComments(int mid, int ignore_uid) {
+ return jdbc.queryForList("SELECT tg_id FROM telegram INNER JOIN subscr_messages " +
+ "ON (telegram.user_id=subscr_messages.suser_id) WHERE message_id=? AND suser_id!=?", Long.class, mid, ignore_uid);
+ }
+
+ private String getReplyQuote(int MID, int ReplyTo) {
+ String quote = "";
+ if (ReplyTo > 0) {
+ com.juick.Message q = MessagesQueries.getReply(jdbc, MID, ReplyTo);
+ if (q != null) {
+ quote = q.getText();
+ }
+ } else {
+ com.juick.Message q = MessagesQueries.getMessage(jdbc, MID);
+ if (q != null) {
+ quote = q.getText();
+ }
+ }
+ if (quote.length() > 50) {
+ quote = ">" + quote.substring(0, 47).replace('\n', ' ') + "...\n";
+ } else if (quote.length() > 0) {
+ quote = ">" + quote.replace('\n', ' ') + "\n";
+ }
+ return quote;
+ }
+}