From 22c5fd623022c4b2c2b0d43d4fb7fd8c0648cc81 Mon Sep 17 00:00:00 2001 From: Mathurshan Vimalesvaran Date: Sun, 21 Jan 2018 17:50:48 -0500 Subject: [PATCH 1/2] use converstations api to get members for each channel --- .../slack/simpleslackapi/SlackChannel.java | 45 +++++++++-- .../slack/simpleslackapi/SlackSession.java | 38 +++++++++- .../simpleslackapi/SlackSessionWrapper.java | 11 ++- .../impl/AbstractSlackSessionImpl.java | 45 +++++++++-- .../impl/SlackJSONMessageParser.java | 14 ++-- .../impl/SlackJSONParsingUtils.java | 11 ++- .../impl/SlackJSONSessionStatusParser.java | 28 ++++--- .../impl/SlackWebSocketSessionImpl.java | 74 +++++++++++++++++-- .../impl/TestAbstractSlackSessionImpl.java | 37 +++++++--- .../impl/TestSlackJSONMessageParser.java | 15 ++-- .../TestSlackJSONSessionStatusParser.java | 2 +- 11 files changed, 257 insertions(+), 63 deletions(-) diff --git a/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackChannel.java b/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackChannel.java index 9dd41ddf..9587c3b1 100644 --- a/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackChannel.java +++ b/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackChannel.java @@ -1,27 +1,45 @@ package com.ullink.slack.simpleslackapi; -import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.threeten.bp.LocalDateTime; + +import com.ullink.slack.simpleslackapi.SlackSession.GetMembersForChannelCallable; -import com.ullink.slack.simpleslackapi.SlackUser; //TODO: a domain object public class SlackChannel { + private static final Logger LOGGER = LoggerFactory.getLogger(SlackChannel.class); + private static final long REFRESH_MEMBERS_EVERY_SECONDS = TimeUnit.HOURS.toSeconds(1); + private final boolean direct; private String id; private String name; private Set members = new HashSet<>(); + private GetMembersForChannelCallable getMembersForChannelCallable; private String topic; private String purpose; private boolean isMember; private boolean isArchived; - - public SlackChannel(String id, String name, String topic, String purpose, boolean direct, boolean isMember, boolean isArchived) + private LocalDateTime membersLastUpdated; + + public SlackChannel(String id, + String name, + GetMembersForChannelCallable getMembersForChannelCallable, + String topic, + String purpose, + boolean direct, + boolean isMember, + boolean isArchived) { this.id = id; this.name = name; + this.getMembersForChannelCallable = getMembersForChannelCallable; this.topic = topic; this.purpose = purpose; this.direct = direct; @@ -49,9 +67,17 @@ public String getName() return name; } - public Collection getMembers() - { - return new ArrayList<>(members); + public Collection getMembers() { + if (shouldRefreshMembers()) { + try { + members = getMembersForChannelCallable.setChannelId(id).call(); + membersLastUpdated = LocalDateTime.now(); + } catch (Exception e) { + LOGGER.error("Failed to refresh members for {}", name, e); + } + } + + return members; } public String getTopic() @@ -101,4 +127,9 @@ public SlackChannelType getType() public enum SlackChannelType { PUBLIC_CHANNEL, PRIVATE_GROUP, INSTANT_MESSAGING } + + private boolean shouldRefreshMembers() { + return membersLastUpdated == null || + LocalDateTime.now().isAfter(membersLastUpdated.plusSeconds(REFRESH_MEMBERS_EVERY_SECONDS)); + } } diff --git a/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackSession.java b/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackSession.java index 9ff5c722..4d099965 100644 --- a/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackSession.java +++ b/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackSession.java @@ -1,11 +1,37 @@ package com.ullink.slack.simpleslackapi; -import com.ullink.slack.simpleslackapi.listeners.*; -import com.ullink.slack.simpleslackapi.replies.*; - import java.io.IOException; import java.util.Collection; import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; + +import com.ullink.slack.simpleslackapi.listeners.PinAddedListener; +import com.ullink.slack.simpleslackapi.listeners.PinRemovedListener; +import com.ullink.slack.simpleslackapi.listeners.PresenceChangeListener; +import com.ullink.slack.simpleslackapi.listeners.ReactionAddedListener; +import com.ullink.slack.simpleslackapi.listeners.ReactionRemovedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelArchivedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelCreatedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelDeletedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelJoinedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelLeftListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelRenamedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelUnarchivedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackConnectedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackDisconnectedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackGroupJoinedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackMessageDeletedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackMessagePostedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackMessageUpdatedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackTeamJoinListener; +import com.ullink.slack.simpleslackapi.listeners.SlackUserChangeListener; +import com.ullink.slack.simpleslackapi.listeners.UserTypingListener; +import com.ullink.slack.simpleslackapi.replies.EmojiSlackReply; +import com.ullink.slack.simpleslackapi.replies.GenericSlackReply; +import com.ullink.slack.simpleslackapi.replies.ParsedSlackReply; +import com.ullink.slack.simpleslackapi.replies.SlackChannelReply; +import com.ullink.slack.simpleslackapi.replies.SlackMessageReply; public interface SlackSession { @@ -15,6 +41,12 @@ public interface SlackSession { Collection getUsers(); + interface GetMembersForChannelCallable extends Callable> { + GetMembersForChannelCallable setChannelId(String channelId); + } + + GetMembersForChannelCallable getMembersForChannelCallable(String channelId); + Collection getBots(); Collection getIntegrations(); diff --git a/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackSessionWrapper.java b/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackSessionWrapper.java index 14d7c63c..f0018e01 100644 --- a/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackSessionWrapper.java +++ b/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackSessionWrapper.java @@ -25,7 +25,11 @@ import com.ullink.slack.simpleslackapi.listeners.SlackTeamJoinListener; import com.ullink.slack.simpleslackapi.listeners.SlackUserChangeListener; import com.ullink.slack.simpleslackapi.listeners.UserTypingListener; -import com.ullink.slack.simpleslackapi.replies.*; +import com.ullink.slack.simpleslackapi.replies.EmojiSlackReply; +import com.ullink.slack.simpleslackapi.replies.GenericSlackReply; +import com.ullink.slack.simpleslackapi.replies.ParsedSlackReply; +import com.ullink.slack.simpleslackapi.replies.SlackChannelReply; +import com.ullink.slack.simpleslackapi.replies.SlackMessageReply; public class SlackSessionWrapper implements SlackSession { @@ -51,6 +55,11 @@ public SlackSessionWrapper(SlackSession delegate) return delegate.getUsers(); } + @Override + public GetMembersForChannelCallable getMembersForChannelCallable(String channelId) { + return delegate.getMembersForChannelCallable(channelId); + } + @Override public Collection getBots() { return delegate.getBots(); diff --git a/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/AbstractSlackSessionImpl.java b/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/AbstractSlackSessionImpl.java index 63eec8f1..fd392491 100644 --- a/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/AbstractSlackSessionImpl.java +++ b/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/AbstractSlackSessionImpl.java @@ -1,13 +1,46 @@ package com.ullink.slack.simpleslackapi.impl; -import com.ullink.slack.simpleslackapi.*; -import com.ullink.slack.simpleslackapi.listeners.*; -import com.ullink.slack.simpleslackapi.replies.SlackMessageReply; - -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import com.ullink.slack.simpleslackapi.SlackAttachment; +import com.ullink.slack.simpleslackapi.SlackBot; +import com.ullink.slack.simpleslackapi.SlackChannel; +import com.ullink.slack.simpleslackapi.SlackChatConfiguration; +import com.ullink.slack.simpleslackapi.SlackIntegration; +import com.ullink.slack.simpleslackapi.SlackMessageHandle; +import com.ullink.slack.simpleslackapi.SlackPersona; +import com.ullink.slack.simpleslackapi.SlackPreparedMessage; +import com.ullink.slack.simpleslackapi.SlackSession; +import com.ullink.slack.simpleslackapi.SlackTeam; +import com.ullink.slack.simpleslackapi.SlackUser; +import com.ullink.slack.simpleslackapi.listeners.PinAddedListener; +import com.ullink.slack.simpleslackapi.listeners.PinRemovedListener; +import com.ullink.slack.simpleslackapi.listeners.PresenceChangeListener; +import com.ullink.slack.simpleslackapi.listeners.ReactionAddedListener; +import com.ullink.slack.simpleslackapi.listeners.ReactionRemovedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelArchivedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelCreatedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelDeletedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelJoinedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelLeftListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelRenamedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackChannelUnarchivedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackConnectedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackDisconnectedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackGroupJoinedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackMessageDeletedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackMessagePostedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackMessageUpdatedListener; +import com.ullink.slack.simpleslackapi.listeners.SlackTeamJoinListener; +import com.ullink.slack.simpleslackapi.listeners.SlackUserChangeListener; +import com.ullink.slack.simpleslackapi.listeners.UserTypingListener; +import com.ullink.slack.simpleslackapi.replies.SlackMessageReply; + abstract class AbstractSlackSessionImpl implements SlackSession { @@ -102,7 +135,7 @@ public SlackChannel findChannelById(String channelId) // direct channel case if (channelId != null && channelId.startsWith("D")) { - toReturn = new SlackChannel(channelId, "", "", "", true, false, false); + toReturn = new SlackChannel(channelId, "", getMembersForChannelCallable(channelId),"", "", true, false, false); } } return toReturn; diff --git a/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONMessageParser.java b/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONMessageParser.java index 7db6526f..5b8167ae 100644 --- a/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONMessageParser.java +++ b/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONMessageParser.java @@ -100,7 +100,7 @@ static SlackEvent decode(SlackSession slackSession, JsonObject obj) { private static SlackChannelJoined extractChannelJoinedEvent(SlackSession slackSession, JsonObject obj) { JsonObject channelJSONObject = obj.get("channel").getAsJsonObject(); - SlackChannel slackChannel = parseChannelDescription(channelJSONObject); + SlackChannel slackChannel = parseChannelDescription(slackSession, channelJSONObject); return new SlackChannelJoined(slackChannel); } @@ -114,14 +114,14 @@ private static SlackChannelLeft extractChannelLeftEvent(SlackSession slackSessio private static SlackGroupJoined extractGroupJoinedEvent(SlackSession slackSession, JsonObject obj) { JsonObject channelJSONObject = obj.get("channel").getAsJsonObject(); - SlackChannel slackChannel = parseChannelDescription(channelJSONObject); + SlackChannel slackChannel = parseChannelDescription(slackSession, channelJSONObject); return new SlackGroupJoined(slackChannel); } private static SlackChannelRenamed extractChannelRenamedEvent(SlackSession slackSession, JsonObject obj) { JsonObject channelJSONObject = obj.get("channel").getAsJsonObject(); - SlackChannel channel = parseChannelDescription(channelJSONObject); + SlackChannel channel = parseChannelDescription(slackSession, channelJSONObject); return new SlackChannelRenamed(channel, channel.getName()); } @@ -148,7 +148,7 @@ private static SlackChannelArchived extractChannelArchiveEvent(SlackSession slac private static SlackChannelCreated extractChannelCreatedEvent(SlackSession slackSession, JsonObject obj) { JsonObject channelJSONObject = obj.get("channel").getAsJsonObject(); - SlackChannel channel = parseChannelDescription(channelJSONObject); + SlackChannel channel = parseChannelDescription(slackSession, channelJSONObject); String creatorId = GsonHelper.getStringOrNull(channelJSONObject.get("creator")); SlackUser user = slackSession.findUserById(creatorId); return new SlackChannelCreated(channel, user); @@ -183,7 +183,7 @@ private static SlackChannel getChannel(SlackSession slackSession, String channel if (channelId.startsWith("D")) { // direct messaging, on the fly channel creation - return new SlackChannel(channelId, channelId, "", "", true, false, false); + return new SlackChannel(channelId, channelId, slackSession.getMembersForChannelCallable(channelId), "", "", true, false, false); } else { @@ -304,7 +304,7 @@ private static SlackMessagePosted parseMessagePublishedWithFile(JsonObject obj, return new SlackMessagePosted(text, user, user, channel, ts,file,obj.toString(), SlackMessagePosted.MessageSubType.fromCode(subtype), threadTimestamp); } - private static SlackChannel parseChannelDescription(JsonObject channelJSONObject) { + private static SlackChannel parseChannelDescription(SlackSession slackSession, JsonObject channelJSONObject) { String id = GsonHelper.getStringOrNull(channelJSONObject.get("id")); String name = GsonHelper.getStringOrNull(channelJSONObject.get("name")); String topic = null; @@ -316,7 +316,7 @@ private static SlackChannel parseChannelDescription(JsonObject channelJSONObject purpose = GsonHelper.getStringOrNull((channelJSONObject.get("purpose").getAsJsonObject().get("value"))); } boolean isArchived = GsonHelper.getBooleanOrDefaultValue(channelJSONObject.get("is_archived"), false); - return new SlackChannel(id, name, topic, purpose, id.startsWith("D"),false, isArchived); + return new SlackChannel(id, name, slackSession.getMembersForChannelCallable(id), topic, purpose, id.startsWith("D"),false, isArchived); } diff --git a/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONParsingUtils.java b/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONParsingUtils.java index 064c4a67..792d230c 100644 --- a/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONParsingUtils.java +++ b/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONParsingUtils.java @@ -6,6 +6,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.ullink.slack.simpleslackapi.*; +import com.ullink.slack.simpleslackapi.SlackSession.GetMembersForChannelCallable; class SlackJSONParsingUtils { @@ -59,7 +60,7 @@ static final SlackUser buildSlackUser(JsonObject jsonUser) return new SlackUserImpl(id, name, realName, email, skype, title, phone, deleted, admin, owner, primaryOwner, restricted, ultraRestricted, bot, tz, tzLabel, tzOffset == null ? null : new Integer(tzOffset.intValue()), slackPresence); } - static final SlackChannel buildSlackChannel(JsonObject jsonChannel, Map knownUsersById) { + static final SlackChannel buildSlackChannel(JsonObject jsonChannel, Map knownUsersById, GetMembersForChannelCallable getMembersForChannelCallable) { String id = GsonHelper.getStringOrNull(jsonChannel.get("id")); String name = GsonHelper.getStringOrNull(jsonChannel.get("name")); @@ -82,8 +83,7 @@ static final SlackChannel buildSlackChannel(JsonObject jsonChannel, Map knownUsersById) - { + static final SlackChannel buildSlackImChannel(JsonObject jsonChannel, Map knownUsersById, GetMembersForChannelCallable getMembersForChannelCallable) { String id = GsonHelper.getStringOrNull(jsonChannel.get("id")); - SlackChannel toReturn = new SlackChannel(id, null, null, null, true, false, false); + SlackChannel toReturn = new SlackChannel(id, null, getMembersForChannelCallable, null, null, true, false, false); String memberId = GsonHelper.getStringOrNull(jsonChannel.get("user")); SlackUser user = knownUsersById.get(memberId); toReturn.addUser(user); diff --git a/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONSessionStatusParser.java b/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONSessionStatusParser.java index 8f3e8b41..80874c15 100644 --- a/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONSessionStatusParser.java +++ b/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackJSONSessionStatusParser.java @@ -3,13 +3,19 @@ import java.util.HashMap; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import com.ullink.slack.simpleslackapi.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.ullink.slack.simpleslackapi.SlackChannel; +import com.ullink.slack.simpleslackapi.SlackIntegration; +import com.ullink.slack.simpleslackapi.SlackPersona; +import com.ullink.slack.simpleslackapi.SlackSession.GetMembersForChannelCallable; +import com.ullink.slack.simpleslackapi.SlackTeam; +import com.ullink.slack.simpleslackapi.SlackUser; class SlackJSONSessionStatusParser { @@ -18,6 +24,7 @@ class SlackJSONSessionStatusParser { private Map channels = new HashMap<>(); private Map users = new HashMap<>(); private Map integrations = new HashMap<>(); + private GetMembersForChannelCallable getMembersForChannelCallable; private SlackPersona sessionPersona; @@ -29,9 +36,10 @@ class SlackJSONSessionStatusParser { private String error; - SlackJSONSessionStatusParser(String toParse) + SlackJSONSessionStatusParser(String toParse, GetMembersForChannelCallable getMembersForChannelCallable) { this.toParse = toParse; + this.getMembersForChannelCallable = getMembersForChannelCallable; } Map getChannels() @@ -44,6 +52,7 @@ Map getUsers() return users; } + Map getIntegrations() { return integrations; } @@ -58,14 +67,13 @@ public String getError() return error; } - void parse() - { + void parse() { LOGGER.debug("parsing session status : " + toParse); JsonParser parser = new JsonParser(); JsonObject jsonResponse = parser.parse(toParse).getAsJsonObject(); Boolean ok = jsonResponse.get("ok").getAsBoolean(); if (Boolean.FALSE.equals(ok)) { - error = (String)jsonResponse.get("error").getAsString(); + error = jsonResponse.get("error").getAsString(); return; } JsonArray usersJson = jsonResponse.get("users").getAsJsonArray(); @@ -94,7 +102,7 @@ void parse() for (JsonElement jsonObject : channelsJson) { JsonObject jsonChannel = jsonObject.getAsJsonObject(); - SlackChannel channel = SlackJSONParsingUtils.buildSlackChannel(jsonChannel, users); + SlackChannel channel = SlackJSONParsingUtils.buildSlackChannel(jsonChannel, users, getMembersForChannelCallable); LOGGER.debug("slack public channel found : " + channel.getId()); channels.put(channel.getId(), channel); } @@ -105,7 +113,7 @@ void parse() for (JsonElement jsonObject : groupsJson) { JsonObject jsonChannel = jsonObject.getAsJsonObject(); - SlackChannel channel = SlackJSONParsingUtils.buildSlackChannel(jsonChannel, users); + SlackChannel channel = SlackJSONParsingUtils.buildSlackChannel(jsonChannel, users, getMembersForChannelCallable); LOGGER.debug("slack private group found : " + channel.getId()); channels.put(channel.getId(), channel); } @@ -118,7 +126,7 @@ void parse() for (JsonElement jsonObject : imsJson) { JsonObject jsonChannel = jsonObject.getAsJsonObject(); - SlackChannel channel = SlackJSONParsingUtils.buildSlackImChannel(jsonChannel, users); + SlackChannel channel = SlackJSONParsingUtils.buildSlackImChannel(jsonChannel, users, getMembersForChannelCallable); LOGGER.debug("slack im channel found : " + channel.getId()); channels.put(channel.getId(), channel); } diff --git a/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackWebSocketSessionImpl.java b/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackWebSocketSessionImpl.java index 50a06f3b..4ce20f7d 100644 --- a/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackWebSocketSessionImpl.java +++ b/sources/src/main/java/com/ullink/slack/simpleslackapi/impl/SlackWebSocketSessionImpl.java @@ -52,7 +52,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; -class SlackWebSocketSessionImpl extends AbstractSlackSessionImpl implements SlackSession, MessageHandler.Whole { +public 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"; @@ -99,6 +99,7 @@ class SlackWebSocketSessionImpl extends AbstractSlackSessionImpl implements Slac private static final String LIST_USERS = "users.list"; + private static final String CONVERSTATIONS_MEMBERS = "conversations.members"; private static final Logger LOGGER = LoggerFactory.getLogger(SlackWebSocketSessionImpl.class); @@ -250,6 +251,26 @@ private > void dispatchImp } } + public class GetMembersForChannelImpl implements GetMembersForChannelCallable { + private String channelId; + + GetMembersForChannelImpl() {} + + GetMembersForChannelImpl(String channelId) { + this.channelId = channelId; + } + + public GetMembersForChannelImpl setChannelId(String channelId) { + this.channelId = channelId; + return this; + } + + @Override + public Set call() { + return getMembersForChannel(channelId); + } + } + SlackWebSocketSessionImpl(WebSocketContainerProvider webSocketContainerProvider, String authToken, boolean reconnectOnDisconnection, boolean isRateLimitSupported, long heartbeat, TimeUnit unit) { this.authToken = authToken; this.reconnectOnDisconnection = reconnectOnDisconnection; @@ -303,7 +324,7 @@ public void disconnect() { stopConnectionMonitoring(); } - public void reconnect() throws IOException{ + public void reconnect() throws Exception{ while(true) { if (!this.isConnected()) { connectImpl(); @@ -330,7 +351,7 @@ private void connectImpl() throws IOException HttpResponse response = httpClient.execute(request); LOGGER.debug(response.getStatusLine().toString()); String jsonResponse = consumeToString(response.getEntity().getContent()); - SlackJSONSessionStatusParser sessionParser = new SlackJSONSessionStatusParser(jsonResponse); + final SlackJSONSessionStatusParser sessionParser = new SlackJSONSessionStatusParser(jsonResponse, new GetMembersForChannelImpl()); sessionParser.parse(); if (sessionParser.getError() != null) { @@ -352,6 +373,40 @@ private void connectImpl() throws IOException establishWebsocketConnection(); } + private Set getMembersForChannel(String channelId) { + JsonParser parser = new JsonParser(); + Set membersForChannel = new HashSet<>(); + + Map params = new HashMap<>(); + params.put("token", authToken); + params.put("channel", channelId); + JsonObject answerJson; + + do { + SlackMessageHandle handle = postGenericSlackCommand(params, CONVERSTATIONS_MEMBERS); + String answer = handle.getReply().getPlainAnswer(); + answerJson = parser.parse(answer).getAsJsonObject(); + for (JsonElement member : answerJson.get("members").getAsJsonArray()) { + membersForChannel.add(users.get(member.getAsString())); + } + updateCursor(params, answerJson); + } while (hasMoreMembers(answerJson)); + + return membersForChannel; + } + + private boolean hasMoreMembers(JsonObject answerJson) { + return !answerJson.get("response_metadata").isJsonNull() && + !answerJson.get("response_metadata").getAsJsonObject().get("next_cursor").isJsonNull() && + !answerJson.get("response_metadata").getAsJsonObject().get("next_cursor").getAsString().isEmpty(); + } + + private void updateCursor(Map params, JsonObject answerJson) { + if (hasMoreMembers(answerJson)) { + params.put("cursor", answerJson.get("response_metadata").getAsJsonObject().get("next_cursor").getAsString()); + } + } + private void establishWebsocketConnection() throws IOException { lastPingSent = 0; @@ -479,7 +534,7 @@ else if (reconnectOnDisconnection) { LOGGER.info("monitoring thread interrupted"); break; } - catch (IOException e) { + catch (Exception e) { LOGGER.error("unexpected exception on monitoring thread ", e); } } @@ -798,6 +853,11 @@ public SlackMessageHandle openMultipartyDirectMessageChannel( return handle; } + @Override + public GetMembersForChannelImpl getMembersForChannelCallable(String channelId) { + return new GetMembersForChannelImpl(channelId); + } + public SlackMessageHandle listEmoji() { SlackMessageHandle handle = new SlackMessageHandle<>(getNextMessageId()); Map arguments = new HashMap<>(); @@ -1116,7 +1176,7 @@ public long getHeartbeat() { @Override public void onEvent(SlackChannelArchived event, SlackSession session) { SlackChannel channel = channels.get(event.getSlackChannel().getId()); - SlackChannel newChannel = new SlackChannel(channel.getId(), channel.getName(), channel.getTopic(), channel.getPurpose(), channel.isDirect(), channel.isMember(), true); + SlackChannel newChannel = new SlackChannel(channel.getId(), channel.getName(), getMembersForChannelCallable(channel.getId()), channel.getTopic(), channel.getPurpose(), channel.isDirect(), channel.isMember(), true); channels.put(newChannel.getId(), newChannel); } }; @@ -1142,7 +1202,7 @@ public long getHeartbeat() { @Override public void onEvent(SlackChannelRenamed event, SlackSession session) { SlackChannel channel = channels.get(event.getSlackChannel().getId()); - SlackChannel newChannel = new SlackChannel(channel.getId(), event.getNewName(), channel.getTopic(), channel.getPurpose(), channel.isDirect(), channel.isMember(), channel.isArchived()); + SlackChannel newChannel = new SlackChannel(channel.getId(), event.getNewName(), getMembersForChannelCallable(channel.getId()), channel.getTopic(), channel.getPurpose(), channel.isDirect(), channel.isMember(), channel.isArchived()); channels.put(newChannel.getId(), newChannel); } }; @@ -1152,7 +1212,7 @@ public long getHeartbeat() { @Override public void onEvent(SlackChannelUnarchived event, SlackSession session) { SlackChannel channel = channels.get(event.getSlackChannel().getId()); - SlackChannel newChannel = new SlackChannel(channel.getId(), channel.getName(), channel.getTopic(), channel.getPurpose(), channel.isDirect(), channel.isMember(), false); + SlackChannel newChannel = new SlackChannel(channel.getId(), channel.getName(), getMembersForChannelCallable(channel.getId()), channel.getTopic(), channel.getPurpose(), channel.isDirect(), channel.isMember(), false); channels.put(newChannel.getId(), newChannel); } }; diff --git a/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestAbstractSlackSessionImpl.java b/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestAbstractSlackSessionImpl.java index ee633fdf..ae165bd8 100644 --- a/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestAbstractSlackSessionImpl.java +++ b/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestAbstractSlackSessionImpl.java @@ -1,12 +1,24 @@ package com.ullink.slack.simpleslackapi.impl; -import com.ullink.slack.simpleslackapi.*; -import com.ullink.slack.simpleslackapi.events.SlackConnected; -import com.ullink.slack.simpleslackapi.listeners.SlackConnectedListener; -import com.ullink.slack.simpleslackapi.replies.*; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.Test; -import static org.assertj.core.api.Assertions.assertThat; +import com.ullink.slack.simpleslackapi.SlackAttachment; +import com.ullink.slack.simpleslackapi.SlackChannel; +import com.ullink.slack.simpleslackapi.SlackChatConfiguration; +import com.ullink.slack.simpleslackapi.SlackMessageHandle; +import com.ullink.slack.simpleslackapi.SlackPersona; +import com.ullink.slack.simpleslackapi.SlackPreparedMessage; +import com.ullink.slack.simpleslackapi.SlackSession; +import com.ullink.slack.simpleslackapi.SlackUser; +import com.ullink.slack.simpleslackapi.events.SlackConnected; +import com.ullink.slack.simpleslackapi.listeners.SlackConnectedListener; +import com.ullink.slack.simpleslackapi.replies.EmojiSlackReply; +import com.ullink.slack.simpleslackapi.replies.GenericSlackReply; +import com.ullink.slack.simpleslackapi.replies.ParsedSlackReply; +import com.ullink.slack.simpleslackapi.replies.SlackChannelReply; +import com.ullink.slack.simpleslackapi.replies.SlackMessageReply; public class TestAbstractSlackSessionImpl { @@ -19,11 +31,11 @@ public void setPresence(SlackPersona.SlackPresence presence) { @Override public void connect() { - channels.put("channelid1",new SlackChannel("channelid1", "testchannel1", "topicchannel1", "topicchannel1", false, false, false)); - channels.put("channelid2",new SlackChannel("channelid2", "testchannel2", "topicchannel2", "topicchannel2", false, false, false)); - channels.put("channelid3",new SlackChannel("channelid3", "testchannel3", "topicchannel3", "topicchannel3", false, false, false)); - channels.put("channelid4",new SlackChannel("channelid4", "testchannel4", "topicchannel4", "topicchannel4", false, false, false)); - channels.put("channelid5",new SlackChannel("channelid5", "testchannel5", "topicchannel5", "topicchannel5", false, false, false)); + channels.put("channelid1",new SlackChannel("channelid1", "testchannel1", getMembersForChannelCallable("channelid1"), "topicchannel1", "topicchannel1", false, false, false)); + channels.put("channelid2",new SlackChannel("channelid2", "testchannel2", getMembersForChannelCallable("channelid2"), "topicchannel2", "topicchannel2", false, false, false)); + channels.put("channelid3",new SlackChannel("channelid3", "testchannel3", getMembersForChannelCallable("channelid3"), "topicchannel3", "topicchannel3", false, false, false)); + channels.put("channelid4",new SlackChannel("channelid4", "testchannel4", getMembersForChannelCallable("channelid4"), "topicchannel4", "topicchannel4", false, false, false)); + channels.put("channelid5",new SlackChannel("channelid5", "testchannel5", getMembersForChannelCallable("channelid5"), "topicchannel5", "topicchannel5", false, false, false)); users.put("userid1",new SlackUserImpl("userid1", "username1", "realname1","userid1@my.mail", "testSkype", "testPhone", "testTitle", false,false,false,false,false,false, false,"tz","tzLabel",new Integer(0), SlackPersona.SlackPresence.ACTIVE)); users.put("userid2",new SlackUserImpl("userid2", "username2", "realname2","userid2@my.mail", "testSkype", "testPhone", "testTitle", false,false,false,false,false,false, false,"tz","tzLabel",new Integer(0), SlackPersona.SlackPresence.ACTIVE)); @@ -154,6 +166,11 @@ public SlackMessageHandle openMultipartyDirectMessageChannel( return null; } + @Override + public GetMembersForChannelCallable getMembersForChannelCallable(String channelId) { + return null; + } + @Override public SlackMessageHandle listEmoji() { return null; diff --git a/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestSlackJSONMessageParser.java b/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestSlackJSONMessageParser.java index e407a481..d77f5253 100644 --- a/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestSlackJSONMessageParser.java +++ b/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestSlackJSONMessageParser.java @@ -72,10 +72,10 @@ public void connect() { integrations.put(integration.getId(),integration); - SlackChannel channel1 = new SlackChannel("TESTCHANNEL1", "testchannel1", null, null, false, false, false); - SlackChannel channel2 = new SlackChannel("TESTCHANNEL2", "testchannel2", null, null, false, false, false); - SlackChannel channel3 = new SlackChannel("TESTCHANNEL3", "testchannel3", null, null, false, false, false); - SlackChannel channel4 = new SlackChannel("NEWCHANNEL", "new channel", "To have something new", "This channel so new it aint even old yet", false, false, false); + SlackChannel channel1 = new SlackChannel("TESTCHANNEL1", "testchannel1", getMembersForChannelCallable("TESTCHANNEL1"), null, null, false, false, false); + SlackChannel channel2 = new SlackChannel("TESTCHANNEL2", "testchannel2", getMembersForChannelCallable("TESTCHANNEL2"), null, null, false, false, false); + SlackChannel channel3 = new SlackChannel("TESTCHANNEL3", "testchannel3", getMembersForChannelCallable("TESTCHANNEL3"), null, null, false, false, false); + SlackChannel channel4 = new SlackChannel("NEWCHANNEL", "new channel", getMembersForChannelCallable("NEWCHANNEL"), "To have something new", "This channel so new it aint even old yet", false, false, false); channels.put(channel1.getId(), channel1); channels.put(channel2.getId(), channel2); channels.put(channel3.getId(), channel3); @@ -192,6 +192,11 @@ public SlackMessageHandle openMultipartyDirectMessageChannel( return null; } + @Override + public GetMembersForChannelCallable getMembersForChannelCallable(String channelId) { + return null; + } + @Override public SlackMessageHandle listEmoji() { return null; @@ -246,7 +251,7 @@ public SlackMessageHandle archiveChannel(SlackChannel channel) }; try { session.connect(); - } catch (IOException e) { + } catch (Exception e) { e.printStackTrace(); } } diff --git a/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestSlackJSONSessionStatusParser.java b/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestSlackJSONSessionStatusParser.java index 8bfa4bda..c510ada2 100644 --- a/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestSlackJSONSessionStatusParser.java +++ b/sources/src/test/java/com/ullink/slack/simpleslackapi/impl/TestSlackJSONSessionStatusParser.java @@ -22,7 +22,7 @@ public void testParsingSessionDescription() throws Exception strBuilder.append(line); } - SlackJSONSessionStatusParser parser = new SlackJSONSessionStatusParser(strBuilder.toString()); + SlackJSONSessionStatusParser parser = new SlackJSONSessionStatusParser(strBuilder.toString(), null); parser.parse(); assertThat(parser.getChannels()).containsOnlyKeys("CHANNELID1", "CHANNELID2", "CHANNELID3", "GROUPID1", "DIM01"); From c75625be20e6b4122293493af84b90ad424074f0 Mon Sep 17 00:00:00 2001 From: Mathurshan Vimalesvaran Date: Fri, 26 Jan 2018 10:14:16 -0500 Subject: [PATCH 2/2] only refresh members for public channels --- .../java/com/ullink/slack/simpleslackapi/SlackChannel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackChannel.java b/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackChannel.java index 9587c3b1..27e6d0ae 100644 --- a/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackChannel.java +++ b/sources/src/main/java/com/ullink/slack/simpleslackapi/SlackChannel.java @@ -129,7 +129,7 @@ public enum SlackChannelType { } private boolean shouldRefreshMembers() { - return membersLastUpdated == null || - LocalDateTime.now().isAfter(membersLastUpdated.plusSeconds(REFRESH_MEMBERS_EVERY_SECONDS)); + return getType().equals(SlackChannelType.PUBLIC_CHANNEL) && + (membersLastUpdated == null || LocalDateTime.now().isAfter(membersLastUpdated.plusSeconds(REFRESH_MEMBERS_EVERY_SECONDS))); } }