Skip to content

Commit

Permalink
Add template for Server Sent Events (SSE)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kaliumhexacyanoferrat committed Dec 23, 2024
1 parent bf6998c commit d7de82a
Show file tree
Hide file tree
Showing 12 changed files with 332 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ To use one of the templates below, create a new folder and run `dotnet new <temp
| `genhttp-webservice-minimal` | A project that will host a new [REST web service](https://genhttp.org/documentation/content/frameworks/functional/) in a single file. |
| `genhttp-webservice-controllers` | A project that will host a new REST web service using [controllers](https://genhttp.org/documentation/content/frameworks/controllers/). |
| `genhttp-websocket` | A project providing a web socket endpoint using the [websocket](https://genhttp.org/documentation/content/frameworks/websockets/) framework. |
| `genhttp-sse` | A project providing a SSE event source using the [Server Sent Events](https://genhttp.org/documentation/content/handlers/server-sent-events/) handler. |
| `genhttp-website-static` | Project to serve a [static website](https://genhttp.org/documentation/content/frameworks/static-websites/) from the file system. |
| `genhttp-spa` | Project to serve the distribution files of a [Single Page Application](https://genhttp.org/documentation/content/frameworks/single-page-applications/). |

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>

<TargetFramework>net9.0</TargetFramework>

<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<ImplicitUsings>true</ImplicitUsings>

<IsPackable>false</IsPackable>

</PropertyGroup>

<ItemGroup>

<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />

<PackageReference Include="MSTest.TestAdapter" Version="3.6.4" />
<PackageReference Include="MSTest.TestFramework" Version="3.6.4" />

<PackageReference Include="GenHTTP.Testing" Version="9.4.0" />

<ProjectReference Include="..\$safeprojectname$\$safeprojectname$.csproj" />

</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Net;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using GenHTTP.Testing;

namespace $safeprojectname$.Tests;

[TestClass]
public class EventStreamTests
{

[TestMethod]
public async Task TestIndexServed()
{
await using var runner = await TestHost.RunAsync(Project.Setup());

using var response = await runner.GetResponseAsync();

Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>

<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>

<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<ImplicitUsings>true</ImplicitUsings>

<AssemblyVersion>0.1.0.0</AssemblyVersion>
<FileVersion>0.1.0.0</FileVersion>
<Version>0.1.0</Version>

<ServerGarbageCollection>true</ServerGarbageCollection>

</PropertyGroup>

<ItemGroup>

<PackageReference Include="GenHTTP.Core" Version="9.4.0" />

<PackageReference Include="GenHTTP.Modules.ServerSentEvents" Version="9.4.0" />

</ItemGroup>

<ItemGroup>

<EmbeddedResource Include="Resources\client.html" />

</ItemGroup>

</Project>
31 changes: 31 additions & 0 deletions Templates/ServerSentEvents/$safeprojectname$/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using GenHTTP.Engine.Internal;

using GenHTTP.Modules.Practices;

using $safeprojectname$;

//
// GenHTTP Server Sent Events Template
//
// URLs:
// http://localhost:8080/
//
// Handler documentation:
// https://genhttp.org/documentation/content/handlers/server-sent-events/
//
// Additional features:
// https://genhttp.org/documentation/content/
//

var project = Project.Setup();

return await Host.Create()
.Handler(project)
.Defaults()
.Console()
//-:cnd:noEmit
#if DEBUG
.Development()
#endif
//+:cnd:noEmit
.RunAsync();
43 changes: 43 additions & 0 deletions Templates/ServerSentEvents/$safeprojectname$/Project.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using GenHTTP.Api.Content;

using GenHTTP.Modules.IO;
using GenHTTP.Modules.Layouting;
using GenHTTP.Modules.ServerSentEvents;

namespace $safeprojectname$;

public static class Project
{

public static IHandlerBuilder Setup()
{
var client = Content.From(Resource.FromAssembly("client.html"));

var stocks = EventSource.Create()
.Generator(GenerateStock);

return Layout.Create()
.Add("stock", stocks)
.Index(client);
}

private static async ValueTask GenerateStock(IEventConnection connection)
{
var rand = new Random();

var stockSymbols = new List<string> { "AAPL", "GOOGL", "MSFT" };

await connection.CommentAsync("Sending stock data");

while (connection.Connected)
{
var symbol = stockSymbols[rand.Next(0, 3)];

await connection.DataAsync(rand.Next(100, 1000), symbol);

await Task.Delay(1000);
}

}

}
68 changes: 68 additions & 0 deletions Templates/ServerSentEvents/$safeprojectname$/Resources/client.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stock Tracker</title>
<style>
body {
font-family: Arial, sans-serif;
}
#stocks {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 20px;
}
.stock {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
background-color: #f9f9f9;
}
</style>
</head>
<body>
<h1>Stock Tracker</h1>
<div id="stocks"></div>

<script>
// Establish a connection to the server using Server-Sent Events
const eventSource = new EventSource('http://localhost:8080/stock/');

// Function to display stock updates
function updateStock(symbol, value) {
let stockElement = document.getElementById(symbol);

if (!stockElement) {
// Create a new element for the stock symbol if it doesn't exist
stockElement = document.createElement('div');
stockElement.id = symbol;
stockElement.className = 'stock';
document.getElementById('stocks').appendChild(stockElement);
}

// Update stock value
stockElement.innerHTML = `<strong>${symbol}:</strong> ${value}`;
}

// Event listener for general updates
eventSource.onmessage = function(event) {
updateStock(event.type, event.data);
};

// Event listeners for specific stock symbols
const symbols = ['AAPL', 'GOOGL', 'MSFT']; // Example stocks
symbols.forEach(symbol => {
eventSource.addEventListener(symbol, event => {
updateStock(symbol, event.data);
});
});

// Error handling
eventSource.onerror = function() {
console.error('Connection to the server lost.');
};
</script>
</body>
</html>
14 changes: 14 additions & 0 deletions Templates/ServerSentEvents/.template.config/template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "http://json.schemastore.org/template",
"author": "genhttp.org",
"classifications": [ "GenHTTP", "Server Sent Events", "SSE" ],
"identity": "GenHTTP.Templates.ServerSentEvents",
"name": "GenHTTP: Server Sent Events",
"shortName": "genhttp-sse",
"sourceName": "$safeprojectname$",
"description": "A project template to serve a SSE event stream using the GenHTTP webserver framework",
"tags": {
"language": "C#",
"type": "project"
}
}
19 changes: 19 additions & 0 deletions Templates/ServerSentEvents/Dockerfile.linux-arm32
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /source

# copy csproj and restore as distinct layers
COPY $safeprojectname$/*.csproj .
RUN dotnet restore -r linux-arm

# copy and publish app and libraries
COPY $safeprojectname$/ .
RUN dotnet publish -c release -o /app -r linux-arm --no-restore /p:PublishTrimmed=true /p:TrimMode=Link

# final stage/image
FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine-arm32v7
WORKDIR /app
COPY --from=build /app .

ENTRYPOINT ["./$safeprojectname$"]

EXPOSE 8080
19 changes: 19 additions & 0 deletions Templates/ServerSentEvents/Dockerfile.linux-arm64
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /source

# copy csproj and restore as distinct layers
COPY $safeprojectname$/*.csproj .
RUN dotnet restore -r linux-arm64

# copy and publish app and libraries
COPY $safeprojectname$/ .
RUN dotnet publish -c release -o /app -r linux-arm64 --no-restore /p:PublishTrimmed=true /p:TrimMode=Link

# final stage/image
FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine-arm64v8
WORKDIR /app
COPY --from=build /app .

ENTRYPOINT ["./$safeprojectname$"]

EXPOSE 8080
19 changes: 19 additions & 0 deletions Templates/ServerSentEvents/Dockerfile.linux-x64
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build
WORKDIR /source

# copy csproj and restore as distinct layers
COPY $safeprojectname$/*.csproj .
RUN dotnet restore -r linux-musl-x64

# copy and publish app and libraries
COPY $safeprojectname$/ .
RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore /p:PublishTrimmed=true /p:TrimMode=Link

# final stage/image
FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine
WORKDIR /app
COPY --from=build /app .

ENTRYPOINT ["./$safeprojectname$"]

EXPOSE 8080
33 changes: 33 additions & 0 deletions Templates/ServerSentEvents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# $safeprojectname$

*Add your project description here.*

## Development

To build this project from source, checkout this repository and execute
the following commands in your terminal. This requires the
[.NET SDK](https://dotnet.microsoft.com/download) to be installed.

```
cd $safeprojectname$
dotnet run
```

This will make the service available at http://localhost:8080/.

## Deployment

To run this project with [Docker](https://www.docker.com/), run the
following commands in your terminal (and adjust the first line
depending on your platform).

```
docker build -f Dockerfile.linux-x64 -t $safeprojectname$ .
docker run -p 8080:8080 $safeprojectname$
```

## About

This project uses the [GenHTTP webserver](https://genhttp.org/) to
implement its functionality.

0 comments on commit d7de82a

Please sign in to comment.