0
# Networking
1
2
The GWT backend provides HTTP-based networking through browser APIs. Due to web security restrictions, only HTTP/HTTPS requests are supported, with no TCP/UDP socket capabilities.
3
4
## Core Networking Classes
5
6
### GwtNet { .api }
7
8
```java
9
public class GwtNet implements Net {
10
// HTTP requests
11
public void sendHttpRequest(HttpRequest httpRequest, HttpResponseListener httpResponseListener);
12
public void cancelHttpRequest(HttpRequest httpRequest);
13
14
// Browser integration
15
public void openURI(String URI);
16
17
// Unsupported operations (throw UnsupportedOperationException)
18
public ServerSocket newServerSocket(Protocol protocol, String hostname, int port, ServerSocketHints hints);
19
public ServerSocket newServerSocket(Protocol protocol, int port, ServerSocketHints hints);
20
public Socket newClientSocket(Protocol protocol, String host, int port, SocketHints hints);
21
}
22
```
23
24
## HTTP Request Support
25
26
### Basic HTTP Operations
27
28
```java
29
// GET request example
30
HttpRequest httpGet = new HttpRequest(HttpMethods.GET);
31
httpGet.setUrl("https://api.example.com/data");
32
httpGet.setHeader("User-Agent", "MyGame/1.0");
33
34
Gdx.net.sendHttpRequest(httpGet, new HttpResponseListener() {
35
@Override
36
public void handleHttpResponse(HttpResponse httpResponse) {
37
int statusCode = httpResponse.getStatus().getStatusCode();
38
if (statusCode == 200) {
39
String responseData = httpResponse.getResultAsString();
40
// Handle successful response
41
processApiData(responseData);
42
} else {
43
System.err.println("HTTP Error: " + statusCode);
44
}
45
}
46
47
@Override
48
public void failed(Throwable t) {
49
System.err.println("Request failed: " + t.getMessage());
50
}
51
52
@Override
53
public void cancelled() {
54
System.out.println("Request was cancelled");
55
}
56
});
57
58
// POST request example
59
HttpRequest httpPost = new HttpRequest(HttpMethods.POST);
60
httpPost.setUrl("https://api.example.com/submit");
61
httpPost.setHeader("Content-Type", "application/json");
62
httpPost.setContent("{\"score\": 1000, \"player\": \"Alice\"}");
63
64
Gdx.net.sendHttpRequest(httpPost, new HttpResponseListener() {
65
@Override
66
public void handleHttpResponse(HttpResponse httpResponse) {
67
if (httpResponse.getStatus().getStatusCode() == 201) {
68
System.out.println("Score submitted successfully");
69
}
70
}
71
72
@Override
73
public void failed(Throwable t) {
74
System.err.println("Score submission failed: " + t.getMessage());
75
}
76
77
@Override
78
public void cancelled() {
79
System.out.println("Score submission cancelled");
80
}
81
});
82
```
83
84
## Usage Examples
85
86
### Game API Integration
87
88
```java
89
public class GameAPI {
90
private static final String BASE_URL = "https://api.mygame.com";
91
private static final String API_KEY = "your-api-key";
92
93
public void submitHighScore(int score, String playerName, ApiCallback<Boolean> callback) {
94
HttpRequest request = new HttpRequest(HttpMethods.POST);
95
request.setUrl(BASE_URL + "/scores");
96
request.setHeader("Authorization", "Bearer " + API_KEY);
97
request.setHeader("Content-Type", "application/json");
98
99
String jsonData = String.format(
100
"{\"player\": \"%s\", \"score\": %d, \"timestamp\": %d}",
101
playerName, score, System.currentTimeMillis()
102
);
103
request.setContent(jsonData);
104
105
Gdx.net.sendHttpRequest(request, new HttpResponseListener() {
106
@Override
107
public void handleHttpResponse(HttpResponse httpResponse) {
108
boolean success = httpResponse.getStatus().getStatusCode() == 200;
109
callback.onResult(success);
110
}
111
112
@Override
113
public void failed(Throwable t) {
114
callback.onError(t.getMessage());
115
}
116
117
@Override
118
public void cancelled() {
119
callback.onError("Request cancelled");
120
}
121
});
122
}
123
124
public void getLeaderboard(ApiCallback<LeaderboardData> callback) {
125
HttpRequest request = new HttpRequest(HttpMethods.GET);
126
request.setUrl(BASE_URL + "/leaderboard?limit=10");
127
request.setHeader("Authorization", "Bearer " + API_KEY);
128
129
Gdx.net.sendHttpRequest(request, new HttpResponseListener() {
130
@Override
131
public void handleHttpResponse(HttpResponse httpResponse) {
132
if (httpResponse.getStatus().getStatusCode() == 200) {
133
String jsonResponse = httpResponse.getResultAsString();
134
LeaderboardData data = parseLeaderboard(jsonResponse);
135
callback.onResult(data);
136
} else {
137
callback.onError("HTTP " + httpResponse.getStatus().getStatusCode());
138
}
139
}
140
141
@Override
142
public void failed(Throwable t) {
143
callback.onError(t.getMessage());
144
}
145
146
@Override
147
public void cancelled() {
148
callback.onError("Request cancelled");
149
}
150
});
151
}
152
153
private LeaderboardData parseLeaderboard(String json) {
154
// Parse JSON response into LeaderboardData object
155
// Can use libGDX Json class or manual parsing
156
return new LeaderboardData();
157
}
158
159
public interface ApiCallback<T> {
160
void onResult(T result);
161
void onError(String error);
162
}
163
164
public static class LeaderboardData {
165
public String[] playerNames;
166
public int[] scores;
167
public long[] timestamps;
168
}
169
}
170
```
171
172
### File Download System
173
174
```java
175
public class AssetDownloader {
176
private Map<String, HttpRequest> activeRequests = new HashMap<>();
177
178
public void downloadAsset(String url, String localPath, DownloadCallback callback) {
179
HttpRequest request = new HttpRequest(HttpMethods.GET);
180
request.setUrl(url);
181
182
// Store request for potential cancellation
183
activeRequests.put(localPath, request);
184
185
Gdx.net.sendHttpRequest(request, new HttpResponseListener() {
186
@Override
187
public void handleHttpResponse(HttpResponse httpResponse) {
188
activeRequests.remove(localPath);
189
190
if (httpResponse.getStatus().getStatusCode() == 200) {
191
try {
192
// Save downloaded data to local storage
193
byte[] data = httpResponse.getResult();
194
FileHandle localFile = Gdx.files.local(localPath);
195
localFile.writeBytes(data, false);
196
197
callback.onDownloadComplete(localPath);
198
} catch (Exception e) {
199
callback.onDownloadFailed(localPath, e.getMessage());
200
}
201
} else {
202
callback.onDownloadFailed(localPath, "HTTP " + httpResponse.getStatus().getStatusCode());
203
}
204
}
205
206
@Override
207
public void failed(Throwable t) {
208
activeRequests.remove(localPath);
209
callback.onDownloadFailed(localPath, t.getMessage());
210
}
211
212
@Override
213
public void cancelled() {
214
activeRequests.remove(localPath);
215
callback.onDownloadCancelled(localPath);
216
}
217
});
218
}
219
220
public void cancelDownload(String localPath) {
221
HttpRequest request = activeRequests.get(localPath);
222
if (request != null) {
223
Gdx.net.cancelHttpRequest(request);
224
}
225
}
226
227
public void cancelAllDownloads() {
228
for (HttpRequest request : activeRequests.values()) {
229
Gdx.net.cancelHttpRequest(request);
230
}
231
activeRequests.clear();
232
}
233
234
public interface DownloadCallback {
235
void onDownloadComplete(String localPath);
236
void onDownloadFailed(String localPath, String error);
237
void onDownloadCancelled(String localPath);
238
}
239
}
240
```
241
242
### Configuration Server Integration
243
244
```java
245
public class ConfigManager {
246
private static final String CONFIG_URL = "https://config.mygame.com/settings.json";
247
private JsonValue serverConfig;
248
249
public void loadServerConfig(Runnable onComplete) {
250
HttpRequest request = new HttpRequest(HttpMethods.GET);
251
request.setUrl(CONFIG_URL);
252
request.setHeader("Accept", "application/json");
253
254
Gdx.net.sendHttpRequest(request, new HttpResponseListener() {
255
@Override
256
public void handleHttpResponse(HttpResponse httpResponse) {
257
if (httpResponse.getStatus().getStatusCode() == 200) {
258
try {
259
String jsonString = httpResponse.getResultAsString();
260
Json json = new Json();
261
serverConfig = json.fromJson(JsonValue.class, jsonString);
262
263
System.out.println("Server config loaded successfully");
264
if (onComplete != null) onComplete.run();
265
} catch (Exception e) {
266
System.err.println("Failed to parse server config: " + e.getMessage());
267
useDefaultConfig();
268
if (onComplete != null) onComplete.run();
269
}
270
} else {
271
System.err.println("Failed to load server config: HTTP " + httpResponse.getStatus().getStatusCode());
272
useDefaultConfig();
273
if (onComplete != null) onComplete.run();
274
}
275
}
276
277
@Override
278
public void failed(Throwable t) {
279
System.err.println("Server config request failed: " + t.getMessage());
280
useDefaultConfig();
281
if (onComplete != null) onComplete.run();
282
}
283
284
@Override
285
public void cancelled() {
286
System.out.println("Server config request cancelled");
287
useDefaultConfig();
288
if (onComplete != null) onComplete.run();
289
}
290
});
291
}
292
293
public String getConfigString(String key, String defaultValue) {
294
if (serverConfig != null && serverConfig.has(key)) {
295
return serverConfig.getString(key, defaultValue);
296
}
297
return defaultValue;
298
}
299
300
public int getConfigInt(String key, int defaultValue) {
301
if (serverConfig != null && serverConfig.has(key)) {
302
return serverConfig.getInt(key, defaultValue);
303
}
304
return defaultValue;
305
}
306
307
public boolean getConfigBoolean(String key, boolean defaultValue) {
308
if (serverConfig != null && serverConfig.has(key)) {
309
return serverConfig.getBoolean(key, defaultValue);
310
}
311
return defaultValue;
312
}
313
314
private void useDefaultConfig() {
315
// Create default configuration
316
Json json = new Json();
317
String defaultJson = "{\"maxPlayers\": 4, \"gameMode\": \"classic\", \"enableFeatureX\": true}";
318
serverConfig = json.fromJson(JsonValue.class, defaultJson);
319
}
320
}
321
```
322
323
### Browser Integration
324
325
```java
326
public class BrowserIntegration {
327
// Open URLs in browser
328
public static void openWebsite(String url) {
329
try {
330
Gdx.net.openURI(url);
331
System.out.println("Opened URL: " + url);
332
} catch (Exception e) {
333
System.err.println("Failed to open URL: " + e.getMessage());
334
}
335
}
336
337
// Open social media sharing
338
public static void shareScore(int score) {
339
String message = "I just scored " + score + " points in MyGame!";
340
String twitterUrl = "https://twitter.com/intent/tweet?text=" +
341
java.net.URLEncoder.encode(message, "UTF-8");
342
openWebsite(twitterUrl);
343
}
344
345
// Open game store page
346
public static void openStorePage() {
347
openWebsite("https://store.example.com/mygame");
348
}
349
350
// Open support/feedback page
351
public static void openSupport() {
352
openWebsite("https://support.mygame.com");
353
}
354
}
355
```
356
357
### Analytics Integration
358
359
```java
360
public class Analytics {
361
private static final String ANALYTICS_URL = "https://analytics.mygame.com/events";
362
private static final String SESSION_ID = generateSessionId();
363
364
public static void trackEvent(String eventName, Map<String, Object> properties) {
365
HttpRequest request = new HttpRequest(HttpMethods.POST);
366
request.setUrl(ANALYTICS_URL);
367
request.setHeader("Content-Type", "application/json");
368
369
// Build event data
370
Json json = new Json();
371
Map<String, Object> eventData = new HashMap<>();
372
eventData.put("event", eventName);
373
eventData.put("sessionId", SESSION_ID);
374
eventData.put("timestamp", System.currentTimeMillis());
375
eventData.put("properties", properties);
376
377
String jsonContent = json.toJson(eventData);
378
request.setContent(jsonContent);
379
380
Gdx.net.sendHttpRequest(request, new HttpResponseListener() {
381
@Override
382
public void handleHttpResponse(HttpResponse httpResponse) {
383
// Analytics requests typically don't need response handling
384
if (httpResponse.getStatus().getStatusCode() != 200) {
385
System.err.println("Analytics event failed: " + httpResponse.getStatus().getStatusCode());
386
}
387
}
388
389
@Override
390
public void failed(Throwable t) {
391
System.err.println("Analytics event failed: " + t.getMessage());
392
}
393
394
@Override
395
public void cancelled() {
396
// Ignore cancellations for analytics
397
}
398
});
399
}
400
401
public static void trackLevelStart(int level) {
402
Map<String, Object> props = new HashMap<>();
403
props.put("level", level);
404
trackEvent("level_start", props);
405
}
406
407
public static void trackLevelComplete(int level, int score, float time) {
408
Map<String, Object> props = new HashMap<>();
409
props.put("level", level);
410
props.put("score", score);
411
props.put("completionTime", time);
412
trackEvent("level_complete", props);
413
}
414
415
public static void trackPurchase(String itemId, float price) {
416
Map<String, Object> props = new HashMap<>();
417
props.put("itemId", itemId);
418
props.put("price", price);
419
trackEvent("purchase", props);
420
}
421
422
private static String generateSessionId() {
423
return "session_" + System.currentTimeMillis() + "_" + (int)(Math.random() * 10000);
424
}
425
}
426
```
427
428
## Web-Specific Networking Considerations
429
430
### CORS (Cross-Origin Resource Sharing)
431
432
```java
433
// Browser CORS policy affects HTTP requests
434
public class CORSHelper {
435
// Only requests to same origin are always allowed
436
// Cross-origin requests require server CORS headers
437
438
public static void makeCORSRequest(String url) {
439
// Server must include appropriate CORS headers:
440
// Access-Control-Allow-Origin: *
441
// Access-Control-Allow-Methods: GET, POST, PUT, DELETE
442
// Access-Control-Allow-Headers: Content-Type, Authorization
443
444
HttpRequest request = new HttpRequest(HttpMethods.GET);
445
request.setUrl(url);
446
447
Gdx.net.sendHttpRequest(request, new HttpResponseListener() {
448
@Override
449
public void handleHttpResponse(HttpResponse httpResponse) {
450
// Handle response
451
}
452
453
@Override
454
public void failed(Throwable t) {
455
// CORS failures often appear as network errors
456
System.err.println("Request failed (possibly CORS): " + t.getMessage());
457
}
458
459
@Override
460
public void cancelled() {
461
// Handle cancellation
462
}
463
});
464
}
465
}
466
```
467
468
### Security Limitations
469
470
```java
471
// Web security model limitations:
472
473
// ✓ Supported: HTTP/HTTPS requests
474
HttpRequest httpRequest = new HttpRequest(HttpMethods.GET);
475
httpRequest.setUrl("https://api.example.com/data");
476
477
// ✗ NOT supported: TCP/UDP sockets
478
try {
479
Socket socket = Gdx.net.newClientSocket(Net.Protocol.TCP, "example.com", 8080, null);
480
// Throws UnsupportedOperationException
481
} catch (UnsupportedOperationException e) {
482
System.out.println("TCP sockets not supported on web");
483
}
484
485
// ✗ NOT supported: Server sockets
486
try {
487
ServerSocket serverSocket = Gdx.net.newServerSocket(Net.Protocol.TCP, 8080, null);
488
// Throws UnsupportedOperationException
489
} catch (UnsupportedOperationException e) {
490
System.out.println("Server sockets not supported on web");
491
}
492
493
// ✓ Supported: Opening URLs in browser
494
Gdx.net.openURI("https://example.com");
495
```
496
497
### Request Limitations
498
499
```java
500
// Browser request limitations and best practices:
501
502
public class RequestManager {
503
private static final int MAX_CONCURRENT_REQUESTS = 6; // Browser limit
504
private int activeRequests = 0;
505
private Queue<Runnable> requestQueue = new LinkedList<>();
506
507
public void makeRequest(HttpRequest request, HttpResponseListener listener) {
508
if (activeRequests < MAX_CONCURRENT_REQUESTS) {
509
executeRequest(request, listener);
510
} else {
511
// Queue request if at browser limit
512
requestQueue.offer(() -> executeRequest(request, listener));
513
}
514
}
515
516
private void executeRequest(HttpRequest request, HttpResponseListener listener) {
517
activeRequests++;
518
519
Gdx.net.sendHttpRequest(request, new HttpResponseListener() {
520
@Override
521
public void handleHttpResponse(HttpResponse httpResponse) {
522
activeRequests--;
523
processQueue();
524
listener.handleHttpResponse(httpResponse);
525
}
526
527
@Override
528
public void failed(Throwable t) {
529
activeRequests--;
530
processQueue();
531
listener.failed(t);
532
}
533
534
@Override
535
public void cancelled() {
536
activeRequests--;
537
processQueue();
538
listener.cancelled();
539
}
540
});
541
}
542
543
private void processQueue() {
544
if (!requestQueue.isEmpty() && activeRequests < MAX_CONCURRENT_REQUESTS) {
545
Runnable nextRequest = requestQueue.poll();
546
nextRequest.run();
547
}
548
}
549
}
550
```