Skip to content

Commit 9d88534

Browse files
committed
Significant change of ChatBot interface
1 parent 1248b6b commit 9d88534

File tree

7 files changed

+191
-86
lines changed

7 files changed

+191
-86
lines changed
Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,29 @@
11
package net.zomis.duga.chat;
22

33
import java.util.List;
4+
import java.util.concurrent.Future;
45

56
public interface ChatBot {
67

7-
void postDebug(String message);
8-
void postChat(WebhookParameters params, List<String> messages);
8+
Future<List<ChatMessageResponse>> postChat(WebhookParameters params, List<String> messages);
99

1010
void postSingle(WebhookParameters params, String message);
11+
12+
Future<ChatMessageResponse> postAsync(ChatMessage message);
13+
14+
/**
15+
* Try to post a message once and return result no matter what the response is
16+
* @return Response with details of success or error
17+
*/
18+
ChatMessageResponse postNowOnce(ChatMessage message);
19+
20+
/**
21+
* Repeatedly try to post a message until either success or a serious error occurs.
22+
* @return Response with details of success or error
23+
*/
24+
ChatMessageResponse postNow(ChatMessage message);
25+
26+
void start();
27+
28+
void stop();
1129
}

duga-core/src/main/java/net/zomis/duga/chat/ChatMessage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import com.gistlabs.mechanize.document.json.JsonDocument;
66

