Skip to content

Commit 47325c0

Browse files
committed
allow a websocket to access initial request parameters fix jooby-project#6
1 parent 272e84a commit 47325c0

11 files changed

Lines changed: 283 additions & 164 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package org.jooby.issues;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import java.util.Arrays;
6+
import java.util.LinkedList;
7+
import java.util.concurrent.CountDownLatch;
8+
import java.util.concurrent.TimeUnit;
9+
10+
import org.jooby.test.ServerFeature;
11+
import org.junit.After;
12+
import org.junit.Before;
13+
import org.junit.Test;
14+
15+
import com.ning.http.client.AsyncHttpClient;
16+
import com.ning.http.client.AsyncHttpClientConfig;
17+
import com.ning.http.client.ws.WebSocket;
18+
import com.ning.http.client.ws.WebSocketTextListener;
19+
import com.ning.http.client.ws.WebSocketUpgradeHandler;
20+
21+
public class Issue6 extends ServerFeature {
22+
23+
{
24+
ws("/connect", (req, ws) -> {
25+
ws.send(req.param("ws").value(), () -> {
26+
Thread.sleep(300L);
27+
ws.close();
28+
});
29+
});
30+
31+
}
32+
33+
private AsyncHttpClient client;
34+
35+
@Before
36+
public void before() {
37+
client = new AsyncHttpClient(new AsyncHttpClientConfig.Builder().build());
38+
}
39+
40+
@After
41+
public void after() {
42+
client.close();
43+
}
44+
45+
@Test
46+
public void connectWithRequest() throws Exception {
47+
48+
LinkedList<String> messages = new LinkedList<>();
49+
50+
CountDownLatch latch = new CountDownLatch(2);
51+
52+
client.prepareGet(ws("connect?ws=006").toString())
53+
.execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(
54+
new WebSocketTextListener() {
55+
56+
@Override
57+
public void onMessage(final String message) {
58+
messages.add(message);
59+
latch.countDown();
60+
}
61+
62+
@Override
63+
public void onOpen(final WebSocket websocket) {
64+
}
65+
66+
@Override
67+
public void onClose(final WebSocket websocket) {
68+
latch.countDown();
69+
}
70+
71+
@Override
72+
public void onError(final Throwable t) {
73+
}
74+
}).build())
75+
.get();
76+
77+
if (latch.await(1L, TimeUnit.SECONDS)) {
78+
assertEquals(Arrays.asList("006"), messages);
79+
}
80+
}
81+
82+
}

