Skip to content

Commit 3674094

Browse files
feat: EventServer ( Fixes #6 )
1 parent d10bbba commit 3674094

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

Servers/EventServer.ps1

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<#
2+
.SYNOPSIS
3+
Event Server
4+
.DESCRIPTION
5+
A simple event driven server.
6+
7+
Each request will generate an event, which will be responded to by a handler.
8+
.EXAMPLE
9+
./EventServer.ps1 ($pwd | Split-Path)
10+
#>
11+
param(
12+
# The rootDirectory.
13+
[string]$RootDirectory = $PSScriptRoot,
14+
15+
# The rootUrl of the server. By default, a random loopback address.
16+
[string]$RootUrl=
17+
"http://127.0.0.1:$(Get-Random -Minimum 4200 -Maximum 42000)/",
18+
19+
# The type map. This determines how each extension will be served.
20+
[Collections.IDictionary]
21+
$TypeMap = [Ordered]@{
22+
".html" = "text/html" ; ".css" = "text/css" ; ".svg" = "image/svg+xml" ;
23+
".png" = "image/png" ; ".jpg" = "image/jpeg"; ".gif" = "image/gif"
24+
".mp3" = "audio/mpeg"; ".mp4" = "video/mp4"
25+
".json" = "application/json"; ".xml" = "application/xml" ;
26+
".js" = "text/javascript" ; ".jsm" = "text/javascript" ;
27+
}
28+
)
29+
30+
$httpListener = [Net.HttpListener]::new()
31+
$httpListener.Prefixes.Add($RootUrl)
32+
Write-Warning "Listening on $RootUrl $($httpListener.Start())"
33+
34+
$io = [Ordered]@{ # Pack our job input into an IO dictionary
35+
HttpListener = $httpListener ; ServerRoot = $RootDirectory
36+
MainRunspace = [Runspace]::DefaultRunspace; SourceIdentifier = $RootUrl
37+
TypeMap = $TypeMap
38+
}
39+
40+
# Our server is a thread job
41+
Start-ThreadJob -ScriptBlock {param([Collections.IDictionary]$io)
42+
$psvariable = $ExecutionContext.SessionState.PSVariable
43+
foreach ($key in $io.Keys) { # First, let's unpack.
44+
if ($io[$key] -is [PSVariable]) { $psvariable.set($io[$key]) }
45+
else { $psvariable.set($key, $io[$key]) }
46+
}
47+
48+
# Listen for the next request
49+
:nextRequest while ($httpListener.IsListening) {
50+
$getContext = $httpListener.GetContextAsync()
51+
while (-not $getContext.Wait(17)) { }
52+
$request, $reply =
53+
$getContext.Result.Request, $getContext.Result.Response
54+
# Generate an event for every request
55+
$mainRunspace.Events.GenerateEvent(
56+
$SourceIdentifier, $httpListener, @(
57+
$getContext.Result, $request, $reply
58+
), [Ordered]@{
59+
Method = $Request.HttpMethod; Url = $request.Url
60+
Request = $request; Reply = $reply; Response = $reply
61+
ServerRoot = $ServerRoot; TypeMap = $TypeMap
62+
}
63+
)
64+
}
65+
} -ThrottleLimit 100 -ArgumentList $IO -Name "$RootUrl" | # Output our job,
66+
Add-Member -NotePropertyMembers @{ # but attach a few properties first:
67+
HttpListener=$httpListener # * The listener (so we can stop it)
68+
IO=$IO # * The IO (so we can change it)
69+
Url="$RootUrl" # The URL (so we can easily access it).
70+
} -Force -PassThru # Pass all of that thru and return it to you.
71+
72+
# Now register a handler for these events.
73+
Register-EngineEvent -SourceIdentifier $RootUrl -Action {
74+
$request = $event.MessageData.Request
75+
$reply = $event.MessageData.Reply
76+
77+
$timeToRespond = [DateTime]::Now - $event.TimeGenerated
78+
$myReply = "$($request.HttpMethod) $($request.Url) $($timeToRespond)"
79+
$reply.Close($OutputEncoding.GetBytes($myReply), $false)
80+
}
81+
82+
# Because events are processed on the main runspace thread, this cannot Invoke-RestMethod itself.

0 commit comments

Comments
 (0)