Skip to content

Commit 864f0fb

Browse files
feat: DualEventServer ( Fixes #7 )
1 parent 3674094 commit 864f0fb

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

Servers/DualEventServer.ps1

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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+
#>
9+
param(
10+
# The rootUrl of the server. By default, a random loopback address.
11+
[string]$RootUrl=
12+
"http://127.0.0.1:$(Get-Random -Minimum 4200 -Maximum 42000)/"
13+
)
14+
15+
$httpListener = [Net.HttpListener]::new()
16+
$httpListener.Prefixes.Add($RootUrl)
17+
Write-Warning "Listening on $RootUrl $($httpListener.Start())"
18+
19+
$io = [Ordered]@{ # Pack our job input into an IO dictionary
20+
HttpListener = $httpListener ; ServerRoot = $RootDirectory
21+
MainRunspace = [Runspace]::DefaultRunspace; SourceIdentifier = $RootUrl
22+
TypeMap = $TypeMap
23+
}
24+
25+
# Our server is a thread job
26+
Start-ThreadJob -ScriptBlock {param([Collections.IDictionary]$io)
27+
$psvariable = $ExecutionContext.SessionState.PSVariable
28+
foreach ($key in $io.Keys) { # First, let's unpack.
29+
if ($io[$key] -is [PSVariable]) { $psvariable.set($io[$key]) }
30+
else { $psvariable.set($key, $io[$key]) }
31+
}
32+
33+
$thisRunspace = [Runspace]::DefaultRunspace
34+
35+
# Because we are handling the event locally, the main thread can keep chugging.
36+
Register-EngineEvent -SourceIdentifier $SourceIdentifier -Action {
37+
try {
38+
$request = $event.MessageData.Request
39+
$reply = $event.MessageData.Reply
40+
41+
$timeToRespond = [DateTime]::Now - $event.TimeGenerated
42+
$myReply = "$($request.HttpMethod) $($request.Url) $($timeToRespond)"
43+
$reply.Close($OutputEncoding.GetBytes($myReply), $false)
44+
} catch {
45+
Write-Error $_
46+
}
47+
}
48+
49+
# Listen for the next request
50+
:nextRequest while ($httpListener.IsListening) {
51+
$getContext = $httpListener.GetContextAsync()
52+
while (-not $getContext.Wait(17)) { }
53+
$request, $reply =
54+
$getContext.Result.Request, $getContext.Result.Response
55+
56+
# Generate events for every request
57+
foreach ($runspace in $thisRunspace, $mainRunspace) {
58+
# by broadcasting to multiple runspaces, we can both reply and have a record.
59+
$runspace.Events.GenerateEvent(
60+
$SourceIdentifier, $httpListener, @(
61+
$getContext.Result, $request, $reply
62+
), [Ordered]@{
63+
Method = $Request.HttpMethod; Url = $request.Url
64+
Request = $request; Reply = $reply; Response = $reply
65+
ServerRoot = $ServerRoot; TypeMap = $TypeMap
66+
}
67+
)
68+
}
69+
}
70+
} -ThrottleLimit 100 -ArgumentList $IO -Name "$RootUrl" | # Output our job,
71+
Add-Member -NotePropertyMembers @{ # but attach a few properties first:
72+
HttpListener=$httpListener # * The listener (so we can stop it)
73+
IO=$IO # * The IO (so we can change it)
74+
Url="$RootUrl" # The URL (so we can easily access it).
75+
} -Force -PassThru # Pass all of that thru and return it to you.

0 commit comments

Comments
 (0)