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