
org.riversun.xternal.simpleslackapi.impl.SlackWebSocketSessionImpl Maven / Gradle / Ivy
The newest version!
package org.riversun.xternal.simpleslackapi.impl;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.message.BasicNameValuePair;
import org.riversun.xternal.log.Logger;
import org.riversun.xternal.log.LoggerFactory;
import org.riversun.xternal.simpleslackapi.*;
import org.riversun.xternal.simpleslackapi.SlackChatConfiguration.Avatar;
import org.riversun.xternal.simpleslackapi.events.*;
import org.riversun.xternal.simpleslackapi.listeners.PresenceChangeListener;
import org.riversun.xternal.simpleslackapi.listeners.SlackChannelArchivedListener;
import org.riversun.xternal.simpleslackapi.listeners.SlackChannelCreatedListener;
import org.riversun.xternal.simpleslackapi.listeners.SlackChannelDeletedListener;
import org.riversun.xternal.simpleslackapi.listeners.SlackChannelRenamedListener;
import org.riversun.xternal.simpleslackapi.listeners.SlackChannelUnarchivedListener;
import org.riversun.xternal.simpleslackapi.listeners.SlackEventListener;
import org.riversun.xternal.simpleslackapi.listeners.SlackTeamJoinListener;
import org.riversun.xternal.simpleslackapi.listeners.SlackUserChangeListener;
import org.riversun.xternal.simpleslackapi.replies.*;
import org.riversun.xternal.simpleslackapi.utils.ReaderUtils;
import javax.websocket.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.ConnectException;
import java.net.Proxy;
import java.net.URI;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
class SlackWebSocketSessionImpl extends AbstractSlackSessionImpl implements SlackSession, MessageHandler.Whole {
private static final String SLACK_API_SCHEME = "https";
private static final String SLACK_API_HOST = "slack.com";
private static final String SLACK_API_PATH = "/api";
private static final String SLACK_API_HTTPS_ROOT = SLACK_API_SCHEME + "://" + SLACK_API_HOST + SLACK_API_PATH + "/";
private static final String DIRECT_MESSAGE_OPEN_CHANNEL_COMMAND = "im.open";
private static final String MULTIPARTY_DIRECT_MESSAGE_OPEN_CHANNEL_COMMAND = "mpim.open";
private static final String CHANNELS_LEAVE_COMMAND = "channels.leave";
private static final String CHANNELS_JOIN_COMMAND = "channels.join";
private static final String CHANNELS_SET_TOPIC_COMMAND = "channels.setTopic";
private static final String CHANNELS_INVITE_COMMAND = "channels.invite";
private static final String CHANNELS_ARCHIVE_COMMAND = "channels.archive";
private static final String CHANNELS_UNARCHIVE_COMMAND = "channels.unarchive";
private static final String CHAT_POST_MESSAGE_COMMAND = "chat.postMessage";
private static final String FILE_UPLOAD_COMMAND = "files.upload";
private static final String CHAT_DELETE_COMMAND = "chat.delete";
private static final String CHAT_UPDATE_COMMAND = "chat.update";
private static final String REACTIONS_ADD_COMMAND = "reactions.add";
private static final String REACTIONS_REMOVE_COMMAND = "reactions.remove";
private static final String INVITE_USER_COMMAND = "users.admin.invite";
private static final String SET_PERSONA_ACTIVE = "users.setPresence";
private static final String LIST_EMOJI_COMMAND = "emoji.list";
private static final String LIST_USERS = "users.list";
private static final Logger LOGGER = LoggerFactory.getLogger(SlackWebSocketSessionImpl.class);
private static final String SLACK_HTTPS_AUTH_URL = "https://slack.com/api/rtm.start?token=";
private static final int DEFAULT_HEARTBEAT_IN_MILLIS = 30000;
private volatile Session websocketSession;
private String authToken;
private String proxyAddress;
private int proxyPort = -1;
HttpHost proxyHost;
private volatile long lastPingSent;
private volatile long lastPingAck;
private AtomicLong messageId = new AtomicLong();
private final boolean reconnectOnDisconnection;
private volatile boolean wantDisconnect;
private Thread connectionMonitoringThread;
private EventDispatcher dispatcher = new EventDispatcher();
private final long heartbeat;
private WebSocketContainerProvider webSocketContainerProvider;
private volatile String webSocketConnectionURL;
@Override
public SlackMessageHandle sendMessageToUser(SlackUser user, SlackPreparedMessage message) {
SlackChannel iMChannel = getIMChannelForUser(user);
return sendMessage(iMChannel, message);
}
@Override
public SlackMessageHandle sendMessageToUser(SlackUser user, String message, SlackAttachment attachment) {
SlackChannel iMChannel = getIMChannelForUser(user);
return sendMessage(iMChannel, message, attachment, DEFAULT_CONFIGURATION);
}
@Override
public SlackMessageHandle sendMessageToUser(String userName, String message, SlackAttachment attachment) {
return sendMessageToUser(findUserByUserName(userName), message, attachment);
}
private List getAllIMChannels() {
Collection allChannels = getChannels();
List iMChannels = new ArrayList<>();
for (SlackChannel channel : allChannels) {
if (channel.isDirect()) {
iMChannels.add(channel);
}
}
return iMChannels;
}
private SlackChannel getIMChannelForUser(SlackUser user) {
List imcs = getAllIMChannels();
for (SlackChannel channel : imcs) {
if (channel.getMembers().contains(user)) {
return channel;
}
}
SlackMessageHandle reply = openDirectMessageChannel(user);
return reply.getReply().getSlackChannel();
}
public class EventDispatcher {
void dispatch(SlackEvent event, String rawMessage) {
switch (event.getEventType()) {
case SLACK_CHANNEL_ARCHIVED:
dispatchImpl((SlackChannelArchived) event, channelArchiveListener);
break;
case SLACK_CHANNEL_CREATED:
dispatchImpl((SlackChannelCreated) event, channelCreateListener);
break;
case SLACK_CHANNEL_DELETED:
dispatchImpl((SlackChannelDeleted) event, channelDeleteListener);
break;
case SLACK_CHANNEL_RENAMED:
dispatchImpl((SlackChannelRenamed) event, channelRenamedListener);
break;
case SLACK_CHANNEL_UNARCHIVED:
dispatchImpl((SlackChannelUnarchived) event, channelUnarchiveListener);
break;
case SLACK_CHANNEL_JOINED:
dispatchImpl((SlackChannelJoined) event, channelJoinedListener);
break;
case SLACK_CHANNEL_LEFT:
dispatchImpl((SlackChannelLeft) event, channelLeftListener);
break;
case SLACK_GROUP_JOINED:
dispatchImpl((SlackGroupJoined) event, groupJoinedListener);
break;
case SLACK_MESSAGE_DELETED:
dispatchImpl((SlackMessageDeleted) event, messageDeletedListener);
break;
case SLACK_MESSAGE_POSTED:
dispatchImpl((SlackMessagePosted) event, messagePostedListener);
break;
case SLACK_MESSAGE_UPDATED:
dispatchImpl((SlackMessageUpdated) event, messageUpdatedListener);
break;
case SLACK_CONNECTED:
dispatchImpl((SlackConnected) event, slackConnectedListener);
break;
case REACTION_ADDED:
dispatchImpl((ReactionAdded) event, reactionAddedListener);
break;
case REACTION_REMOVED:
dispatchImpl((ReactionRemoved) event, reactionRemovedListener);
break;
case SLACK_USER_CHANGE:
dispatchImpl((SlackUserChange) event, slackUserChangeListener);
break;
case SLACK_TEAM_JOIN:
dispatchImpl((SlackTeamJoin) event, slackTeamJoinListener);
break;
case PIN_ADDED:
dispatchImpl((PinAdded) event, pinAddedListener);
break;
case PIN_REMOVED:
dispatchImpl((PinRemoved) event, pinRemovedListener);
break;
case PRESENCE_CHANGE:
dispatchImpl((PresenceChange) event, presenceChangeListener);
break;
case SLACK_DISCONNECTED:
dispatchImpl((SlackDisconnected) event, slackDisconnectedListener);
break;
case USER_TYPING:
dispatchImpl((UserTyping) event, userTypingListener);
break;
case UNKNOWN:
LOGGER.warn("event of type " + event.getEventType() + " not handled: " + event + " raw message:" + rawMessage);
}
}
private > void dispatchImpl(E event, List listeners) {
for (L listener : listeners) {
try {
listener.onEvent(event, SlackWebSocketSessionImpl.this);
} catch (Throwable thr) {
LOGGER.error("caught exception in dispatchImpl", thr);
}
}
}
}
SlackWebSocketSessionImpl(WebSocketContainerProvider webSocketContainerProvider, String authToken, boolean reconnectOnDisconnection, long heartbeat,
TimeUnit unit) {
this.authToken = authToken;
this.reconnectOnDisconnection = reconnectOnDisconnection;
this.heartbeat = heartbeat != 0 ? unit.toMillis(heartbeat) : 30000;
this.webSocketContainerProvider = webSocketContainerProvider != null ? webSocketContainerProvider : new DefaultWebSocketContainerProvider(null, 0);
addInternalListeners();
}
SlackWebSocketSessionImpl(WebSocketContainerProvider webSocketContainerProvider, String authToken, Proxy.Type proxyType, String proxyAddress, int proxyPort,
boolean reconnectOnDisconnection, long heartbeat, TimeUnit unit) {
this.authToken = authToken;
this.proxyAddress = proxyAddress;
this.proxyPort = proxyPort;
this.proxyHost = new HttpHost(proxyAddress, proxyPort);
this.reconnectOnDisconnection = reconnectOnDisconnection;
this.heartbeat = heartbeat != 0 ? unit.toMillis(heartbeat) : DEFAULT_HEARTBEAT_IN_MILLIS;
this.webSocketContainerProvider = webSocketContainerProvider != null ? webSocketContainerProvider
: new DefaultWebSocketContainerProvider(proxyAddress, proxyPort);
addInternalListeners();
}
private void addInternalListeners() {
addPresenceChangeListener(INTERNAL_PRESENCE_CHANGE_LISTENER);
addChannelArchivedListener(INTERNAL_CHANNEL_ARCHIVE_LISTENER);
addChannelCreatedListener(INTERNAL_CHANNEL_CREATED_LISTENER);
addChannelDeletedListener(INTERNAL_CHANNEL_DELETED_LISTENER);
addChannelRenamedListener(INTERNAL_CHANNEL_RENAMED_LISTENER);
addChannelUnarchivedListener(INTERNAL_CHANNEL_UNARCHIVED_LISTENER);
addSlackTeamJoinListener(INTERNAL_TEAM_JOIN_LISTENER);
addSlackUserChangeListener(INTERNAL_USER_CHANGE_LISTENER);
}
@Override
public void connect() throws IOException {
wantDisconnect = false;
connectImpl();
LOGGER.debug("starting actions monitoring");
startConnectionMonitoring();
}
@Override
public void disconnect() {
wantDisconnect = true;
LOGGER.debug("Disconnecting from the Slack server");
disconnectImpl();
stopConnectionMonitoring();
}
@Override
public boolean isConnected() {
return websocketSession != null && websocketSession.isOpen();
}
private void connectImpl() throws IOException {
LOGGER.info("connecting to slack");
HttpClient httpClient = getHttpClient();
String extra = "&batch_presence_aware=true&presence_sub=true";
HttpGet request = new HttpGet(SLACK_HTTPS_AUTH_URL + authToken + extra);
HttpResponse response;
response = httpClient.execute(request);
LOGGER.debug(response.getStatusLine().toString());
String jsonResponse = consumeToString(response.getEntity().getContent());
SlackJSONSessionStatusParser sessionParser = new SlackJSONSessionStatusParser(jsonResponse);
sessionParser.parse();
if (sessionParser.getError() != null) {
LOGGER.error("Error during authentication : " + sessionParser.getError());
throw new ConnectException(sessionParser.getError());
}
users = sessionParser.getUsers();
integrations = sessionParser.getIntegrations();
channels = sessionParser.getChannels();
sessionPersona = sessionParser.getSessionPersona();
team = sessionParser.getTeam();
LOGGER.info("Team " + team.getId() + " : " + team.getName());
LOGGER.info("Self " + sessionPersona.getId() + " : " + sessionPersona.getUserName());
LOGGER.info(users.size() + " users found on this session");
LOGGER.info(channels.size() + " channels found on this session");
webSocketConnectionURL = sessionParser.getWebSocketURL();
LOGGER.debug("retrieved websocket URL : " + webSocketConnectionURL);
establishWebsocketConnection();
}
private void establishWebsocketConnection() throws IOException {
lastPingSent = 0;
lastPingAck = 0;
WebSocketContainer client = webSocketContainerProvider.getWebSocketContainer();
final MessageHandler handler = this;
LOGGER.debug("initiating actions to websocket");
try {
websocketSession = client.connectToServer(new Endpoint() {
@Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(handler);
}
@Override
public void onError(Session session, Throwable thr) {
LOGGER.error("Endpoint#onError called", thr);
websocketSession = null;
}
}, URI.create(webSocketConnectionURL));
} catch (DeploymentException e) {
LOGGER.error(e.toString());
throw new IOException(e);
}
if (websocketSession != null) {
SlackConnectedImpl slackConnectedImpl = new SlackConnectedImpl(sessionPersona);
dispatcher.dispatch(slackConnectedImpl, null);
LOGGER.debug("websocket actions established");
LOGGER.info("slack session ready");
} else {
throw new IOException("Unable to establish a connection to this websocket URL " + webSocketConnectionURL);
}
}
private String consumeToString(InputStream content) throws IOException {
Reader reader = new InputStreamReader(content, "UTF-8");
StringBuffer buf = new StringBuffer();
char data[] = new char[16384];
int numread;
while (0 <= (numread = reader.read(data)))
buf.append(data, 0, numread);
return buf.toString();
}
private void disconnectImpl() {
if (websocketSession != null) {
try {
websocketSession.close();
} catch (IOException ex) {
// ignored.
} finally {
SlackDisconnectedImpl slackDisconnected = new SlackDisconnectedImpl(sessionPersona);
dispatcher.dispatch(slackDisconnected, null);
websocketSession = null;
}
}
}
private void startConnectionMonitoring() {
connectionMonitoringThread = new Thread() {
@Override
public void run() {
LOGGER.debug("monitoring thread started");
while (true) {
try {
Thread.sleep(heartbeat);
// disconnect() was called.
if (wantDisconnect) {
this.interrupt();
}
if (lastPingSent != lastPingAck || websocketSession == null) {
// disconnection happened
LOGGER.warn("Connection lost...");
try {
if (websocketSession != null) {
websocketSession.close();
}
} catch (IOException e) {
LOGGER.error("exception while trying to close the websocket ", e);
}
websocketSession = null;
if (reconnectOnDisconnection) {
establishWebsocketConnection();
} else {
this.interrupt();
}
} else {
lastPingSent = getNextMessageId();
LOGGER.debug("sending ping " + lastPingSent);
try {
if (websocketSession.isOpen()) {
websocketSession.getBasicRemote().sendText("{\"type\":\"ping\",\"id\":" + lastPingSent + "}");
} else if (reconnectOnDisconnection) {
establishWebsocketConnection();
}
} catch (IllegalStateException e) {
LOGGER.warn("exception caught while using websocket ", e);
// websocketSession might be closed in this case
if (reconnectOnDisconnection) {
establishWebsocketConnection();
}
}
}
} catch (InterruptedException e) {
LOGGER.info("monitoring thread interrupted");
break;
} catch (IOException e) {
LOGGER.error("unexpected exception on monitoring thread ", e);
}
}
LOGGER.debug("monitoring thread stopped");
}
};
if (!wantDisconnect) {
connectionMonitoringThread.start();
}
}
private void stopConnectionMonitoring() {
if (connectionMonitoringThread != null) {
while (true) {
try {
connectionMonitoringThread.interrupt();
connectionMonitoringThread.join();
break;
} catch (InterruptedException ex) {
// ouch - let's try again!
}
}
}
}
@Override
public SlackMessageHandle sendMessage(SlackChannel channel, SlackPreparedMessage preparedMessage,
SlackChatConfiguration chatConfiguration) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("channel", channel.getId());
arguments.put("text", preparedMessage.getMessage());
if (chatConfiguration.isAsUser()) {
arguments.put("as_user", "true");
}
if (chatConfiguration.getAvatar() == Avatar.ICON_URL) {
arguments.put("icon_url", chatConfiguration.getAvatarDescription());
}
if (chatConfiguration.getAvatar() == Avatar.EMOJI) {
arguments.put("icon_emoji", chatConfiguration.getAvatarDescription());
}
if (chatConfiguration.getUserName() != null) {
arguments.put("username", chatConfiguration.getUserName());
}
if (preparedMessage.getAttachments() != null && preparedMessage.getAttachments().length > 0) {
arguments.put("attachments", SlackJSONAttachmentFormatter
.encodeAttachments(preparedMessage.getAttachments()).toString());
}
if (!preparedMessage.isUnfurl()) {
arguments.put("unfurl_links", "false");
arguments.put("unfurl_media", "false");
}
if (preparedMessage.isLinkNames()) {
arguments.put("link_names", "1");
}
postSlackCommand(arguments, CHAT_POST_MESSAGE_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle sendFileToUser(String userName, byte[] data, String fileName) {
return sendFileToUser(findUserByUserName(userName), data, fileName);
}
@Override
public SlackMessageHandle sendFileToUser(SlackUser user, byte[] data, String fileName) {
SlackChannel iMChannel = getIMChannelForUser(user);
return sendFile(iMChannel, data, fileName);
}
@Override
public SlackMessageHandle sendFile(SlackChannel channel, byte[] data, String fileName) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("channels", channel.getId());
arguments.put("filename", fileName);
postSlackCommandWithFile(arguments, data, fileName, FILE_UPLOAD_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle deleteMessage(String timeStamp, SlackChannel channel) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("channel", channel.getId());
arguments.put("ts", timeStamp);
postSlackCommand(arguments, CHAT_DELETE_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle updateMessage(String timeStamp, SlackChannel channel, String message) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("ts", timeStamp);
arguments.put("channel", channel.getId());
arguments.put("text", message);
postSlackCommand(arguments, CHAT_UPDATE_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle addReactionToMessage(SlackChannel channel, String messageTimeStamp, String emojiCode) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("channel", channel.getId());
arguments.put("timestamp", messageTimeStamp);
arguments.put("name", emojiCode);
postSlackCommand(arguments, REACTIONS_ADD_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle removeReactionFromMessage(SlackChannel channel, String messageTimeStamp, String emojiCode) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("channel", channel.getId());
arguments.put("timestamp", messageTimeStamp);
arguments.put("name", emojiCode);
postSlackCommand(arguments, REACTIONS_REMOVE_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle joinChannel(String channelName) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("name", channelName);
postSlackCommand(arguments, CHANNELS_JOIN_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle setChannelTopic(SlackChannel channel, String topic) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("channel", channel.getId());
arguments.put("topic", topic);
postSlackCommand(arguments, CHANNELS_SET_TOPIC_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle leaveChannel(SlackChannel channel) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("channel", channel.getId());
postSlackCommand(arguments, CHANNELS_LEAVE_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle inviteToChannel(SlackChannel channel, SlackUser user) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("channel", channel.getId());
arguments.put("user", user.getId());
postSlackCommand(arguments, CHANNELS_INVITE_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle archiveChannel(SlackChannel channel) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("channel", channel.getId());
postSlackCommand(arguments, CHANNELS_ARCHIVE_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle unarchiveChannel(SlackChannel channel) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("channel", channel.getId());
postSlackCommand(arguments, CHANNELS_UNARCHIVE_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle openDirectMessageChannel(SlackUser user) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("user", user.getId());
postSlackCommand(arguments, DIRECT_MESSAGE_OPEN_CHANNEL_COMMAND, handle);
return handle;
}
@Override
public SlackMessageHandle openMultipartyDirectMessageChannel(SlackUser... users) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < users.length; i++) {
if (i != 0) {
strBuilder.append(',');
}
strBuilder.append(users[i].getId());
}
arguments.put("users", strBuilder.toString());
postSlackCommand(arguments, MULTIPARTY_DIRECT_MESSAGE_OPEN_CHANNEL_COMMAND, handle);
if (!handle.getReply().isOk()) {
LOGGER.debug("Error occurred while performing command: '" + handle.getReply().getErrorMessage() + "'");
return null;
}
return handle;
}
public SlackMessageHandle listEmoji() {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
postSlackCommand(arguments, LIST_EMOJI_COMMAND, handle);
return handle;
}
@Override
public void refetchUsers() {
Map params = new HashMap<>();
params.put("presence", "1");
SlackMessageHandle handle = postGenericSlackCommand(params, LIST_USERS);
GenericSlackReply replyEv = handle.getReply();
String answer = replyEv.getPlainAnswer();
JsonParser parser = new JsonParser();
JsonObject answerJson = parser.parse(answer).getAsJsonObject();
JsonArray membersjson = answerJson.get("members").getAsJsonArray();
Map members = new HashMap<>();
if (membersjson != null) {
for (JsonElement member : membersjson) {
SlackUser user = SlackJSONParsingUtils.buildSlackUser(member.getAsJsonObject());
members.put(user.getId(), user);
}
}
// blindly replace cache
users = members;
}
private void postSlackCommand(Map params, String command, SlackMessageHandleImpl handle) {
HttpClient client = getHttpClient();
HttpPost request = new HttpPost(SLACK_API_HTTPS_ROOT + command);
List nameValuePairList = new ArrayList<>();
for (Map.Entry arg : params.entrySet()) {
nameValuePairList.add(new BasicNameValuePair(arg.getKey(), arg.getValue()));
}
try {
request.setEntity(new UrlEncodedFormEntity(nameValuePairList, "UTF-8"));
HttpResponse response = client.execute(request);
String jsonResponse = consumeToString(response.getEntity().getContent());
LOGGER.debug("PostMessage return: " + jsonResponse);
ParsedSlackReply reply = SlackJSONReplyParser.decode(parseObject(jsonResponse), this);
handle.setReply(reply);
} catch (Exception e) {
// TODO : improve exception handling
e.printStackTrace();
}
}
private void postSlackCommandWithFile(Map params, byte[] fileContent, String fileName, String command, SlackMessageHandleImpl handle) {
URIBuilder uriBuilder = new URIBuilder();
uriBuilder.setScheme(SLACK_API_SCHEME).setHost(SLACK_API_HOST).setPath(SLACK_API_PATH + "/" + command);
for (Map.Entry arg : params.entrySet()) {
uriBuilder.setParameter(arg.getKey(), arg.getValue());
}
HttpPost request = new HttpPost(uriBuilder.toString());
HttpClient client = getHttpClient();
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
try {
builder.addBinaryBody("file", fileContent, ContentType.DEFAULT_BINARY, fileName);
request.setEntity(builder.build());
HttpResponse response = client.execute(request);
String jsonResponse = ReaderUtils.readAll(new InputStreamReader(response.getEntity().getContent()));
LOGGER.debug("PostMessage return: " + jsonResponse);
ParsedSlackReply reply = SlackJSONReplyParser.decode(parseObject(jsonResponse), this);
handle.setReply(reply);
} catch (Exception e) {
// TODO : improve exception handling
e.printStackTrace();
}
}
@Override
public SlackMessageHandle postGenericSlackCommand(Map params, String command) {
HttpClient client = getHttpClient();
HttpPost request = new HttpPost(SLACK_API_HTTPS_ROOT + command);
List nameValuePairList = new ArrayList<>();
for (Map.Entry arg : params.entrySet()) {
if (!"token".equals(arg.getKey())) {
nameValuePairList.add(new BasicNameValuePair(arg.getKey(), arg.getValue()));
}
}
nameValuePairList.add(new BasicNameValuePair("token", authToken));
try {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
request.setEntity(new UrlEncodedFormEntity(nameValuePairList, "UTF-8"));
HttpResponse response = client.execute(request);
String jsonResponse = consumeToString(response.getEntity().getContent());
LOGGER.debug("PostMessage return: " + jsonResponse);
GenericSlackReplyImpl reply = new GenericSlackReplyImpl(jsonResponse);
handle.setReply(reply);
return handle;
} catch (Exception e) {
// TODO : improve exception handling
e.printStackTrace();
}
return null;
}
private HttpClient getHttpClient() {
HttpClient client;
if (proxyHost != null) {
client = HttpClientBuilder.create().setRoutePlanner(new DefaultProxyRoutePlanner(proxyHost)).build();
} else {
client = HttpClientBuilder.create().build();
}
return client;
}
@Override
public SlackMessageHandle sendMessageOverWebSocket(SlackChannel channel, String message) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
try {
JsonObject messageJSON = new JsonObject();
messageJSON.addProperty("id", handle.getMessageId());
messageJSON.addProperty("type", "message");
messageJSON.addProperty("channel", channel.getId());
messageJSON.addProperty("text", message);
websocketSession.getBasicRemote().sendText(messageJSON.toString());
} catch (Exception e) {
// TODO : improve exception handling
e.printStackTrace();
}
return handle;
}
@Override
public SlackMessageHandle sendPresenceSubMessageOverWebSocket(String[] ids) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
try {
JsonArray userIdArray = new JsonArray();
for (String userId : ids) {
userIdArray.add(userId);
}
JsonObject messageJSON = new JsonObject();
// messageJSON.addProperty("id", handle.getMessageId());
messageJSON.addProperty("type", "presence_sub");
messageJSON.add("ids", userIdArray);
websocketSession.getBasicRemote().sendText(messageJSON.toString());
} catch (Exception e) {
// TODO : improve exception handling
e.printStackTrace();
}
return handle;
}
@Override
public SlackMessageHandle sendRawMessageOverWebSocket(JsonObject messageJSON) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
try {
websocketSession.getBasicRemote().sendText(messageJSON.toString());
} catch (Exception e) {
// TODO : improve exception handling
e.printStackTrace();
}
return handle;
}
@Override
public SlackMessageHandle sendTyping(SlackChannel channel) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
try {
JsonObject messageJSON = new JsonObject();
messageJSON.addProperty("id", handle.getMessageId());
messageJSON.addProperty("type", "typing");
messageJSON.addProperty("channel", channel.getId());
websocketSession.getBasicRemote().sendText(messageJSON.toString());
} catch (Exception e) {
// TODO : improve exception handling
e.printStackTrace();
}
return handle;
}
@Override
public SlackPersona.SlackPresence getPresence(SlackPersona persona) {
HttpClient client = getHttpClient();
HttpPost request = new HttpPost("https://slack.com/api/users.getPresence");
List nameValuePairList = new ArrayList<>();
nameValuePairList.add(new BasicNameValuePair("token", authToken));
nameValuePairList.add(new BasicNameValuePair("user", persona.getId()));
try {
request.setEntity(new UrlEncodedFormEntity(nameValuePairList, "UTF-8"));
HttpResponse response = client.execute(request);
String jsonResponse = consumeToString(response.getEntity().getContent());
LOGGER.debug("PostMessage return: " + jsonResponse);
JsonObject resultObject = parseObject(jsonResponse);
// quite hacky need to refactor this
SlackUserPresenceReply reply = (SlackUserPresenceReply) SlackJSONReplyParser.decode(resultObject, this);
if (!reply.isOk()) {
return SlackPersona.SlackPresence.UNKNOWN;
}
String presence = resultObject.get("presence") != null ? resultObject.get("presence").getAsString() : null;
if ("active".equals(presence)) {
return SlackPersona.SlackPresence.ACTIVE;
}
if ("away".equals(presence)) {
return SlackPersona.SlackPresence.AWAY;
}
} catch (Exception e) {
// TODO : improve exception handling
e.printStackTrace();
}
return SlackPersona.SlackPresence.UNKNOWN;
}
public void setPresence(SlackPersona.SlackPresence presence) {
if (presence == SlackPersona.SlackPresence.UNKNOWN || presence == SlackPersona.SlackPresence.ACTIVE) {
throw new IllegalArgumentException("Presence must be either AWAY or AUTO");
}
HttpClient client = getHttpClient();
HttpPost request = new HttpPost(SLACK_API_HTTPS_ROOT + SET_PERSONA_ACTIVE);
List nameValuePairList = new ArrayList<>();
nameValuePairList.add(new BasicNameValuePair("token", authToken));
nameValuePairList.add(new BasicNameValuePair("presence", presence.toString().toLowerCase()));
try {
request.setEntity(new UrlEncodedFormEntity(nameValuePairList, "UTF-8"));
HttpResponse response = client.execute(request);
String JSONResponse = consumeToString(response.getEntity().getContent());
LOGGER.debug("JSON Response=" + JSONResponse);
} catch (IOException e) {
e.printStackTrace();
}
}
private long getNextMessageId() {
return messageId.getAndIncrement();
}
@Override
public void onMessage(String message) {
final JsonObject object = parseObject(message);
LOGGER.debug("receiving from websocket " + message);
if ("pong".equals(object.get("type").getAsString())) {
lastPingAck = object.get("reply_to").getAsInt();
LOGGER.debug("pong received " + lastPingAck);
} else if ("reconnect_url".equals(object.get("type").getAsString())) {
webSocketConnectionURL = object.get("url").getAsString();
LOGGER.debug("new websocket connection received " + webSocketConnectionURL);
} else if ("hello".equals(object.get("type").getAsString())) {
LOGGER.debug("hello message received.");
Collection slackUsers = getUsers();
List userIdList=new ArrayList();
for(SlackUser u:slackUsers) {
userIdList.add(u.getId());
}
sendPresenceSubMessageOverWebSocket(userIdList.toArray(new String[] {}));
} else {
SlackEvent slackEvent = SlackJSONMessageParser.decode(this, object);
if (slackEvent instanceof SlackChannelCreated) {
SlackChannelCreated slackChannelCreated = (SlackChannelCreated) slackEvent;
channels.put(slackChannelCreated.getSlackChannel().getId(), slackChannelCreated.getSlackChannel());
}
if (slackEvent instanceof SlackGroupJoined) {
SlackGroupJoined slackGroupJoined = (SlackGroupJoined) slackEvent;
channels.put(slackGroupJoined.getSlackChannel().getId(), slackGroupJoined.getSlackChannel());
}
if (slackEvent instanceof SlackUserChangeEvent) {
SlackUserChangeEvent slackUserChangeEvent = (SlackUserChangeEvent) slackEvent;
users.put(slackUserChangeEvent.getUser().getId(), slackUserChangeEvent.getUser());
}
dispatcher.dispatch(slackEvent, message);
}
}
private JsonObject parseObject(String json) {
JsonParser parser = new JsonParser();
return parser.parse(json).getAsJsonObject();
}
@Override
public SlackMessageHandle inviteUser(String email, String firstName, boolean setActive) {
SlackMessageHandleImpl handle = new SlackMessageHandleImpl<>(getNextMessageId());
Map arguments = new HashMap<>();
arguments.put("token", authToken);
arguments.put("email", email);
arguments.put("first_name", firstName);
arguments.put("set_active", "" + setActive);
postSlackCommand(arguments, INVITE_USER_COMMAND, handle);
return handle;
}
public long getHeartbeat() {
return TimeUnit.MILLISECONDS.toSeconds(heartbeat);
}
private final PresenceChangeListener INTERNAL_PRESENCE_CHANGE_LISTENER = new PresenceChangeListener() {
@Override
public void onEvent(PresenceChange event, SlackSession session) {
SlackUser user = users.get(event.getUserId());
SlackUserImpl newUser = new SlackUserImpl(user.getId(), user.getUserName(), user.getRealName(), user.getUserMail(), user.getUserSkype(),
user.getUserTitle(), user.getUserPhone(),
user.isDeleted(), user.isAdmin(), user.isOwner(), user.isPrimaryOwner(), user.isRestricted(),
user.isUltraRestricted(), user.isBot(), user.getTimeZone(), user.getTimeZoneLabel(), user.getTimeZoneOffset(),
event.getPresence());
users.put(event.getUserId(), newUser);
}
};
private final SlackChannelArchivedListener INTERNAL_CHANNEL_ARCHIVE_LISTENER = new SlackChannelArchivedListener() {
@Override
public void onEvent(SlackChannelArchived event, SlackSession session) {
SlackChannel channel = channels.get(event.getSlackChannel().getId());
SlackChannelImpl newChannel = new SlackChannelImpl(channel.getId(), channel.getName(), channel.getTopic(), channel.getPurpose(), channel.isDirect(),
channel.isMember(), true);
channels.put(newChannel.getId(), newChannel);
}
};
private final SlackChannelCreatedListener INTERNAL_CHANNEL_CREATED_LISTENER = new SlackChannelCreatedListener() {
@Override
public void onEvent(SlackChannelCreated event, SlackSession session) {
channels.put(event.getSlackChannel().getId(), event.getSlackChannel());
}
};
private final SlackChannelDeletedListener INTERNAL_CHANNEL_DELETED_LISTENER = new SlackChannelDeletedListener() {
@Override
public void onEvent(SlackChannelDeleted event, SlackSession session) {
channels.remove(event.getSlackChannel().getId());
}
};
private final SlackChannelRenamedListener INTERNAL_CHANNEL_RENAMED_LISTENER = new SlackChannelRenamedListener() {
@Override
public void onEvent(SlackChannelRenamed event, SlackSession session) {
SlackChannel channel = channels.get(event.getSlackChannel().getId());
SlackChannelImpl newChannel = new SlackChannelImpl(channel.getId(), event.getNewName(), channel.getTopic(), channel.getPurpose(), channel.isDirect(),
channel.isMember(), channel.isArchived());
channels.put(newChannel.getId(), newChannel);
}
};
private final SlackChannelUnarchivedListener INTERNAL_CHANNEL_UNARCHIVED_LISTENER = new SlackChannelUnarchivedListener() {
@Override
public void onEvent(SlackChannelUnarchived event, SlackSession session) {
SlackChannel channel = channels.get(event.getSlackChannel().getId());
SlackChannelImpl newChannel = new SlackChannelImpl(channel.getId(), channel.getName(), channel.getTopic(), channel.getPurpose(), channel.isDirect(),
channel.isMember(), false);
channels.put(newChannel.getId(), newChannel);
}
};
private final SlackTeamJoinListener INTERNAL_TEAM_JOIN_LISTENER = new SlackTeamJoinListener() {
@Override
public void onEvent(SlackTeamJoin event, SlackSession session) {
users.put(event.getUser().getId(), event.getUser());
}
};
private final SlackUserChangeListener INTERNAL_USER_CHANGE_LISTENER = new SlackUserChangeListener() {
@Override
public void onEvent(SlackUserChange event, SlackSession session) {
users.put(event.getUser().getId(), event.getUser());
}
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy