Skip to content

Commit c8b666d

Browse files
committed
Feat: Added WebSocket client for chat crawling feature.
1 parent da71d3c commit c8b666d

11 files changed

+486
-4
lines changed

.idea/gradle.xml

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package net.ledestudio.acc.client;
2+
3+
import com.google.common.collect.Sets;
4+
import net.ledestudio.acc.http.AccHttpRequestResult;
5+
import net.ledestudio.acc.http.AccHttpResponseType;
6+
import org.java_websocket.client.WebSocketClient;
7+
import org.java_websocket.drafts.Draft;
8+
import org.java_websocket.handshake.ServerHandshake;
9+
import org.jetbrains.annotations.NotNull;
10+
11+
import java.nio.ByteBuffer;
12+
import java.util.Set;
13+
import java.util.logging.Logger;
14+
15+
public class AccClient extends WebSocketClient {
16+
17+
private final Logger logger;
18+
private final AccHttpRequestResult result;
19+
20+
private final Set<AccClientHandler> handlers = Sets.newHashSet();
21+
22+
public AccClient(@NotNull AccHttpRequestResult result, @NotNull Draft protocolDraft) {
23+
super(result.toWebSocketURI(), protocolDraft);
24+
this.result = result;
25+
this.logger = Logger.getLogger(String.format("AccClient:%s", result.get(AccHttpResponseType.BID)));
26+
}
27+
28+
public void addHandler(@NotNull AccClientHandler handler) {
29+
handler.init(this, result.clone(), logger);
30+
handlers.add(handler);
31+
}
32+
33+
public void removeHandler(@NotNull AccClientHandler handler) {
34+
handlers.remove(handler);
35+
}
36+
37+
public Set<AccClientHandler> getHandlers() {
38+
return Sets.newHashSet(handlers);
39+
}
40+
41+
@Override
42+
public void onOpen(ServerHandshake handshake) {
43+
handlers.forEach(handler -> handler.onOpen(handshake));
44+
}
45+
46+
@Override
47+
public void onClose(int code, String reason, boolean remote) {
48+
handlers.forEach(handler -> handler.onClose(code, reason, remote));
49+
}
50+
51+
@Override
52+
public void onMessage(String message) {
53+
handlers.forEach(handler -> handler.onMessage(message));
54+
55+
// decode message
56+
AccMessageDecoder decoder = new AccMessageDecoder(message);
57+
DecodedMessage decodedMessage = decoder.decode();
58+
handlers.forEach(handler -> handler.onMessageDecoded(decodedMessage));
59+
}
60+
61+
@Override
62+
public void onMessage(ByteBuffer bytes) {
63+
handlers.forEach(handler -> handler.onMessage(bytes));
64+
}
65+
66+
@Override
67+
public void onError(Exception ex) {
68+
handlers.forEach(handler -> handler.onError(ex));
69+
}
70+
71+
public Logger getLogger() {
72+
return logger;
73+
}
74+
75+
public AccHttpRequestResult getResult() {
76+
return result.clone();
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package net.ledestudio.acc.client;
2+
3+
import net.ledestudio.acc.http.AccHttpRequestResult;
4+
import org.java_websocket.handshake.ServerHandshake;
5+
import org.jetbrains.annotations.NotNull;
6+
import org.jetbrains.annotations.Nullable;
7+
8+
import java.nio.ByteBuffer;
9+
import java.util.logging.Logger;
10+
11+
public abstract class AccClientHandler {
12+
13+
private @Nullable AccClient client;
14+
private @Nullable AccHttpRequestResult result;
15+
private @Nullable Logger logger;
16+
17+
public void init(@NotNull AccClient client, @NotNull AccHttpRequestResult result, @NotNull Logger logger) {
18+
this.client = client;
19+
this.result = result;
20+
this.logger = logger;
21+
}
22+
23+
public @NotNull AccClient getClient() {
24+
if (client == null) {
25+
throw new NullPointerException("Accessing uninitialized fields in AccClientHandler without calling the init method.");
26+
}
27+
return client;
28+
}
29+
30+
public @NotNull AccHttpRequestResult getResult() {
31+
if (result == null) {
32+
throw new NullPointerException("Accessing uninitialized fields in AccClientHandler without calling the init method.");
33+
}
34+
return result;
35+
}
36+
37+
public @NotNull Logger getLogger() {
38+
if (logger == null) {
39+
throw new NullPointerException("Accessing uninitialized fields in AccClientHandler without calling the init method.");
40+
}
41+
return logger;
42+
}
43+
44+
public abstract void onOpen(@NotNull ServerHandshake handshake);
45+
46+
public abstract void onClose(int code, @NotNull String reason, boolean remote);
47+
48+
public abstract void onMessage(@NotNull String message);
49+
50+
public abstract void onMessage(@NotNull ByteBuffer bytes);
51+
52+
public abstract void onMessageDecoded(@NotNull AccMessage message);
53+
54+
public abstract void onError(@NotNull Exception ex);
55+
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package net.ledestudio.acc.client;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
5+
import java.time.ZoneId;
6+
import java.time.ZonedDateTime;
7+
8+
public interface AccMessage {
9+
10+
@NotNull String getSenderId();
11+
12+
@NotNull String getSenderNickname();
13+
14+
@NotNull String getMessage();
15+
16+
@NotNull ZonedDateTime getTimestamp(@NotNull ZoneId zone);
17+
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package net.ledestudio.acc.client;
2+
3+
import net.ledestudio.acc.util.AccConstants;
4+
import org.jetbrains.annotations.NotNull;
5+
6+
public class AccMessageDecoder {
7+
8+
9+
10+
private final String textToDecode;
11+
12+
public AccMessageDecoder(String textToDecode) {
13+
this.textToDecode = textToDecode;
14+
}
15+
16+
public @NotNull DecodedMessage decode() {
17+
String[] parts = textToDecode.split(AccConstants.F);
18+
if (parts.length > 5 && !parts[1].equals("-1") && !parts[1].equals("1") && !parts[1].contains("|")) {
19+
String senderId = parts[2];
20+
String senderNickname = parts[6];
21+
String message = parts[1];
22+
return new DecodedMessage(senderId, senderNickname, message);
23+
}
24+
return new DecodedMessage();
25+
}
26+
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package net.ledestudio.acc.client;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
5+
import java.time.ZoneId;
6+
import java.time.ZonedDateTime;
7+
8+
public class DecodedMessage implements AccMessage {
9+
10+
private final @NotNull String senderId;
11+
private final @NotNull String senderNickname;
12+
private final @NotNull String message;
13+
14+
private final @NotNull ZonedDateTime timestamp = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
15+
16+
public DecodedMessage() {
17+
this.senderId = "";
18+
this.senderNickname = "";
19+
this.message = "";
20+
}
21+
22+
public DecodedMessage(@NotNull String senderId, @NotNull String senderNickname, @NotNull String message) {
23+
this.senderId = senderId;
24+
this.senderNickname = senderNickname;
25+
this.message = message;
26+
}
27+
28+
@Override
29+
public @NotNull String getSenderId() {
30+
return senderId;
31+
}
32+
33+
@Override
34+
public @NotNull String getSenderNickname() {
35+
return senderNickname;
36+
}
37+
38+
@Override
39+
public @NotNull String getMessage() {
40+
return message;
41+
}
42+
43+
@Override
44+
public @NotNull ZonedDateTime getTimestamp(@NotNull ZoneId zone) {
45+
return timestamp;
46+
}
47+
}

src/main/java/net/ledestudio/acc/http/AccHttpRequestResult.java

+24-4
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@
1010

1111
public class AccHttpRequestResult extends HashMap<AccHttpResponseType, String> {
1212

13-
public @NotNull URI toWebSocketURI() throws URISyntaxException {
14-
return new URI(toWebSocketUrlString());
13+
public @NotNull URI toWebSocketURI() {
14+
try {
15+
return new URI(toWebSocketUrlString());
16+
} catch (URISyntaxException e) {
17+
throw new RuntimeException(e);
18+
}
1519
}
1620

17-
public @NotNull URL toWebSocketURL() throws MalformedURLException {
18-
return new URL(toWebSocketUrlString());
21+
public @NotNull URL toWebSocketURL() {
22+
try {
23+
return new URL(toWebSocketUrlString());
24+
} catch (MalformedURLException e) {
25+
throw new RuntimeException(e);
26+
}
1927
}
2028

2129
public @NotNull String toWebSocketUrlString() {
@@ -27,4 +35,16 @@ public class AccHttpRequestResult extends HashMap<AccHttpResponseType, String> {
2735
);
2836
}
2937

38+
@Override
39+
public String toString() {
40+
StringBuilder sb = new StringBuilder();
41+
this.forEach((key, value) -> sb.append(key).append(":").append(value).append("\n"));
42+
return sb.toString();
43+
}
44+
45+
@Override
46+
public AccHttpRequestResult clone() {
47+
return (AccHttpRequestResult) super.clone();
48+
}
49+
3050
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package net.ledestudio.acc.service;
2+
3+
import net.ledestudio.acc.client.AccClientHandler;
4+
import net.ledestudio.acc.client.AccMessage;
5+
import org.java_websocket.handshake.ServerHandshake;
6+
import org.jetbrains.annotations.NotNull;
7+
8+
import java.nio.ByteBuffer;
9+
10+
public class AfreecaTvChatClientHandler extends AccClientHandler {
11+
12+
@Override
13+
public void onOpen(@NotNull ServerHandshake handshake) {
14+
getLogger().info("Open connection");
15+
}
16+
17+
@Override
18+
public void onClose(int code, @NotNull String reason, boolean remote) {
19+
getLogger().info("close connection");
20+
}
21+
22+
@Override
23+
public void onMessage(@NotNull String message) {
24+
getLogger().info("receive message : " + message);
25+
}
26+
27+
@Override
28+
public void onMessage(@NotNull ByteBuffer bytes) {
29+
getLogger().info("receive byte message : " + bytes);
30+
}
31+
32+
@Override
33+
public void onMessageDecoded(@NotNull AccMessage message) {
34+
getLogger().info("decode message : " + message);
35+
}
36+
37+
@Override
38+
public void onError(@NotNull Exception ex) {
39+
ex.printStackTrace();
40+
}
41+
42+
}

0 commit comments

Comments
 (0)