jooby/src/main/java/org/jooby/Jooby.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3409,9 +3409,7 @@ public Jooby err(final Err.Handler err) {
34093409
* @param handler A connect callback.
34103410
* @return A new WebSocket definition.
34113411
*/
3412-
@Override
3413-
public WebSocket.Definition ws(final String path,
3414-
final WebSocket.Handler handler) {
3412+
public WebSocket.Definition ws(final String path, final WebSocket.FullHandler handler) {
34153413
WebSocket.Definition ws = new WebSocket.Definition(path, handler);
34163414
checkArgument(bag.add(ws), "Path is in use: '%s'", path);
34173415
return ws;

jooby/src/main/java/org/jooby/Routes.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2419,7 +2419,28 @@ Route.Collection complete(String method, String pattern, Route.Complete handler,
24192419
* @param handler A connect callback.
24202420
* @return A new WebSocket definition.
24212421
*/
2422-
WebSocket.Definition ws(String path, WebSocket.Handler handler);
2422+
default WebSocket.Definition ws(final String path, final WebSocket.Handler handler) {
2423+
return ws(path, (WebSocket.FullHandler) handler);
2424+
}
2425+
2426+
/**
2427+
* Append a new WebSocket handler under the given path.
2428+
*
2429+
* <pre>
2430+
* ws("/ws", (req, socket) {@literal ->} {
2431+
* // connected
2432+
* socket.onMessage(message {@literal ->} {
2433+
* System.out.println(message);
2434+
* });
2435+
* socket.send("Connected"):
2436+
* });
2437+
* </pre>
2438+
*
2439+
* @param path A path pattern.
2440+
* @param handler A connect callback.
2441+
* @return A new WebSocket definition.
2442+
*/
2443+
WebSocket.Definition ws(String path, WebSocket.FullHandler handler);
24232444

24242445
/**
24252446
* Add a server-sent event handler.

jooby/src/main/java/org/jooby/WebSocket.java

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
* @author edgar
8383
* @since 0.1.0
8484
*/
85-
public interface WebSocket extends Closeable {
85+
public interface WebSocket extends Closeable, Registry {
8686

8787
/** Websocket key. */
8888
Key<Set<WebSocket.Definition>> KEY = Key.get(new TypeLiteral<Set<WebSocket.Definition>>() {
@@ -94,7 +94,34 @@ public interface WebSocket extends Closeable {
9494
* @author edgar
9595
* @since 0.1.0
9696
*/
97-
interface Handler {
97+
interface FullHandler {
98+
/**
99+
* Inside a connect event, you can listen for {@link WebSocket#onMessage(Callback)},
100+
* {@link WebSocket#onClose(Callback)} or {@link WebSocket#onError(ErrCallback)} events.
101+
*
102+
* Also, you can send text and binary message.
103+
*
104+
* @param req Current request.
105+
* @param ws A web socket.
106+
* @throws Exception If something goes wrong while connecting.
107+
*/
108+
void connect(Request req, WebSocket ws) throws Exception;
109+
}
110+
111+
112+
/**
113+
* A web socket connect handler. Executed every time a new client connect to the socket.
114+
*
115+
* @author edgar
116+
* @since 0.1.0
117+
*/
118+
interface Handler extends FullHandler {
119+
120+
@Override
121+
default void connect(final Request req, final WebSocket ws) throws Exception {
122+
connect(ws);
123+
}
124+
98125
/**
99126
* Inside a connect event, you can listen for {@link WebSocket#onMessage(Callback)},
100127
* {@link WebSocket#onClose(Callback)} or {@link WebSocket#onError(ErrCallback)} events.
@@ -264,15 +291,15 @@ class Definition {
264291
private String pattern;
265292

266293
/** A ws handler. */
267-
private Handler handler;
294+
private FullHandler handler;
268295

269296
/**
270297
* Creates a new {@link Definition}.
271298
*
272299
* @param pattern A path pattern.
273300
* @param handler A ws handler.
274301
*/
275-
public Definition(final String pattern, final Handler handler) {
302+
public Definition(final String pattern, final FullHandler handler) {
276303
requireNonNull(pattern, "A route path is required.");
277304
requireNonNull(handler, "A handler is required.");
278305

@@ -621,35 +648,4 @@ default void send(final Object data, final ErrCallback err)
621648
void send(Object data, SuccessCallback success, ErrCallback err)
622649
throws Exception;
623650

624-
/**
625-
* Find and return a service using the provided type.
626-
*
627-
* @param type A service type.
628-
* @param <T> Service type.
629-
* @return Binded service.
630-
*/
631-
default <T> T require(final Class<T> type) {
632-
return require(Key.get(type));
633-
}
634-
635-
/**
636-
* Find and return a service using the provided type.
637-
*
638-
* @param type A service type.
639-
* @param <T> Service type.
640-
* @return Binded service.
641-
*/
642-
default <T> T require(final TypeLiteral<T> type) {
643-
return require(Key.get(type));
644-
}
645-
646-
/**
647-
* Find and return a service using the provided key.
648-
*
649-
* @param key A key for a service.
650-
* @param <T> Service type.
651-
* @return Binded service.
652-
*/
653-
<T> T require(Key<T> key);
654-
655651
}

jooby/src/main/java/org/jooby/internal/AbstractRendererContext.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ public void send(final InputStream stream) throws Exception {
176176
committed = true;
177177
}
178178

179+
protected void setCommitted() {
180+
committed = true;
181+
}
182+
179183
@Override
180184
public String toString() {
181185
return renderers.stream().map(Renderer::name).collect(Collectors.joining(", "));

jooby/src/main/java/org/jooby/internal/HttpHandlerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ public void handle(final NativeRequest request, final NativeResponse response) t
280280
Optional<WebSocket> sockets = findSockets(socketDefs, requestPath);
281281
if (sockets.isPresent()) {
282282
NativeWebSocket ws = request.upgrade(NativeWebSocket.class);
283-
ws.onConnect(() -> ((WebSocketImpl) sockets.get()).connect(injector, ws));
283+
ws.onConnect(() -> ((WebSocketImpl) sockets.get()).connect(injector, req, ws));
284284
return;
285285
}
286286
}

jooby/src/main/java/org/jooby/internal/WebSocketImpl.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.jooby.MediaType;
3030
import org.jooby.Mutant;
3131
import org.jooby.Renderer;
32+
import org.jooby.Request;
3233
import org.jooby.WebSocket;
3334
import org.jooby.internal.parser.ParserExecutor;
3435
import org.jooby.spi.NativeWebSocket;
@@ -58,7 +59,7 @@ public class WebSocketImpl implements WebSocket {
5859

5960
private MediaType produces;
6061

61-
private Handler handler;
62+
private FullHandler handler;
6263

6364
private Callback<Mutant> messageCallback = noop();
6465

@@ -76,7 +77,7 @@ public class WebSocketImpl implements WebSocket {
7677

7778
private List<Renderer> renderers;
7879

79-
public WebSocketImpl(final Handler handler, final String path,
80+
public WebSocketImpl(final FullHandler handler, final String path,
8081
final String pattern, final Map<Object, String> vars,
8182
final MediaType consumes, final MediaType produces) {
8283
this.handler = handler;
@@ -116,9 +117,9 @@ public void terminate() throws Exception {
116117
@Override
117118
public void send(final Object data, final SuccessCallback success, final ErrCallback err)
118119
throws Exception {
119-
requireNonNull(data, "A data message is required.");
120-
requireNonNull(success, "A success callback is required.");
121-
requireNonNull(err, "An error callback is required.");
120+
requireNonNull(data, "Message required.");
121+
requireNonNull(success, "Success callback required.");
122+
requireNonNull(err, "Error callback required.");
122123

123124
new WebSocketRendererContext(
124125
renderers,
@@ -131,12 +132,12 @@ public void send(final Object data, final SuccessCallback success, final ErrCall
131132

132133
@Override
133134
public void onMessage(final Callback<Mutant> callback) throws Exception {
134-
this.messageCallback = requireNonNull(callback, "Message callback is required.");
135+
this.messageCallback = requireNonNull(callback, "Message callback required.");
135136
}
136137

137-
public void connect(final Injector injector, final NativeWebSocket ws) {
138-
this.injector = requireNonNull(injector, "An injector is required.");
139-
this.ws = requireNonNull(ws, "Web socket is required.");
138+
public void connect(final Injector injector, final Request req, final NativeWebSocket ws) {
139+
this.injector = requireNonNull(injector, "Injector required.");
140+
this.ws = requireNonNull(ws, "WebSocket is required.");
140141
renderers = ImmutableList.copyOf(injector.getInstance(Renderer.KEY));
141142

142143
/**
@@ -153,8 +154,7 @@ public void connect(final Injector injector, final NativeWebSocket ws) {
153154
try {
154155
messageCallback.invoke(
155156
new MutantImpl(injector.getInstance(ParserExecutor.class),
156-
new StrParamReferenceImpl("body", "message", ImmutableList.of(message)))
157-
);
157+
new StrParamReferenceImpl("body", "message", ImmutableList.of(message))));
158158
} catch (Throwable ex) {
159159
handleErr(ex);
160160
}
@@ -174,7 +174,7 @@ public void connect(final Injector injector, final NativeWebSocket ws) {
174174

175175
// connect now
176176
try {
177-
handler.connect(this);
177+
handler.connect(req, this);
178178
} catch (Throwable ex) {
179179
handleErr(ex);
180180
}

jooby/src/main/java/org/jooby/internal/WebSocketRendererContext.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public WebSocketRendererContext(final List<Renderer> renderers, final NativeWebS
5656
@Override
5757
public void send(final String text) throws Exception {
5858
ws.sendText(text, success, err);
59+
setCommitted();
5960
}
6061

6162
@Override

0 commit comments

Comments
 (0)