Skip to content

Commit ee74b74

Browse files
committed
feat: add PersistentServer API implementation and model classes
1 parent fd91e8b commit ee74b74

File tree

8 files changed

+827
-1
lines changed

8 files changed

+827
-1
lines changed

api/src/main/java/app/simplecloud/api/CloudApi.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import app.simplecloud.api.event.EventApi;
44
import app.simplecloud.api.group.GroupApi;
55
import app.simplecloud.api.internal.CloudApiImpl;
6+
import app.simplecloud.api.persistentserver.PersistentServerApi;
67
import app.simplecloud.api.player.PlayerApi;
78
import app.simplecloud.api.server.ServerApi;
89

@@ -82,6 +83,16 @@ static CloudApi create(CloudApiOptions options) {
8283
*/
8384
ServerApi server();
8485

86+
/**
87+
* Returns the persistent server management API.
88+
*
89+
* <p>Use this to create, read, update, and delete persistent servers.
90+
* Persistent servers are long-lived server instances that maintain state across restarts.
91+
*
92+
* @return the persistent server API
93+
*/
94+
PersistentServerApi persistentServer();
95+
8596
/**
8697
* Returns the event subscription API.
8798
*

api/src/main/java/app/simplecloud/api/internal/CloudApiImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
import app.simplecloud.api.group.GroupApi;
77
import app.simplecloud.api.internal.event.EventApiImpl;
88
import app.simplecloud.api.internal.group.GroupApiImpl;
9+
import app.simplecloud.api.internal.persistentserver.PersistentServerApiImpl;
910
import app.simplecloud.api.internal.server.ServerApiImpl;
1011
import app.simplecloud.api.internal.player.PlayerApiImpl;
12+
import app.simplecloud.api.persistentserver.PersistentServerApi;
1113
import app.simplecloud.api.player.PlayerApi;
1214
import app.simplecloud.api.server.ServerApi;
1315
import io.nats.client.Connection;
@@ -23,6 +25,7 @@ public class CloudApiImpl implements CloudApi {
2325
private final Connection natsClient;
2426
private final ServerApi serverApi;
2527
private final GroupApi groupApi;
28+
private final PersistentServerApi persistentServerApi;
2629
private final EventApi eventApi;
2730
private final PlayerApi playerApi;
2831

@@ -42,6 +45,7 @@ public CloudApiImpl(CloudApiOptions options) {
4245

4346
this.serverApi = new ServerApiImpl(options);
4447
this.groupApi = new GroupApiImpl(options);
48+
this.persistentServerApi = new PersistentServerApiImpl(options);
4549
this.eventApi = new EventApiImpl(natsClient, options.getNetworkId());
4650
this.playerApi = new PlayerApiImpl(options, natsClient);
4751
}
@@ -56,6 +60,11 @@ public ServerApi server() {
5660
return serverApi;
5761
}
5862

63+
@Override
64+
public PersistentServerApi persistentServer() {
65+
return persistentServerApi;
66+
}
67+
5968
@Override
6069
public EventApi event() {
6170
return eventApi;
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
package app.simplecloud.api.internal.persistentserver;
2+
3+
import app.simplecloud.api.CloudApiOptions;
4+
import app.simplecloud.api.group.SourceConfig;
5+
import app.simplecloud.api.group.WorkflowsConfig;
6+
import app.simplecloud.api.persistentserver.*;
7+
import app.simplecloud.api.web.ApiException;
8+
import app.simplecloud.api.web.apis.PersistentServersApi;
9+
import app.simplecloud.api.web.models.*;
10+
import org.jetbrains.annotations.Nullable;
11+
12+
import java.util.HashMap;
13+
import java.util.List;
14+
import java.util.Map;
15+
import java.util.concurrent.CompletableFuture;
16+
17+
public class PersistentServerApiImpl implements PersistentServerApi {
18+
19+
private final CloudApiOptions options;
20+
private final PersistentServersApi persistentServersApi;
21+
22+
public PersistentServerApiImpl(CloudApiOptions options) {
23+
this.options = options;
24+
this.persistentServersApi = new PersistentServersApi();
25+
this.persistentServersApi.setCustomBaseUrl(options.getControllerUrl());
26+
}
27+
28+
@Override
29+
public CompletableFuture<PersistentServer> getPersistentServerById(String id) {
30+
return CompletableFuture.supplyAsync(() -> {
31+
try {
32+
ModelsListPersistentServersResponse response = persistentServersApi.v0PersistentServersGet(
33+
options.getNetworkId(),
34+
options.getNetworkSecret()
35+
);
36+
List<ModelsPersistentServerSummary> servers = response.getPersistentServers();
37+
if (servers != null) {
38+
for (ModelsPersistentServerSummary summary : servers) {
39+
if (id.equals(summary.getPersistentServerId())) {
40+
return new PersistentServerImpl(summary);
41+
}
42+
}
43+
}
44+
throw new RuntimeException("Persistent server not found: " + id);
45+
} catch (ApiException e) {
46+
throw new RuntimeException(e);
47+
}
48+
});
49+
}
50+
51+
@Override
52+
public CompletableFuture<PersistentServer> getPersistentServerByName(String name) {
53+
return CompletableFuture.supplyAsync(() -> {
54+
try {
55+
ModelsListPersistentServersResponse response = persistentServersApi.v0PersistentServersGet(
56+
options.getNetworkId(),
57+
options.getNetworkSecret()
58+
);
59+
List<ModelsPersistentServerSummary> servers = response.getPersistentServers();
60+
if (servers != null) {
61+
for (ModelsPersistentServerSummary summary : servers) {
62+
if (name.equals(summary.getName())) {
63+
return new PersistentServerImpl(summary);
64+
}
65+
}
66+
}
67+
throw new RuntimeException("Persistent server not found: " + name);
68+
} catch (ApiException e) {
69+
throw new RuntimeException(e);
70+
}
71+
});
72+
}
73+
74+
@Override
75+
public CompletableFuture<List<PersistentServer>> getAllPersistentServers(@Nullable PersistentServerQuery query) {
76+
return CompletableFuture.supplyAsync(() -> {
77+
try {
78+
ModelsListPersistentServersResponse response = persistentServersApi.v0PersistentServersGet(
79+
options.getNetworkId(),
80+
options.getNetworkSecret()
81+
);
82+
List<ModelsPersistentServerSummary> servers = response.getPersistentServers();
83+
if (servers == null) {
84+
return List.of();
85+
}
86+
87+
List<PersistentServer> result = servers.stream()
88+
.<PersistentServer>map(PersistentServerImpl::new)
89+
.toList();
90+
91+
if (query != null) {
92+
result = result.stream()
93+
.filter(ps -> query.getActive() == null || query.getActive().equals(ps.isActive()))
94+
.filter(ps -> query.getServerhostId() == null || query.getServerhostId().equals(ps.getServerhostId()))
95+
.filter(ps -> query.getTags() == null || query.getTags().isEmpty() ||
96+
(ps.getTags() != null && query.getTags().stream().anyMatch(ps.getTags()::contains)))
97+
.toList();
98+
99+
if (query.getLimit() != null && result.size() > query.getLimit()) {
100+
result = result.subList(0, query.getLimit());
101+
}
102+
}
103+
104+
return result;
105+
} catch (ApiException e) {
106+
throw new RuntimeException(e);
107+
}
108+
});
109+
}
110+
111+
@Override
112+
public CompletableFuture<PersistentServer> createPersistentServer(CreatePersistentServerRequest request) {
113+
return CompletableFuture.supplyAsync(() -> {
114+
try {
115+
ModelsCreatePersistentServerRequest apiRequest = new ModelsCreatePersistentServerRequest();
116+
apiRequest.setName(request.getName());
117+
apiRequest.setMinMemory(request.getMinMemory());
118+
apiRequest.setMaxMemory(request.getMaxMemory());
119+
apiRequest.setMaxPlayers(request.getMaxPlayers());
120+
apiRequest.setActive(request.getActive());
121+
apiRequest.setServerhostId(request.getServerhostId());
122+
apiRequest.setProperties(request.getProperties());
123+
apiRequest.setTags(request.getTags());
124+
125+
if (request.getType() != null) {
126+
apiRequest.setType(request.getType().name());
127+
}
128+
if (request.getSource() != null) {
129+
apiRequest.setSource(convertSourceConfig(request.getSource()));
130+
}
131+
if (request.getWorkflows() != null) {
132+
apiRequest.setWorkflows(convertWorkflowsConfig(request.getWorkflows()));
133+
}
134+
135+
ModelsCreatePersistentServerResponse response = persistentServersApi.v0PersistentServersPost(
136+
options.getNetworkId(),
137+
options.getNetworkSecret(),
138+
new V0PersistentServersPostRequest(apiRequest)
139+
);
140+
141+
// Re-fetch to get the full object
142+
return getPersistentServerById(response.getPersistentServerId()).join();
143+
} catch (ApiException e) {
144+
throw new RuntimeException(e);
145+
}
146+
});
147+
}
148+
149+
@Override
150+
public CompletableFuture<PersistentServer> updatePersistentServer(String id, UpdatePersistentServerRequest request) {
151+
return CompletableFuture.supplyAsync(() -> {
152+
try {
153+
ModelsUpdatePersistentServerRequest apiRequest = new ModelsUpdatePersistentServerRequest();
154+
apiRequest.setName(request.getName());
155+
apiRequest.setMinMemory(request.getMinMemory());
156+
apiRequest.setMaxMemory(request.getMaxMemory());
157+
apiRequest.setMaxPlayers(request.getMaxPlayers());
158+
apiRequest.setActive(request.getActive());
159+
apiRequest.setServerhostId(request.getServerhostId());
160+
apiRequest.setProperties(request.getProperties());
161+
apiRequest.setTags(request.getTags());
162+
163+
if (request.getType() != null) {
164+
apiRequest.setType(request.getType().name());
165+
}
166+
if (request.getSource() != null) {
167+
apiRequest.setSource(convertSourceConfig(request.getSource()));
168+
}
169+
if (request.getWorkflows() != null) {
170+
apiRequest.setWorkflows(convertWorkflowsConfig(request.getWorkflows()));
171+
}
172+
173+
persistentServersApi.v0PersistentServersPut(
174+
options.getNetworkId(),
175+
options.getNetworkSecret(),
176+
id,
177+
new V0PersistentServersPutRequest(apiRequest)
178+
);
179+
180+
// Re-fetch to get the updated object
181+
return getPersistentServerById(id).join();
182+
} catch (ApiException e) {
183+
throw new RuntimeException(e);
184+
}
185+
});
186+
}
187+
188+
@Override
189+
public CompletableFuture<Void> deletePersistentServer(String id) {
190+
return CompletableFuture.runAsync(() -> {
191+
try {
192+
persistentServersApi.v0PersistentServersDelete(
193+
options.getNetworkId(),
194+
options.getNetworkSecret(),
195+
id
196+
);
197+
} catch (ApiException e) {
198+
throw new RuntimeException(e);
199+
}
200+
});
201+
}
202+
203+
@Override
204+
public CompletableFuture<Map<String, Object>> updatePersistentServerProperties(String id, Map<String, Object> properties) {
205+
return CompletableFuture.supplyAsync(() -> {
206+
try {
207+
ModelsPatchPropertiesRequest request = new ModelsPatchPropertiesRequest();
208+
request.setProperties(properties);
209+
210+
ModelsPatchPropertiesResponse response = persistentServersApi.v0PersistentServersPropertiesPatch(
211+
options.getNetworkId(),
212+
options.getNetworkSecret(),
213+
id,
214+
new V0PersistentServersPropertiesPatchRequest(request)
215+
);
216+
217+
Map<String, Object> result = response.getProperties();
218+
return result != null ? result : new HashMap<>();
219+
} catch (ApiException e) {
220+
throw new RuntimeException(e);
221+
}
222+
});
223+
}
224+
225+
@Override
226+
public CompletableFuture<Map<String, Object>> deletePersistentServerProperties(String id, List<String> keys) {
227+
return CompletableFuture.supplyAsync(() -> {
228+
try {
229+
ModelsDeletePropertiesRequest request = new ModelsDeletePropertiesRequest();
230+
request.setKeys(keys);
231+
232+
ModelsDeletePropertiesResponse response = persistentServersApi.v0PersistentServersPropertiesDelete(
233+
options.getNetworkId(),
234+
options.getNetworkSecret(),
235+
id,
236+
new V0PersistentServersPropertiesDeleteRequest(request)
237+
);
238+
239+
Map<String, Object> result = response.getProperties();
240+
return result != null ? result : new HashMap<>();
241+
} catch (ApiException e) {
242+
throw new RuntimeException(e);
243+
}
244+
});
245+
}
246+
247+
private ModelsSourceConfig convertSourceConfig(SourceConfig config) {
248+
ModelsSourceConfig result = new ModelsSourceConfig();
249+
if (config.getType() != null) {
250+
result.setType(config.getType().name().toLowerCase());
251+
}
252+
result.setBlueprint(config.getBlueprint());
253+
result.setImage(config.getImage());
254+
return result;
255+
}
256+
257+
private ModelsWorkflowsConfig convertWorkflowsConfig(WorkflowsConfig config) {
258+
ModelsWorkflowsConfig result = new ModelsWorkflowsConfig();
259+
result.setManual(config.getManual());
260+
261+
if (config.getWhen() != null) {
262+
ModelsWorkflowWhen when = new ModelsWorkflowWhen();
263+
when.setStart(config.getWhen().getStart());
264+
when.setStop(config.getWhen().getStop());
265+
result.setWhen(when);
266+
}
267+
268+
return result;
269+
}
270+
}

0 commit comments

Comments
 (0)