7-
class ChatMessage {
7+
public class ChatMessage {
88

99
private final String room;
1010
private final String message;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package net.zomis.duga.chat;
2+
3+
public class ChatMessageResponse {
4+
5+
private final long id;
6+
private final long time;
7+
private final String fullResponse;
8+
private final Exception exception;
9+
10+
public ChatMessageResponse(long id, long time, String fullResponse) {
11+
this.id = id;
12+
this.time = time;
13+
this.fullResponse = fullResponse;
14+
this.exception = null;
15+
}
16+
17+
public ChatMessageResponse(String fullResponse, Exception exception) {
18+
this.id = 0;
19+
this.time = 0;
20+
this.fullResponse = fullResponse;
21+
this.exception = exception;
22+
}
23+
24+
public long getId() {
25+
return id;
26+
}
27+
28+
public long getTime() {
29+
return time;
30+
}
31+
32+
public String getFullResponse() {
33+
return fullResponse;
34+
}
35+
36+
public Exception getException() {
37+
return exception;
38+
}
39+
40+
public boolean hasException() {
41+
return exception != null;
42+
}
43+
44+
}

duga-core/src/main/java/net/zomis/duga/chat/StackExchangeChatBot.java

Lines changed: 84 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
11
package net.zomis.duga.chat;
22

3-
import java.io.UncheckedIOException;
43
import java.io.UnsupportedEncodingException;
5-
import java.net.URI;
64
import java.util.*;
7-
import java.util.concurrent.BlockingQueue;
8-
import java.util.concurrent.ExecutorService;
9-
import java.util.concurrent.Executors;
10-
import java.util.concurrent.LinkedBlockingQueue;
11-
import java.util.concurrent.TimeUnit;
5+
import java.util.concurrent.*;
126
import java.util.logging.Level;
137
import java.util.logging.Logger;
148
import java.util.stream.Collectors;
159

1610
import org.apache.http.HttpRequest;
1711
import org.apache.http.HttpResponse;
1812
import org.apache.http.ProtocolException;
19-
import org.apache.http.client.RedirectHandler;
2013
import org.apache.http.client.RedirectStrategy;
2114
import org.apache.http.client.methods.HttpGet;
2215
import org.apache.http.client.methods.HttpUriRequest;
@@ -30,13 +23,11 @@
3023
import com.gistlabs.mechanize.document.json.JsonDocument;
3124
import com.gistlabs.mechanize.impl.MechanizeAgent;
3225

33-
/**
34-
* @author Frank van Heeswijk
35-
* @author Simon Forsberg
36-
*/
37-
public class StackExchangeChatBot {
26+
public class StackExchangeChatBot implements ChatBot {
3827

3928
private final static Logger LOGGER = Logger.getLogger(StackExchangeChatBot.class.getSimpleName());
29+
30+
@Deprecated
4031
private static final WebhookParameters debugRoom = WebhookParameters.toRoom("20298");
4132

4233
private static final int MAX_MESSAGE_LENGTH = 500;
@@ -49,9 +40,6 @@ public class StackExchangeChatBot {
4940

5041
private final BotConfiguration configuration;
5142

52-
// @Autowired
53-
// private ConfigService configService;
54-
5543
private String chatFKey;
5644

5745
private String undeployGoodbyeText;
@@ -173,9 +161,9 @@ private String retrieveFKey() {
173161
return joinForm.get("fkey").getValue();
174162
}
175163

176-
public void postMessages(WebhookParameters params, final List<String> messages) {
164+
public Future<List<ChatMessageResponse>> postMessages(WebhookParameters params, final List<String> messages) {
177165
if (params == null) {
178-
params = new WebhookParameters();
166+
throw new NullPointerException("Params cannot be null, unable to post " + messages);
179167
}
180168
// params.useDefaultRoom(configuration.getRoomId());
181169
Objects.requireNonNull(messages, "messages");
@@ -196,84 +184,114 @@ public void postMessages(WebhookParameters params, final List<String> messages)
196184
for (ChatMessage message : shortenedMessages) {
197185
LOGGER.info("Ignoring message for " + message.getRoom() + ": " + message.getMessage());
198186
}
199-
return;
187+
return null;
200188
}
201189

202190
System.out.println("Adding messages to queue: " + shortenedMessages);
203191
messagesQueue.add(shortenedMessages);
192+
return null;
204193
}
205194

206195
private void attemptPostMessageToChat(final ChatMessage message) {
207196
System.out.println("Real message post: " + message);
208197
Objects.requireNonNull(message, "message");
209-
try {
210-
postMessageToChat(message);
211-
} catch (ChatThrottleException ex) {
198+
ChatMessageResponse response = postMessageToChat(message);
199+
if (response.getException() instanceof ChatThrottleException) {
200+
ChatThrottleException ex = (ChatThrottleException) response.getException();
212201
System.out.println("Chat throttle");
213202
LOGGER.info("Sleeping for " + ex.getThrottleTiming() + " seconds, then reposting");
214203
try {
215204
TimeUnit.SECONDS.sleep(ex.getThrottleTiming());
216205
} catch(InterruptedException ex1) {
217206
Thread.currentThread().interrupt();
218207
}
219-
try {
220-
postMessageToChat(message);
221-
} catch (ChatThrottleException | ProbablyNotLoggedInException ex1) {
222-
LOGGER.log(Level.INFO, "Failed to post message on retry", ex1);
223-
}
224-
} catch (ProbablyNotLoggedInException ex) {
208+
ChatMessageResponse response2 = postMessageToChat(message);
209+
if (response2.hasException()) {
210+
LOGGER.log(Level.SEVERE, "Failed to post message on retry", response2.getException());
211+
}
212+
}
213+
if (response.getException() instanceof ProbablyNotLoggedInException) {
225214
System.out.println("Probably not logged in");
226215
LOGGER.info("Not logged in, logging in and then reposting");
227216
login();
228-
try {
229-
postMessageToChat(message);
230-
} catch (ChatThrottleException | ProbablyNotLoggedInException ex1) {
231-
LOGGER.log(Level.INFO, "Failed to post message on retry", ex1);
232-
}
217+
ChatMessageResponse response2 = postMessageToChat(message);
218+
if (response2.hasException()) {
219+
LOGGER.log(Level.SEVERE, "Failed to post message on retry", response2.getException());
220+
}
233221
}
234222
}
235223

236-
private void postMessageToChat(final ChatMessage message) throws ChatThrottleException, ProbablyNotLoggedInException {
224+
@Override
225+
public Future<List<ChatMessageResponse>> postChat(WebhookParameters params, List<String> messages) {
226+
return postMessages(params, messages);
227+
}
228+
229+
@Override
230+
public void postSingle(WebhookParameters params, String message) {
231+
postChat(params, Collections.singletonList(message));
232+
}
233+
234+
@Override
235+
public Future<ChatMessageResponse> postAsync(ChatMessage message) {
236+
this.messagesQueue.add(Collections.singletonList(message));
237+
return null;
238+
}
239+
240+
@Override
241+
public ChatMessageResponse postNowOnce(ChatMessage message) {
242+
return postMessageToChat(message);
243+
}
244+
245+
@Override
246+
public ChatMessageResponse postNow(ChatMessage message) {
247+
return null;
248+
}
249+
250+
private ChatMessageResponse postMessageToChat(final ChatMessage message) {
237251
Objects.requireNonNull(message, "message");
238252
Map<String, String> parameters = new HashMap<>();
239253
String text = message.getMessage();
240254
text = text.replaceAll("access_token=([0-9a-f]+)", "access_token=xxxxxxxxxxxxxx");
241255
parameters.put("text", text);
242256
parameters.put("fkey", this.chatFKey);
243257
System.out.println("Okay, here we go!");
258+
Resource response;
244259
try {
245-
Resource response = agent.post("http://chat.stackexchange.com/chats/" + message.getRoom() + "/messages/new", parameters);
246-
System.out.println("Response: " + response.getTitle());
247-
if (response instanceof JsonDocument) {
248-
System.out.println(response);
249-
JsonDocument json = (JsonDocument) response;
250-
System.out.println("Success: " + json.getRoot());
251-
message.onSuccess((JsonDocument) response);
252-
} else if (response instanceof HtmlDocument) {
253-
//failure
254-
HtmlDocument htmlDocument = (HtmlDocument) response;
255-
System.out.println("Failure: " + htmlDocument);
256-
HtmlElement body = htmlDocument.find("body");
257-
if (body.getInnerHtml().contains("You can perform this action again in")) {
258-
int timing =
259-
Integer.parseInt(body.getInnerHtml().replaceAll("You can perform this action again in", "")
260-
.replaceAll("seconds", "").trim());
261-
throw new ChatThrottleException(timing);
262-
}
263-
else {
264-
System.out.println(body.getInnerHtml());
265-
throw new ProbablyNotLoggedInException();
266-
}
267-
}
268-
else {
269-
System.out.println("Uknown response: " + response);
270-
//even harder failure
271-
throw new IllegalStateException("unexpected response, response.getClass() = " + response.getClass());
272-
}
273-
} catch(UnsupportedEncodingException ex) {
274-
System.out.println("Unsupported encoding: " + ex);
275-
throw new UncheckedIOException(ex);
276-
}
260+
response = agent.post("http://chat.stackexchange.com/chats/" +
261+
message.getRoom() + "/messages/new", parameters);
262+
} catch (UnsupportedEncodingException e) {
263+
return new ChatMessageResponse(e.toString(), e);
264+
}
265+
266+
System.out.println("Response: " + response.getTitle());
267+
if (response instanceof JsonDocument) {
268+
System.out.println(response);
269+
JsonDocument json = (JsonDocument) response;
270+
System.out.println("Success: " + json.getRoot());
271+
message.onSuccess(json);
272+
return new ChatMessageResponse(Long.parseLong(json.getRoot().getChild("id").getValue()),
273+
Long.parseLong(json.getRoot().getChild("time").getValue()), json.getRoot().toString());
274+
}
275+
276+
if (response instanceof HtmlDocument) {
277+
//failure
278+
HtmlDocument htmlDocument = (HtmlDocument) response;
279+
System.out.println("Failure: " + htmlDocument);
280+
HtmlElement body = htmlDocument.find("body");
281+
if (body.getInnerHtml().contains("You can perform this action again in")) {
282+
int timing =
283+
Integer.parseInt(body.getInnerHtml().replaceAll("You can perform this action again in", "")
284+
.replaceAll("seconds", "").trim());
285+
return new ChatMessageResponse(body.getInnerHtml(), new ChatThrottleException(timing));
286+
}
287+
288+
System.out.println(body.getInnerHtml());
289+
return new ChatMessageResponse(body.getInnerHtml(), new ProbablyNotLoggedInException());
290+
}
291+
292+
System.out.println("Unknown response: " + response);
293+
//even harder failure
294+
throw new IllegalStateException("unexpected response, response.getClass() = " + response.getClass());
277295
}
278296

279297
public void stop() {

duga-core/src/main/java/net/zomis/duga/chat/WebhookParameters.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
public class WebhookParameters {
44

55
private String roomId;
6+
7+
/**
8+
* Used for webhooks that want to be in the statistics but not post to a room
9+
*/
610
private Boolean post;
711

812
public String getRoomId() {
@@ -13,12 +17,6 @@ public void setRoomId(String roomId) {
1317
this.roomId = roomId;
1418
}
1519

16-
public void useDefaultRoom(String defaultRoomId) {
17-
if (roomId == null) {
18-
roomId = defaultRoomId;
19-
}
20-
}
21-
2220
public boolean getPost() {
2321
return post == null ? true : post;
2422
}
@@ -59,5 +57,8 @@ public int hashCode() {
5957
public String toString() {
6058
return "Room " + roomId;
6159
}
62-
60+
61+
public ChatMessage message(String input) {
62+
return new ChatMessage(this, input);
63+
}
6364
}

duga-core/src/test/java/net/zomis/duga/DugaTest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package net.zomis.duga;
22

33
import net.zomis.duga.chat.BotConfiguration;
4+
import net.zomis.duga.chat.ChatBot;
45
import net.zomis.duga.chat.StackExchangeChatBot;
56
import net.zomis.duga.chat.WebhookParameters;
67

@@ -37,17 +38,17 @@ public static void main(String[] args) {
3738
config.setChatMaxBurst(2);
3839
config.setChatMinimumDelay(500);
3940
Scanner scanner = new Scanner(System.in);
40-
StackExchangeChatBot bot = new StackExchangeChatBot(config);
41+
ChatBot bot = new StackExchangeChatBot(config);
4142
System.out.println("Press enter to start bot");
4243
bot.start();
44+
WebhookParameters room = WebhookParameters.toRoom("16134");
4345
while (true) {
4446
String input = scanner.nextLine();
4547
if (input.isEmpty()) {
4648
break;
4749
}
4850
System.out.println("Input: " + input);
49-
bot.postMessages(WebhookParameters.toRoom("16134"),
50-
Collections.singletonList(input));
51+
bot.postNow(room.message(input));
5152
}
5253
bot.stop();
5354
scanner.close();

0 commit comments

Comments
 (0)