1
+
/*
2
+
* FXGL - JavaFX Game Library. The MIT License (MIT).
3
+
* Copyright (c) AlmasB (almaslvl@gmail.com).
4
+
* See LICENSE for details.
5
+
*/
6
+
7
+
package com.almasb.fxgl.ws;
8
+
9
+
import com.almasb.fxgl.logging.Logger;
10
+
import org.java_websocket.WebSocket;
11
+
import org.java_websocket.handshake.ClientHandshake;
12
+
import org.java_websocket.server.WebSocketServer;
13
+
14
+
import java.net.InetSocketAddress;
15
+
import java.util.ArrayList;
16
+
import java.util.List;
17
+
import java.util.Optional;
18
+
import java.util.concurrent.ArrayBlockingQueue;
19
+
import java.util.concurrent.BlockingQueue;
20
+
import java.util.function.Consumer;
21
+
22
+
/**
23
+
* A simple localhost websocket server.
24
+
* All methods are internally run in a background thread,
25
+
* so they are safe to be called from any thread.
26
+
*
27
+
* @author Almas Baimagambetov (almaslvl@gmail.com)
28
+
*/
29
+
public final class LocalWebSocketServer extends WebSocketServer {
30
+
31
+
private static final String POISON_PILL = "62jkasdy732qjkkhs63jASY_HSF";
32
+
33
+
private final Logger log;
34
+
35
+
private boolean isLoggingEnabled = true;
36
+
37
+
private String serverName;
38
+
private List<Consumer<String>> messageHandlers = new ArrayList<>();
39
+
40
+
private SendMessageThread thread;
41
+
private WebSocket socket = null;
42
+
43
+
/**
44
+
* Create a server without a name at given port.
45
+
*/
46
+
public LocalWebSocketServer(int port) {
47
+
this("Unnamed", port);
48
+
}
49
+
50
+
/**
51
+
* Create a server with the given dev-friendly name at given port.
52
+
*/
53
+
public LocalWebSocketServer(String serverName, int port) {
54
+
super(new InetSocketAddress("localhost", port));
55
+
this.serverName = serverName;
56
+
57
+
log = Logger.get("WSServer " + serverName + ":" + port);
58
+
thread = new SendMessageThread(serverName);
59
+
}
60
+
61
+
public boolean isLoggingEnabled() {
62
+
return isLoggingEnabled;
63
+
}
64
+
65
+
public void setLoggingEnabled(boolean isLoggingEnabled) {
66
+
this.isLoggingEnabled = isLoggingEnabled;
67
+
}
68
+
69
+
/**
70
+
* Add a handler for new messages.
71
+
*/
72
+
public void addMessageHandler(Consumer<String> handler) {
73
+
messageHandlers.add(handler);
74
+
}
75
+
76
+
/**
77
+
* Remove an existing handler.
78
+
*/
79
+
public void removeMessageHandler(Consumer<String> handler) {
80
+
messageHandlers.remove(handler);
81
+
}
82
+
83
+
/**
84
+
* @return last connected socket
85
+
*/
86
+
public Optional<WebSocket> socket() {
87
+
return Optional.ofNullable(socket);
88
+
}
89
+
90
+
/**
91
+
* Send a String to the other end of the socket.
92
+
*/
93
+
public void send(String data) {
94
+
if (!isConnected()) {
95
+
log.warning("Cannot send <" + data + "> Socket is not connected");
96
+
return;
97
+
}
98
+
99
+
try {
100
+
thread.messages.put(data);
101
+
} catch (Exception e) {
102
+
log.warning("Failed to send data to SendMessageThread", e);
103
+
}
104
+
}
105
+
106
+
public boolean isConnected() {
107
+
return socket != null;
108
+
}
109
+
110
+
@Override
111
+
public void onOpen(WebSocket conn, ClientHandshake handshake) {
112
+
log.info("Opened connection: " + conn.getRemoteSocketAddress());
113
+
114
+
socket = conn;
115
+
}
116
+
117
+
@Override
118
+
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
119
+
log.info("Closed connection, code: " + code);
120
+
}
121
+
122
+
@Override
123
+
public void onMessage(WebSocket conn, String message) {
124
+
messageHandlers.forEach(h -> h.accept(message));
125
+
}
126
+
127
+
@Override
128
+
public void onError(WebSocket conn, Exception ex) {
129
+
log.warning("WS error", ex);
130
+
}
131
+
132
+
@Override
133
+
public void onStart() {
134
+
log.info("Server started successfully");
135
+
}
136
+
137
+
@Override
138
+
public void start() {
139
+
try {
140
+
thread.start();
141
+
super.start();
142
+
} catch (Exception e) {
143
+
log.warning("Failed to start WS server", e);
144
+
}
145
+
}
146
+
147
+
@Override
148
+
public void stop() {
149
+
try {
150
+
thread.messages.put(POISON_PILL);
151
+
super.stop();
152
+
} catch (Exception e) {
153
+
log.warning("Failed to stop WS server", e);
154
+
}
155
+
}
156
+
157
+
private class SendMessageThread extends Thread {
158
+
BlockingQueue<String> messages = new ArrayBlockingQueue<>(10);
159
+
160
+
SendMessageThread(String name) {
161
+
super(name);
162
+
}
163
+
164
+
@Override
165
+
public void run() {
166
+
while (true) {
167
+
try {
168
+
var data = messages.take();
169
+
170
+
if (data.equals(POISON_PILL))
171
+
break;
172
+
173
+
socket.send(data);
174
+
175
+
} catch (Exception e) {
176
+
log.warning("Failed to send data", e);
177
+
}
178
+
}
179
+
}
180
+
}
181
+
}
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4