From 20ca1d9e0c1b7b8a4822742f120d6c576454d0d9 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 7 Jul 2016 15:42:16 +0300 Subject: reorganize project --- .../main/java/com/juick/api/TelegramBotHook.java | 243 +++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 juick-api/src/main/java/com/juick/api/TelegramBotHook.java (limited to 'juick-api/src/main/java/com/juick/api/TelegramBotHook.java') diff --git a/juick-api/src/main/java/com/juick/api/TelegramBotHook.java b/juick-api/src/main/java/com/juick/api/TelegramBotHook.java new file mode 100644 index 00000000..e1094ff6 --- /dev/null +++ b/juick-api/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> 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 users = getSubscribers(jmsg.getUser().getUID()); + List 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> 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() { + @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 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 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() { + @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 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 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; + } +} -- cgit v1.2.3