Created
July 11, 2022 13:39
-
-
Save Szer/880fae06e7dedea012a4dd8a36e3b514 to your computer and use it in GitHub Desktop.
Running Kestrel from scripts is simple, you only need to...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#r "nuget: Microsoft.AspNetCore.Server.Kestrel, 2.2.0" | |
#r "nuget: Microsoft.AspNetCore.Server.Kestrel.Core, 2.2.0" | |
#r "nuget: Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv, 2.2.0" | |
#r "nuget: Microsoft.AspNetCore.WebSockets, 2.2.0" | |
#r "nuget: Ply" | |
open System | |
open System.Net.WebSockets | |
open System.Text | |
open System.Threading | |
open Microsoft.AspNetCore.Builder | |
open Microsoft.AspNetCore.Hosting | |
open Microsoft.AspNetCore.Hosting.Server | |
open Microsoft.AspNetCore.Http | |
open Microsoft.AspNetCore.Http.Features | |
open Microsoft.AspNetCore.Server.Kestrel.Core | |
open Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets | |
open Microsoft.AspNetCore.WebSockets | |
open Microsoft.Extensions.Logging.Abstractions | |
open Microsoft.Extensions.Options | |
open FSharp.Control.Tasks.Affine | |
open Microsoft.Extensions.Primitives | |
type Context = { Features: IFeatureCollection } | |
type App() = | |
let message = Encoding.ASCII.GetBytes "hello world" | |
let wsOptions = WebSocketOptions() | |
let continueRequest = RequestDelegate(fun ctx -> | |
if ctx.WebSockets.IsWebSocketRequest then | |
unitTask { | |
let! socket = ctx.WebSockets.AcceptWebSocketAsync() | |
do! socket.SendAsync(ArraySegment message, WebSocketMessageType.Text, true, CancellationToken.None) | |
let buffer = Array.zeroCreate<byte> 4096 | |
let! _ = socket.ReceiveAsync(buffer.AsMemory(), CancellationToken.None) in () | |
} | |
else | |
let buffer = ReadOnlyMemory message | |
ctx.Response.Headers.Add("Content-Type", StringValues "text/plain") | |
(ctx.Response.Body.WriteAsync buffer).AsTask() | |
) | |
let wsMiddleware = WebSocketMiddleware(continueRequest, OptionsWrapper wsOptions) | |
interface IHttpApplication<Context> with | |
member this.CreateContext ctxFeatures = { Features = ctxFeatures } | |
member this.DisposeContext(_,_) = () | |
member this.ProcessRequestAsync ctx = | |
let httpContext = new DefaultHttpContext(ctx.Features); | |
wsMiddleware.Invoke(httpContext); | |
type AppLifetime() = | |
let startedSource = new CancellationTokenSource() | |
let stoppingSource = new CancellationTokenSource() | |
let stoppedSource = new CancellationTokenSource() | |
interface IApplicationLifetime with | |
member this.ApplicationStarted = startedSource.Token | |
member this.ApplicationStopped = stoppedSource.Token | |
member this.ApplicationStopping = stoppingSource.Token | |
member this.StopApplication() = lock stoppingSource (fun _ -> | |
if not(stoppingSource.Token.IsCancellationRequested) then | |
stoppingSource.Cancel(throwOnFirstException = true) | |
) | |
let serverOptions = new KestrelServerOptions() | |
serverOptions.ListenAnyIP 8080 | |
let transportOptions = SocketTransportOptions() | |
let loggerFactory = new NullLoggerFactory() | |
let applicationLifetime = AppLifetime() | |
let transportFactory = SocketTransportFactory(OptionsWrapper(transportOptions), applicationLifetime, loggerFactory) | |
let server = new KestrelServer(OptionsWrapper<KestrelServerOptions>(serverOptions), transportFactory, loggerFactory) | |
server.StartAsync(App(), CancellationToken.None).GetAwaiter().GetResult() | |
Console.ReadLine() |> ignore |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment