Skip to content

Commit 9efff49

Browse files
committed
feat(client): finish api connection
1 parent dc2dbcc commit 9efff49

File tree

11 files changed

+470
-13
lines changed

11 files changed

+470
-13
lines changed

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Exterminator3618
22

3-
[![Release - JAR](https://github.com/im-yuuki/Exterminator3618/actions/workflows/build-jar.yml/badge.svg?event=release)](https://github.com/im-yuuki/Exterminator3618/actions/workflows/build-jar.yml)
4-
[![Testing](https://github.com/im-yuuki/Exterminator3618/actions/workflows/build-jar.yml/badge.svg?event=release)](https://github.com/im-yuuki/Exterminator3618/actions/workflows/build-jar.yml)
3+
[![Build JAR executable](https://github.com/im-yuuki/Exterminator3618/actions/workflows/build-jar.yml/badge.svg?branch=master&event=pull_request)](https://github.com/im-yuuki/Exterminator3618/actions/workflows/build-jar.yml)
4+
[![Run Tests](https://github.com/im-yuuki/Exterminator3618/actions/workflows/run-test.yml/badge.svg?event=pull_request)](https://github.com/im-yuuki/Exterminator3618/actions/workflows/run-test.yml)
55

66
*This game is our team project for the Object-Oriented Programming course at the University of Engineering and Technology (UET), Vietnam National University.*
77

@@ -47,14 +47,14 @@
4747
- [Maven](https://maven.apache.org/) - A build automation tool used primarily for Java projects.
4848

4949
## 🏫 Team members
50-
- @maaL6 Tran Duc Lam (24020197) - Team leader
51-
- @im-yuuki Le Dang Ngo Dan (24020054)
52-
- @BakaAfk Nguyen Xuan Bac (24020036)
53-
- @ngocmai3438 Pham Ngoc Mai (24020216)
50+
- [@maaL6](https://github.com/maaL6) Tran Duc Lam (24020197) - Team leader
51+
- [@im-yuuki](https://github.com/im-yuuki) Le Dang Ngo Dan (24020054)
52+
- [@BakaAfk](https://github.com/BakaAfk) Nguyen Xuan Bac (24020036)
53+
- [@ngocmai3438](https://github.com/ngocmai3438) Pham Ngoc Mai (24020216)
5454

5555
*📀 We keep track of the progress in this [GitHub Project](https://github.com/users/im-yuuki/projects/2) site.*
5656

57-
## 📝Architecture diagram (commit f0d4f1af5df58d55fbd364bf59d84c60aeb72d3c)
57+
## 📝Architecture diagram (commit [f7dc12f](https://github.com/im-yuuki/Exterminator3618/commit/f7dc12f3b6e74535f66ee6e4a68f829b551fe659))
5858

5959
### Client
6060
![Client](.github/images/io.exterminator3618.client.png)

client/src/main/java/io/exterminator3618/client/api/ApiClient.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ public class ApiClient implements FriendsApi, MatchApi, UserApi {
2323
protected final UserInfo userInfo = new UserInfo();
2424
protected final ArrayList<UserInfo> friendsList = new ArrayList<>();
2525

26+
protected boolean inMatch = false;
27+
protected ArrayList<MatchInvite> matchInvites = new ArrayList<>();
28+
protected RoomStatus roomStatus = null;
29+
2630
private ApiClient(Exterminator3618 game, HttpClient httpClient) {
2731
this.game = game;
2832
this.httpClient = httpClient;
@@ -146,4 +150,34 @@ private static HttpClient createHttpClient(CookieManager cookieManager) {
146150
.build();
147151
}
148152

153+
@Override
154+
public ArrayList<UserInfo> getFriendsList() {
155+
return friendsList;
156+
}
157+
158+
@Override
159+
public boolean isInMatch() {
160+
return inMatch;
161+
}
162+
163+
@Override
164+
public void setInMatch(boolean inMatch) {
165+
this.inMatch = inMatch;
166+
}
167+
168+
@Override
169+
public ArrayList<MatchInvite> getMatchInvites() {
170+
return matchInvites;
171+
}
172+
173+
@Override
174+
public RoomStatus getRoomStatus() {
175+
return roomStatus;
176+
}
177+
178+
@Override
179+
public void setRoomStatus(RoomStatus roomStatus) {
180+
this.roomStatus = roomStatus;
181+
}
182+
149183
}

client/src/main/java/io/exterminator3618/client/api/DataProcessor.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ public static String jsonSerializeObject(Object o) {
2424
}
2525
}
2626

27+
public static <T> T jsonDeserializeObject(String json, Class<T> valueType) {
28+
try {
29+
return mapper.readValue(json, valueType);
30+
} catch (JsonProcessingException e) {
31+
throw new RuntimeException(e);
32+
}
33+
}
34+
2735
public static HttpResponse.BodyHandler<JsonResponse> getJsonResponseHandler() {
2836
return responseInfo -> {
2937
int code = responseInfo.statusCode();
@@ -56,4 +64,36 @@ public static HttpResponse.BodyHandler<OperationResponse> getOperationResponseHa
5664
};
5765
}
5866

67+
public static HttpResponse.BodyHandler<FriendListResponse> getFriendListResponseHandler() {
68+
return responseInfo -> {
69+
int code = responseInfo.statusCode();
70+
return HttpResponse.BodySubscribers.mapping(
71+
HttpResponse.BodySubscribers.ofString(Charset.defaultCharset()),
72+
body -> {
73+
try {
74+
return mapper.readValue(body, FriendListResponse.class);
75+
} catch (Exception e) {
76+
throw new JsonParseError(code, "Invalid JSON", e);
77+
}
78+
}
79+
);
80+
};
81+
}
82+
83+
public static HttpResponse.BodyHandler<RoomStatus> getRoomStatusResponseHandler() {
84+
return responseInfo -> {
85+
int code = responseInfo.statusCode();
86+
return HttpResponse.BodySubscribers.mapping(
87+
HttpResponse.BodySubscribers.ofString(Charset.defaultCharset()),
88+
body -> {
89+
try {
90+
return mapper.readValue(body, RoomStatus.class);
91+
} catch (Exception e) {
92+
throw new JsonParseError(code, "Invalid JSON", e);
93+
}
94+
}
95+
);
96+
};
97+
}
98+
5999
}
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package io.exterminator3618.client.api;
22

3-
public class FriendListResponse {
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
5+
import java.util.ArrayList;
6+
7+
@JsonIgnoreProperties(ignoreUnknown = true)
8+
public class FriendListResponse extends ArrayList<UserInfo> {
49

510
}

client/src/main/java/io/exterminator3618/client/api/FriendsApi.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,39 @@
11
package io.exterminator3618.client.api;
22

3-
import org.slf4j.Logger;
4-
53
import java.io.IOException;
64
import java.net.http.HttpRequest;
75
import java.net.http.HttpResponse;
86
import java.util.ArrayList;
9-
import java.util.List;
107

118
interface FriendsApi extends HttpConnection {
129

13-
default boolean getFriendsList() {
10+
default boolean fetchFriendsList() {
1411
HttpRequest req = createGetRequest("/friends/list");
12+
try {
13+
HttpResponse<FriendListResponse> res = getHttpClient().send(req, DataProcessor.getFriendListResponseHandler());
14+
if (res.statusCode() != 200) {
15+
getLogger().error("Get friends list failed with status code {}", res.statusCode());
16+
} else {
17+
ArrayList<UserInfo> friends = getFriendsList();
18+
friends.clear();
19+
friends.addAll(res.body());
20+
friends.sort((a, b) -> {
21+
int aPoint = 0, bPoint = 0;
22+
aPoint += a.isOnline() ? 1 : 0;
23+
bPoint += b.isOnline() ? 1 : 0;
24+
aPoint += a.isInMatch() ? 1 : 0;
25+
bPoint += b.isInMatch() ? 1 : 0;
26+
if (aPoint == bPoint) {
27+
return a.getUsername().compareToIgnoreCase(b.getUsername());
28+
} else {
29+
return Integer.compare(bPoint, aPoint);
30+
}
31+
});
32+
return true;
33+
}
34+
} catch (IOException | InterruptedException e) {
35+
getLogger().error("Get friends list failed", e);
36+
}
1537
return false;
1638
}
1739

@@ -56,4 +78,6 @@ default boolean removeFriend(String friendUsername) throws IOException, Interrup
5678
return false;
5779
}
5880

81+
ArrayList<UserInfo> getFriendsList();
82+
5983
}

client/src/main/java/io/exterminator3618/client/api/HttpConnection.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ default HttpRequest createGetRequest(String endpoint) {
2323
.build();
2424
}
2525

26+
default HttpRequest createPostRequest(String endpoint) {
27+
return HttpRequest.newBuilder()
28+
.uri(URI.create(getBaseServerUrl() + endpoint))
29+
.POST(HttpRequest.BodyPublishers.noBody())
30+
.timeout(Duration.ofSeconds(6))
31+
.build();
32+
}
33+
2634
default HttpRequest createJsonPostRequest(String endpoint, Object body) {
2735
String serializedBody = DataProcessor.jsonSerializeObject(body);
2836
return HttpRequest.newBuilder()
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,170 @@
11
package io.exterminator3618.client.api;
22

3+
import java.net.http.HttpRequest;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
37
public interface MatchApi extends HttpConnection {
48

9+
default boolean fetchStatus() {
10+
HttpRequest req = createGetRequest("/match/status");
11+
try {
12+
var response = getHttpClient().send(req, DataProcessor.getJsonResponseHandler());
13+
if (response.statusCode() == 200) {
14+
setInMatch((Boolean) response.body().get("inMatch"));
15+
Object[] invites = (Object[]) response.body().get("matchInvite");
16+
getMatchInvites().clear();
17+
for (Object invite : invites) {
18+
MatchInvite mi = DataProcessor.jsonDeserializeObject(
19+
DataProcessor.jsonSerializeObject(invite),
20+
MatchInvite.class
21+
);
22+
getMatchInvites().add(mi);
23+
}
24+
return true;
25+
} else {
26+
getLogger().error("Failed to fetch match status. HTTP Status: {}", response.statusCode());
27+
}
28+
} catch (Exception e) {
29+
getLogger().error("Exception while fetching match status", e);
30+
}
31+
return false;
32+
}
33+
34+
default boolean inviteFriendToMatch(String friendUsername) {
35+
HttpRequest req = createJsonPostRequest("/match/invite", new Object() {
36+
public final String friendAccountUsername = friendUsername;
37+
});
38+
try {
39+
var res = getHttpClient().send(req, DataProcessor.getOperationResponseHandler());
40+
if (res.statusCode() != 200) {
41+
getLogger().error("Invite {} failed with status code {}", friendUsername, res.statusCode());
42+
} else if (!res.body().isSuccess()) {
43+
getLogger().error("Invite {} failed: {}", friendUsername, res.body().getMessage());
44+
} else {
45+
getLogger().info("Invited {}", friendUsername);
46+
return true;
47+
}
48+
} catch (Exception e) {
49+
getLogger().error("Exception while inviting friend {} to match", friendUsername, e);
50+
}
51+
return false;
52+
}
53+
54+
default boolean acceptInvite(String friendUsername) {
55+
HttpRequest req = createJsonPostRequest("/match/acceptInvite", new Object() {
56+
public final String friendAccountUsername = friendUsername;
57+
});
58+
try {
59+
var res = getHttpClient().send(req, DataProcessor.getOperationResponseHandler());
60+
if (res.statusCode() != 200) {
61+
getLogger().error("Accept invite from {} failed with status code {}", friendUsername, res.statusCode());
62+
} else if (!res.body().isSuccess()) {
63+
getLogger().error("Accept invite from {} failed: {}", friendUsername, res.body().getMessage());
64+
} else {
65+
getLogger().info("Accepted invite from {}", friendUsername);
66+
return true;
67+
}
68+
} catch (Exception e) {
69+
getLogger().error("Exception while accepting invite from {}", friendUsername, e);
70+
}
71+
return false;
72+
}
73+
74+
default boolean joinQueue() {
75+
HttpRequest req = createPostRequest("/match/joinQueue");
76+
try {
77+
var res = getHttpClient().send(req, DataProcessor.getOperationResponseHandler());
78+
if (res.statusCode() != 200) {
79+
getLogger().error("Join queue failed with status code {}", res.statusCode());
80+
} else if (!res.body().isSuccess()) {
81+
getLogger().error("Join queue failed: {}", res.body().getMessage());
82+
} else {
83+
getLogger().info("Joined match queue");
84+
return true;
85+
}
86+
} catch (Exception e) {
87+
getLogger().error("Exception while joining match queue", e);
88+
}
89+
return false;
90+
}
91+
92+
default boolean leaveQueue() {
93+
HttpRequest req = createPostRequest("/match/leaveQueue");
94+
try {
95+
var res = getHttpClient().send(req, DataProcessor.getOperationResponseHandler());
96+
if (res.statusCode() != 200) {
97+
getLogger().error("Leave queue failed with status code {}", res.statusCode());
98+
} else if (!res.body().isSuccess()) {
99+
getLogger().error("Leave queue failed: {}", res.body().getMessage());
100+
} else {
101+
getLogger().info("Left match queue");
102+
return true;
103+
}
104+
} catch (Exception e) {
105+
getLogger().error("Exception while leaving match queue", e);
106+
}
107+
return false;
108+
}
109+
110+
default boolean fetchRoomStatus() {
111+
HttpRequest req = createGetRequest("/match/roomStatus");
112+
try {
113+
var response = getHttpClient().send(req, DataProcessor.getRoomStatusResponseHandler());
114+
if (response.statusCode() == 200) {
115+
setRoomStatus(response.body());
116+
return true;
117+
} else {
118+
getLogger().error("Failed to fetch match room status. HTTP Status: {}", response.statusCode());
119+
}
120+
} catch (Exception e) {
121+
getLogger().error("Exception while fetching match room status", e);
122+
}
123+
return false;
124+
}
125+
126+
default boolean pushGameEvents(List<String> data) {
127+
HttpRequest req = createJsonPostRequest("/match/pushGameEvents", new Object() {
128+
public final String[] list = data.toArray(new String[] {});
129+
});
130+
try {
131+
var res = getHttpClient().send(req, DataProcessor.getOperationResponseHandler());
132+
if (res.statusCode() != 200) {
133+
getLogger().error("Push game events failed with status code {}", res.statusCode());
134+
} else if (!res.body().isSuccess()) {
135+
getLogger().error("Push game events failed: {}", res.body().getMessage());
136+
} else {
137+
getLogger().info("Pushed {} game events", data.size());
138+
return true;
139+
}
140+
} catch (Exception e) {
141+
getLogger().error("Exception while pushing game events", e);
142+
}
143+
return false;
144+
}
145+
146+
default boolean leaveRoom() {
147+
HttpRequest req = createPostRequest("/match/leaveRoom");
148+
try {
149+
var res = getHttpClient().send(req, DataProcessor.getOperationResponseHandler());
150+
if (res.statusCode() != 200) {
151+
getLogger().error("Leave room failed with status code {}", res.statusCode());
152+
} else if (!res.body().isSuccess()) {
153+
getLogger().error("Leave room failed: {}", res.body().getMessage());
154+
} else {
155+
getLogger().info("Left match room");
156+
return true;
157+
}
158+
} catch (Exception e) {
159+
getLogger().error("Exception while leaving match room", e);
160+
}
161+
return false;
162+
}
163+
164+
boolean isInMatch();
165+
void setInMatch(boolean inMatch);
166+
ArrayList<MatchInvite> getMatchInvites();
167+
RoomStatus getRoomStatus();
168+
void setRoomStatus(RoomStatus roomStatus);
169+
5170
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package io.exterminator3618.client.api;
2+
3+
public record MatchInvite(String fromPlayerName, String fromPlayerUsername) {
4+
5+
}

0 commit comments

Comments
 (0)