Skip to content

Commit 82ec3a5

Browse files
author
James Brundage
committed
feat: WebSocket Server Support ( Fixes #64, Fixes #65, Fixes #66, Fixes #71, Fixes #72, Fixes #75 )
1 parent 7b25694 commit 82ec3a5

File tree

1 file changed

+131
-2
lines changed

1 file changed

+131
-2
lines changed

Commands/Get-WebSocket.ps1

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,46 @@ function Get-WebSocket {
135135
[string]
136136
$HTML,
137137

138+
# The name of the palette to use. This will include the [4bitcss](https://4bitcss.com) stylesheet.
139+
[Alias('Palette','ColorScheme','ColorPalette')]
140+
[ArgumentCompleter({
141+
param ($commandName,$parameterName,$wordToComplete,$commandAst,$fakeBoundParameters )
142+
if (-not $script:4bitcssPaletteList) {
143+
$script:4bitcssPaletteList = Invoke-RestMethod -Uri https://cdn.jsdelivr.net/gh/2bitdesigns/4bitcss@latest/docs/Palette-List.json
144+
}
145+
if ($wordToComplete) {
146+
$script:4bitcssPaletteList -match "$([Regex]::Escape($wordToComplete) -replace '\\\*', '.{0,}')"
147+
} else {
148+
$script:4bitcssPaletteList
149+
}
150+
})]
151+
[string]
152+
$PaletteName,
153+
154+
# The [Google Font](https://fonts.google.com/) name.
155+
[Parameter(ValueFromPipelineByPropertyName)]
156+
[Alias('FontName')]
157+
[string]
158+
$GoogleFont,
159+
160+
# The Google Font name to use for code blocks.
161+
# (this should be a [monospace font](https://fonts.google.com/?classification=Monospace))
162+
[Parameter(ValueFromPipelineByPropertyName)]
163+
[Alias('PreFont','CodeFontName','PreFontName')]
164+
[string]
165+
$CodeFont,
166+
167+
# A list of javascript files or urls to include in the content.
168+
[Parameter(ValueFromPipelineByPropertyName)]
169+
[string[]]
170+
$JavaScript,
171+
172+
# A javascript import map. This allows you to import javascript modules.
173+
[Parameter(ValueFromPipelineByPropertyName)]
174+
[Alias('ImportsJavaScript','JavaScriptImports','JavaScriptImportMap')]
175+
[Collections.IDictionary]
176+
$ImportMap,
177+
138178
# A collection of query parameters.
139179
# These will be appended onto the `-WebSocketUri`.
140180
[Collections.IDictionary]
@@ -488,6 +528,63 @@ function Get-WebSocket {
488528

489529
# If the listener isn't listening, start it.
490530
if (-not $httpListener.IsListening) { $httpListener.Start() }
531+
532+
$variable['SiteHeader'] = $siteHeader = @(
533+
534+
if ($Javascript) {
535+
# as well as any javascript files provided.
536+
foreach ($js in $Javascript) {
537+
if ($js -match '.js$') {
538+
"<script src='$javascript'></script>"
539+
} else {
540+
"<script type='text/javascript'>$js</script>"
541+
}
542+
}
543+
}
544+
545+
# If an import map was provided, we will include it.
546+
if ($ImportMap) {
547+
$variable['ImportMap'] = @(
548+
"<script type='importmap'>"
549+
[Ordered]@{
550+
imports = $ImportMap
551+
} | ConvertTo-Json -Depth 3
552+
"</script>"
553+
) -join [Environment]::NewLine
554+
}
555+
556+
# If a palette name was provided, we will include the 4bitcss stylesheet.
557+
if ($PaletteName) {
558+
if ($PaletteName -match '/.+?\.css$') {
559+
"<link type='text/css' rel='stylesheet' href='$PaletteName' id='4bitcss' />"
560+
561+
} else {
562+
'<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/gh/2bitdesigns/4bitcss@latest/css/.css" id="4bitcss" />' -replace '\.css', "$PaletteName.css"
563+
}
564+
}
565+
566+
# If a font name was provided, we will include the font stylesheet.
567+
if ($GoogleFont) {
568+
"<link type='text/css' rel='stylesheet' href='https://fonts.googleapis.com/css?family=$GoogleFont' id='fontname' />"
569+
"<style type='text/css'>body { font-family: '$GoogleFont'; }</style>"
570+
}
571+
572+
# If a code font was provided, we will include the code font stylesheet.
573+
if ($CodeFont) {
574+
"<link type='text/css' rel='stylesheet' href='https://fonts.googleapis.com/css?family=$CodeFont' id='codefont' />"
575+
"<style type='text/css'>pre, code { font-family: '$CodeFont'; }</style>"
576+
}
577+
578+
# and if any stylesheets were provided, we will include them.
579+
foreach ($css in $variable.StyleSheet) {
580+
if ($css -match '.css$') {
581+
"<link rel='stylesheet' href='$css' />"
582+
} else {
583+
"<style type='text/css'>$css</style>"
584+
}
585+
}
586+
)
587+
491588
$httpListener.psobject.properties.add([psnoteproperty]::new('JobVariable',$Variable), $true)
492589

493590
# While the listener is listening,
@@ -497,6 +594,24 @@ function Get-WebSocket {
497594
# and wait for it to complete.
498595
while (-not ($contextAsync.IsCompleted -or $contextAsync.IsFaulted -or $contextAsync.IsCanceled)) {
499596
# while this is going on, other events can be processed, and CTRL-C can exit.
597+
# also, we can go ahead and check for any socket requests, and get ready for the next one if we find one.
598+
foreach ($socketRequest in @($httpListener.SocketRequests.GetEnumerator())) {
599+
if ($socketRequest.Value.Receiving.IsCompleted) {
600+
$socketRequest.Value.MessageCount++
601+
$jsonMessage = ConvertFrom-Json -InputObject ($OutputEncoding.GetString($socketRequest.Value.ClientBuffer -gt 0))
602+
$socketRequest.Value.ClientBuffer.Clear()
603+
if ($MainRunspace.Events.GenerateEvent) {
604+
$MainRunspace.Events.GenerateEvent.Invoke(@(
605+
"$($request.Url.Scheme -replace '^http', 'ws')://",
606+
$httpListener,
607+
@($socketRequest.Value.Context, $socketRequest.Value.WebSocketContet, $socketRequest.Key, $socketRequest.Value),
608+
$jsonMessage
609+
))
610+
}
611+
$socketRequest.Value.Receiving =
612+
$socketRequest.Value.WebSocket.ReceiveAsync($socketRequest.Value.ClientBuffer, [Threading.CancellationToken]::None)
613+
}
614+
}
500615
}
501616
# If async method fails,
502617
if ($contextAsync.IsFaulted) {
@@ -553,7 +668,18 @@ function Get-WebSocket {
553668
$Protocol = $requestedUrl.Scheme -replace '^http', 'ws'
554669

555670
# Now add the result it to the SocketRequests lookup table, using the request trace identifier as the key.
556-
$httpListener.SocketRequests[$context.Request.RequestTraceIdentifier] = $webSocketResult
671+
$clientBuffer = $webSocketResult.WebSocket::CreateClientBuffer($BufferSize, $BufferSize)
672+
$httpListener.SocketRequests[$context.Request.RequestTraceIdentifier] = [Ordered]@{
673+
Context = $context
674+
WebSocketContext = $webSocketResult
675+
WebSocket = $webSocketResult.WebSocket
676+
ClientBuffer = $clientBuffer
677+
Created = [DateTime]::UtcNow
678+
LastMessageTime = $null
679+
Receiving = $webSocketResult.WebSocket.ReceiveAsync($clientBuffer, [Threading.CancellationToken]::None)
680+
MessageQueue = [Collections.Queue]::new()
681+
MessageCount = [long]0
682+
}
557683
# and add the websocketcontext result to the message data.
558684
$messageData["WebSocketContext"] = $webSocketResult
559685
# also add the websocket result to the message data,
@@ -612,7 +738,7 @@ function Get-WebSocket {
612738
"<html>"
613739
"<head>"
614740
# and apply the site header.
615-
$SiteHeader
741+
$SiteHeader -join [Environment]::NewLine
616742
"</head>"
617743
"<body>"
618744
$html
@@ -742,6 +868,9 @@ function Get-WebSocket {
742868
}
743869

744870
$Variable['MainRunspace'] = [Runspace]::DefaultRunspace
871+
if (-not $variable['BufferSize']) {
872+
$variable['BufferSize'] = $BufferSize
873+
}
745874
$StartThreadJobSplat = [Ordered]@{
746875
InitializationScript = $InitializationScript
747876
ThrottleLimit = $ThrottleLimit

0 commit comments

Comments
 (0)