Skip to content

Commit

Permalink
Big API clean up, and introduction of very primitive SSE support. Add…
Browse files Browse the repository at this point in the history
…ed ChatServer test app to demonstrate what it can be used for.
  • Loading branch information
JonathanGiles committed Feb 13, 2024
1 parent 853f9e5 commit 41df692
Show file tree
Hide file tree
Showing 33 changed files with 2,335 additions and 1,176 deletions.
7 changes: 5 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.jonathangiles.tools</groupId>
<artifactId>teenyhttpd</artifactId>
<version>1.0.5</version>
<version>1.0.6</version>

<name>TeenyHttpd</name>
<description>TeenyHttpd is an extremely basic HTTP server.</description>
Expand Down Expand Up @@ -83,7 +83,7 @@
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>net.jonathangiles.tools.teenyhttpd.Main</mainClass>
<mainClass>net.jonathangiles.tools.teenyhttpd.TeenyHttpd</mainClass>
</manifest>
</archive>
</configuration>
Expand All @@ -92,6 +92,9 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<excludePackageNames>*.implementation.*</excludePackageNames>
</configuration>
<executions>
<execution>
<id>attach-javadoc</id>
Expand Down
67 changes: 66 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ the following code will serve a response of `User ID: 123` when a GET request is
```java
server.addGetRoute("/user/:id/details", request -> {
String id = request.getPathParams().get("id");
return new StringResponse(StatusCode.OK, "User ID: " + id);
return Response.create(StatusCode.OK, "User ID: " + id);
});
```

Expand All @@ -139,6 +139,71 @@ test = true
foo = bar
```

## Server-Sent Events

TeenyHttpd supports Server-Sent Events (SSE). To use this feature, you need to use the `addServerSentEventRoute` method,
with a `ServerSentEventHandler`. For example, the following code will send a message to the client every second:

```java
final int PORT = 80;
TeenyHttpd server = new TeenyHttpd(PORT);
server.addServerSentEventRoute("/events", ServerSentEventHandler.create(sse -> new Thread(() -> {
int i = 0;
while (sse.hasActiveConnections()) {
sse.sendMessage(new ServerSentEventMessage("Message " + i++, "counter"));
threadSleep(1000);
}
}).start()));
server.start();
```

If more than one user connects to the same /events topic, they will share the same state, each getting the same value
for `i` at the same time. If you want to customise the response per user (for example, based on a path parameter or
query parameter), you can use the message generator feature:

```java
ServerSentEventHandler sse = ServerSentEventHandler.create((ServerSentEventHandler _sse) -> {
// start a thread and send messages to the client(s)
new Thread(() -> {
// all clients share the same integer value, but they get a custom message based
// on the path parameter for :username
AtomicInteger i = new AtomicInteger(0);

while (_sse.hasActiveConnections()) {
_sse.sendMessage(client -> {
String username = client.getPathParams().get("username");
return new ServerSentEventMessage("Hello " + username + " - " + i, "counter");
});
i.incrementAndGet();
threadSleep(1000);
}
}).start();
});
server.addServerSentEventRoute("/sse/:username", sse);
```

The above samples assume that you start a thread when there are active connections, to send messages to connected
clients at a regular interval. Another approach is to just have a ServerSentEventHandler that sends messages to
connected clients when a message is received. For example, the following code will send a message to all clients
that are connected to the `/messages` topic, when a message is posted to `/message`:

```java
final int PORT = 80;
TeenyHttpd server = new TeenyHttpd(PORT);
ServerSentEventHandler chatMessagesEventHandler = ServerSentEventHandler.create();
server.addServerSentEventRoute("/messages", chatMessagesEventHandler);
server.addRoute(Method.POST, "/message", request -> {
String message = request.getQueryParams().get("message");
if (message != null && !message.isEmpty()) {
chatMessagesEventHandler.sendMessage(message);
}
return StatusCode.OK.asResponse();
});
```

For a complete example, check out the [ChatServer](src/test/java/net/jonathangiles/tools/teenyhttpd/ChatServer.java)
demo application, that demonstrates how to use Server-Sent Events to create a simple chat server.

### Stopping TeenyHttpd

You stop a running instance as follows:
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
module net.jonathangiles.tools.teenyhttpd {
exports net.jonathangiles.tools.teenyhttpd;
exports net.jonathangiles.tools.teenyhttpd.request;
exports net.jonathangiles.tools.teenyhttpd.response;
exports net.jonathangiles.tools.teenyhttpd.model;
}
Loading

0 comments on commit 41df692

Please sign in to comment.