-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSpiritusChannel.psm1
More file actions
101 lines (90 loc) · 2.82 KB
/
SpiritusChannel.psm1
File metadata and controls
101 lines (90 loc) · 2.82 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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<#
SpiritusChannel class for string based inter-process communication via named pipes.
#>
class SpiritusChannel
{
hidden [System.IO.Pipes.PipeStream]$pipe
hidden [byte[]]$msgp = [System.Text.Encoding]::UTF8.GetBytes("MSGP")
hidden [byte[]]$msgi = [System.Text.Encoding]::UTF8.GetBytes("MSGI")
hidden [byte[]]$msgr = [System.Text.Encoding]::UTF8.GetBytes("MSGR")
SpiritusChannel([string]$pipeName)
{
$this.pipe = new-object System.IO.Pipes.NamedPipeServerStream(
$pipeName,
[System.IO.Pipes.PipeDirection]::InOut,
1,
[System.IO.Pipes.PipeTransmissionMode]::Byte,
[System.IO.Pipes.PipeOptions]::Asynchronous,
32768,
32768
)
}
[void] WaitForConnection([timespan]$timeout)
{
$cts = [System.Threading.CancellationTokenSource]::new($timeout)
try
{
$task = $this.pipe.WaitForConnectionAsync($cts.Token)
$task.Wait()
}
catch
{
throw "Timed out waiting for connection"
}
}
hidden [void] WriteExactly([byte[]]$data)
{
$this.pipe.Write($data,0,$data.Length)
}
hidden [byte[]] ReadExactly([int]$len)
{
$data = [byte[]]::new($len)
$idx = 0
while($idx -lt $len)
{
$done = $this.pipe.Read($data, $idx, $len)
if($done -le 0)
{
throw "Pipe closed unexpectedly"
}
$idx += $done
$len -= $done
}
#$done = $this.pipe.ReadAtLeastAsync($data, $len, $true, [System.Threading.CancellationToken]::None).AsTask().GetAwaiter().GetResult()
return $data
}
hidden [void] WriteMessage([byte[]]$tag, [string]$message)
{
$encoded = [byte[]]([System.Text.Encoding]::UTF8.GetBytes($message))
$lenData = [BitConverter]::GetBytes([int]$encoded.Length)
$this.WriteExactly($tag)
$this.WriteExactly($lenData)
$this.WriteExactly($encoded)
}
hidden [string] ReadMessage()
{
$header = $this.ReadExactly(4)
if(![System.Linq.Enumerable]::SequenceEqual($header, $this.msgr))
{
throw "invalid response type $header"
}
$lenData = $this.ReadExactly(4)
$responseLength = [BitConverter]::ToInt32($lenData)
$responseData = $this.ReadExactly($responseLength)
return [System.Text.Encoding]::UTF8.GetString($responseData)
}
hidden [void] PostMessage([string]$message)
{
$this.WriteMessage($this.msgp, $message)
}
hidden [string] InvokeMessage([string]$message)
{
$this.WriteMessage($this.msgi, $message)
return $this.ReadMessage()
}
[void] Dispose()
{
$this.pipe.Close()
$this.pipe.Dispose()
}
}