790 lines
26 KiB
PowerShell
790 lines
26 KiB
PowerShell
# **************************************************************************
|
|
# Copyright (c) Cloud Native Foundation.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
# **************************************************************************
|
|
|
|
$xmlDataSerilizationLibPath = Join-Path (Join-Path $PSScriptRoot 'dataserialization') 'xml.ps1'
|
|
. $xmlDataSerilizationLibPath
|
|
|
|
function New-CloudEvent {
|
|
<#
|
|
.SYNOPSIS
|
|
This function creates a new cloud event.
|
|
|
|
|
|
.DESCRIPTION
|
|
This function creates a new cloud event object with the provided parameters.
|
|
The result cloud event object has no data. Use Add-CloudEvent* functions to
|
|
add data to the cloud event object.
|
|
|
|
.PARAMETER Type
|
|
Specifies the 'type' attribute of the cloud event.
|
|
|
|
.PARAMETER Source
|
|
Specifies the 'source' attribute of the cloud event.
|
|
|
|
.PARAMETER Id
|
|
Specifies the 'id' attribute of the cloud event.
|
|
|
|
.PARAMETER Time
|
|
Specifies the 'time' attribute of the cloud event.
|
|
|
|
.EXAMPLE
|
|
New-CloudEvent -Type 'com.example.object.deleted.v2' -Source 'mailto:cncf-wg-serverless@lists.cncf.io' -Id '6e8bc430-9c3a-11d9-9669-0800200c9a66' -Time (Get-Date)
|
|
|
|
Creates a cloud event with Type, Source, Id, and Time
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$Type,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[System.Uri]
|
|
$Source,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$Id,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[DateTime]
|
|
$Time
|
|
)
|
|
|
|
PROCESS {
|
|
$cloudEvent = New-Object `
|
|
-TypeName 'CloudNative.CloudEvents.CloudEvent' `
|
|
-ArgumentList @(
|
|
$Type,
|
|
$Source,
|
|
$Id,
|
|
$Time,
|
|
@())
|
|
|
|
Write-Output $cloudEvent
|
|
}
|
|
}
|
|
|
|
#region Set Data Functions
|
|
function Set-CloudEventData {
|
|
<#
|
|
.SYNOPSIS
|
|
This function sets data in a cloud event.
|
|
|
|
.DESCRIPTION
|
|
This function sets data in a cloud event object with the provided parameters.
|
|
|
|
.PARAMETER CloudEvent
|
|
Specifies the cloud event object that receives the data.
|
|
|
|
.PARAMETER Data
|
|
Specifies the data object for the cloud event 'data' attribute.
|
|
|
|
.PARAMETER DataContentType
|
|
Specifies the 'datacontenttype' attribute of the cloud event.
|
|
|
|
|
|
.EXAMPLE
|
|
$cloudEvent = New-CloudEvent -Type 'com.example.object.deleted.v2' -Source 'mailto:cncf-wg-serverless@lists.cncf.io' -Id '6e8bc430-9c3a-11d9-9669-0800200c9a66' -Time (Get-Date)
|
|
$cloudEvent | Set-CloudEventData -Data '<much wow="xml"/>' -DataContentType 'application/xml'
|
|
|
|
Sets xml data to the cloud event
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true,
|
|
ValueFromPipeline = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[CloudNative.CloudEvents.CloudEvent]
|
|
$CloudEvent,
|
|
|
|
[Parameter(Mandatory = $true,
|
|
ValueFromPipeline = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[object]
|
|
$Data,
|
|
|
|
# CloudEvent 'datacontenttype' attribute. Content type of the 'data' attribute value.
|
|
# This attribute enables the data attribute to carry any type of content, whereby
|
|
# format and encoding might differ from that of the chosen event format.
|
|
[Parameter(Mandatory = $false,
|
|
ValueFromPipeline = $false)]
|
|
[string]
|
|
$DataContentType)
|
|
|
|
PROCESS {
|
|
|
|
# https://github.com/cloudevents/spec/blob/master/spec.md#datacontenttype
|
|
$contentType = New-Object `
|
|
-TypeName 'System.Net.Mime.ContentType' `
|
|
-ArgumentList ($DataContentType)
|
|
|
|
$cloudEvent.Data = $Data
|
|
$cloudEvent.DataContentType = $dataContentType
|
|
|
|
Write-Output $CloudEvent
|
|
}
|
|
|
|
}
|
|
|
|
function Set-CloudEventJsonData {
|
|
<#
|
|
.SYNOPSIS
|
|
This function sets JSON format data in a cloud event.
|
|
|
|
.DESCRIPTION
|
|
This function converts a PowerShell hashtable to JSON format data and sets it in a cloud event.
|
|
|
|
.PARAMETER CloudEvent
|
|
Specifies the cloud event object that receives the data.
|
|
|
|
.PARAMETER Data
|
|
Specifies the PowerShell hashtable object that is set as JSON on the cloud event 'data' attribute.
|
|
The 'datacontenttype' attribute is set to 'application/json'
|
|
|
|
.PARAMETER Depth
|
|
The maximum depth of the input hashtable specified on the `Data` parameter that will be converted to JSON.
|
|
This parameter is passed on the `-Depth` parameter of the `ConvertTo-Json` cmdlet.
|
|
The default value is 3
|
|
|
|
|
|
.EXAMPLE
|
|
$cloudEvent = New-CloudEvent -Type 'com.example.object.deleted.v2' -Source 'mailto:cncf-wg-serverless@lists.cncf.io' -Id '6e8bc430-9c3a-11d9-9669-0800200c9a66' -Time (Get-Date)
|
|
$cloudEvent | Set-CloudEventJsonData -Data @{ 'key1' = 'value1'; 'key2' = 'value2'; }
|
|
|
|
Sets JSON data to the cloud event
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true,
|
|
ValueFromPipeline = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[CloudNative.CloudEvents.CloudEvent]
|
|
$CloudEvent,
|
|
|
|
[Parameter(Mandatory = $true,
|
|
ValueFromPipeline = $false)]
|
|
[ValidateNotNull()]
|
|
[Hashtable]
|
|
$Data,
|
|
|
|
[Parameter(Mandatory = $false,
|
|
ValueFromPipeline = $false)]
|
|
[int]
|
|
$Depth = 3)
|
|
|
|
PROCESS {
|
|
|
|
# DataContentType is set to 'application/json'
|
|
# https://github.com/cloudevents/spec/blob/master/spec.md#datacontenttype
|
|
$dataContentType = New-Object `
|
|
-TypeName 'System.Net.Mime.ContentType' `
|
|
-ArgumentList ([System.Net.Mime.MediaTypeNames+Application]::Json)
|
|
|
|
$cloudEvent.DataContentType = $dataContentType
|
|
$cloudEvent.Data = ConvertTo-Json -InputObject $Data -Depth $Depth
|
|
|
|
Write-Output $CloudEvent
|
|
}
|
|
|
|
}
|
|
|
|
function Set-CloudEventXmlData {
|
|
<#
|
|
.SYNOPSIS
|
|
This function sets XML format data in a cloud event.
|
|
|
|
.DESCRIPTION
|
|
This function converts a PowerShell hashtable to XML format data and sets it in a cloud event.
|
|
|
|
.PARAMETER CloudEvent
|
|
Specifies the cloud event object that receives the data.
|
|
|
|
.PARAMETER Data
|
|
Specifies the PowerShell hashtable object that is set as XML on the cloud event 'data' attribute.
|
|
The 'datacontenttype' attribute is set to 'application/xml'
|
|
|
|
.PARAMETER AttributesKeysInElementAttributes
|
|
Specifies how to format the XML. If specified and the input Data hashtable has pairs of 'Attributes', 'Value' keys
|
|
creates XML element with attributes, otherwise each key is formatted as XML element.
|
|
If true
|
|
@{'root' = @{'Attributes' = @{'att1' = 'true'}; 'Value' = 'val-1'}} would be '<root att1="true">val-1</root>'
|
|
Otherwise
|
|
@{'root' = @{'Attributes' = @{'att1' = 'true'}; 'Value' = 'val-1'}} would be '<root><Attributes><att1>true</att1></Attributes><Value>val-1</Value></root>'
|
|
|
|
|
|
.EXAMPLE
|
|
$cloudEvent = New-CloudEvent -Type 'com.example.object.deleted.v2' -Source 'mailto:cncf-wg-serverless@lists.cncf.io' -Id '6e8bc430-9c3a-11d9-9669-0800200c9a66' -Time (Get-Date)
|
|
$cloudEvent | Set-CloudEventXmlData -Data @{ 'key1' = 'value1'; 'key2' = 'value2'; } -AttributesKeysInElementAttributes $true
|
|
|
|
Sets XML data in the cloud event
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true,
|
|
ValueFromPipeline = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[CloudNative.CloudEvents.CloudEvent]
|
|
$CloudEvent,
|
|
|
|
[Parameter(Mandatory = $true,
|
|
ValueFromPipeline = $false)]
|
|
[ValidateNotNull()]
|
|
[Hashtable]
|
|
$Data,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[bool]
|
|
$AttributesKeysInElementAttributes)
|
|
|
|
PROCESS {
|
|
|
|
# DataContentType is set to 'application/xml'
|
|
$dataContentType = New-Object `
|
|
-TypeName 'System.Net.Mime.ContentType' `
|
|
-ArgumentList ([System.Net.Mime.MediaTypeNames+Application]::Xml)
|
|
|
|
$cloudEvent.DataContentType = $dataContentType
|
|
$cloudEvent.Data = ConvertTo-CEDataXml -InputObject $Data -AttributesKeysInElementAttributes $AttributesKeysInElementAttributes
|
|
|
|
Write-Output $CloudEvent
|
|
}
|
|
|
|
}
|
|
#endregion Set Data Functions
|
|
|
|
#region Read Data Functions
|
|
function Read-CloudEventData {
|
|
<#
|
|
.SYNOPSIS
|
|
This function gets the data from a cloud event.
|
|
|
|
.DESCRIPTION
|
|
This function gets the data as-is from a cloud event. It is equiualent of accessing the Data property of a CloudEvent object
|
|
|
|
.PARAMETER CloudEvent
|
|
Specifies the cloud event object to get data from.
|
|
|
|
.EXAMPLE
|
|
$cloudEvent = ConvertFrom-HttpMessage -Headers $httpResponse.Headers -Body $httpResponse.Content
|
|
$cloudEvent | Read-CloudEventData
|
|
|
|
Reads data from a cloud event received on the http response
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true,
|
|
ValueFromPipeline = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[CloudNative.CloudEvents.CloudEvent]
|
|
$CloudEvent
|
|
)
|
|
|
|
PROCESS {
|
|
Write-Output $CloudEvent.Data
|
|
}
|
|
|
|
}
|
|
|
|
function Read-CloudEventJsonData {
|
|
<#
|
|
.SYNOPSIS
|
|
This function gets JSON fromat data from a cloud event as a PowerShell hashtable.
|
|
|
|
.DESCRIPTION
|
|
This function gets the data from a cloud event and converts it to a PowerShell hashtable.
|
|
If the cloud event datacontenttype is not 'application/json' nothing is returned.
|
|
|
|
.PARAMETER CloudEvent
|
|
Specifies the cloud event object to get data from.
|
|
|
|
.PARAMETER Depth
|
|
Specifies how many levels of contained objects are included in the JSON representation. The default value is 3.
|
|
|
|
.EXAMPLE
|
|
$cloudEvent = ConvertFrom-HttpMessage -Headers $httpResponse.Headers -Body $httpResponse.Content
|
|
$hashtable = $cloudEvent | Read-CloudEventJsonData
|
|
|
|
Reads JSON data as a hashtable from a cloud event received on the http response
|
|
#>
|
|
|
|
|
|
<#
|
|
.DESCRIPTION
|
|
Returns PowerShell hashtable that represents the CloudEvent Json Data
|
|
if the data content type is 'application/json', otherwise otherwise non-terminating error and no result
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true,
|
|
ValueFromPipeline = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[CloudNative.CloudEvents.CloudEvent]
|
|
$CloudEvent,
|
|
|
|
[Parameter(Mandatory = $false,
|
|
ValueFromPipeline = $false)]
|
|
[int]
|
|
$Depth = 3
|
|
)
|
|
|
|
PROCESS {
|
|
|
|
# DataContentType is expected to be 'application/json'
|
|
# https://github.com/cloudevents/spec/blob/master/spec.md#datacontenttype
|
|
$dataContentType = New-Object `
|
|
-TypeName 'System.Net.Mime.ContentType' `
|
|
-ArgumentList ([System.Net.Mime.MediaTypeNames+Application]::Json)
|
|
|
|
if ($CloudEvent.DataContentType -eq $dataContentType -or `
|
|
($CloudEvent.DataContentType -eq $null -and ` # Datacontent Type is Optional, if it is not specified we assume it is JSON as per https://github.com/cloudevents/spec/blob/v1.0.1/spec.md#datacontenttype
|
|
$cloudEvent.Data -is [Newtonsoft.Json.Linq.JObject])) {
|
|
|
|
$data = $cloudEvent.Data
|
|
|
|
if ($cloudEvent.Data -is [byte[]]) {
|
|
$data = [System.Text.Encoding]::UTF8.GetString($data)
|
|
}
|
|
|
|
$result = $data.ToString() | ConvertFrom-Json -AsHashtable -Depth $Depth
|
|
|
|
Write-Output $result
|
|
} else {
|
|
Write-Error "Cloud Event '$($cloudEvent.Id)' has no json data"
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
function Read-CloudEventXmlData {
|
|
<#
|
|
.SYNOPSIS
|
|
This function gets XML fromat data from a cloud event as a PowerShell hashtable.
|
|
|
|
.DESCRIPTION
|
|
This function gets the data from a cloud event and converts it to a PowerShell hashtable.
|
|
If the cloud event datacontenttype is not 'application/xml' nothing is returned.
|
|
|
|
.PARAMETER CloudEvent
|
|
Specifies the cloud event object to get data from.
|
|
|
|
.PARAMETER ConvertMode
|
|
Specifies the how to convert the xml data to a hashtable
|
|
'SkipAttributes' - Skips attributes of the XML elements. XmlElement is represented as a
|
|
Key-Value pair where key is the xml element name, and the value is the xml element inner text
|
|
|
|
Example:
|
|
"<key att='true'>value1</key>" is converted to
|
|
@{'key' = 'value-1'}
|
|
|
|
'AlwaysAttrValue' - Each element is represented as a hashtable with two keys
|
|
'Attributes' - key-value pair of the cml element attributes if any, otherwise null
|
|
'Value' - string value represinting the xml element inner text
|
|
|
|
Example:
|
|
"<key1 att='true'>value1</key1><key2>value2</key2>" is converted to
|
|
@{
|
|
'key1' = @{
|
|
'Attributes' = @{
|
|
'att' = 'true'
|
|
}
|
|
'Value' = 'value1'
|
|
}
|
|
'key2' = @{
|
|
'Attributes' = $null
|
|
'Value' = 'value2'
|
|
}
|
|
|
|
}
|
|
'AttrValueWhenAttributes' - Uses 'SkipAttributes' for xml elements without attributes and
|
|
'AlwaysAttrValue' for xml elements with attributes
|
|
Example:
|
|
"<key1 att='true'>value1</key1><key2>value2</key2>" is converted to
|
|
@{
|
|
'key1' = @{
|
|
'Attributes' = @{
|
|
'att' = 'true'
|
|
}
|
|
'Value' = 'value1'
|
|
}
|
|
'key2' = 'value2'
|
|
}
|
|
|
|
.EXAMPLE
|
|
$cloudEvent = ConvertFrom-HttpMessage -Headers $httpResponse.Headers -Body $httpResponse.Content
|
|
$hashtable = $cloudEvent | Read-CloudEventXmlData -ConvertMode AttrValueWhenAttributes
|
|
|
|
Reads XML data as a hashtable from a cloud event received on the http response
|
|
#>
|
|
|
|
|
|
<#
|
|
.DESCRIPTION
|
|
Returns PowerShell hashtable that represents the CloudEvent Xml Data
|
|
if the data content type is 'application/xml', otherwise non-terminating error and no result
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true,
|
|
ValueFromPipeline = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[CloudNative.CloudEvents.CloudEvent]
|
|
$CloudEvent,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateSet("SkipAttributes", "AlwaysAttrValue", "AttrValueWhenAttributes")]
|
|
[string]
|
|
$ConvertMode
|
|
)
|
|
|
|
PROCESS {
|
|
|
|
# DataContentType is expected to be 'application/xml'
|
|
$dataContentType = New-Object `
|
|
-TypeName 'System.Net.Mime.ContentType' `
|
|
-ArgumentList ([System.Net.Mime.MediaTypeNames+Application]::Xml)
|
|
|
|
if ($CloudEvent.DataContentType -eq $dataContentType) {
|
|
|
|
$data = $cloudEvent.Data
|
|
|
|
if ($cloudEvent.Data -is [byte[]]) {
|
|
$data = [System.Text.Encoding]::UTF8.GetString($data)
|
|
}
|
|
|
|
$result = $data.ToString() | ConvertFrom-CEDataXml -ConvertMode $ConvertMode
|
|
|
|
Write-Output $result
|
|
} else {
|
|
Write-Error "Cloud Event '$($cloudEvent.Id)' has no xml data"
|
|
}
|
|
}
|
|
|
|
}
|
|
#endregion Read Data Functions
|
|
|
|
#region HTTP Protocol Binding Conversion Functions
|
|
function ConvertTo-HttpMessage {
|
|
<#
|
|
.SYNOPSIS
|
|
This function converts a cloud event object to a Http Message.
|
|
|
|
.DESCRIPTION
|
|
This function converts a cloud event object to a PSObject with Headers and Body properties.
|
|
The 'Headers' propery is a hashtable that can pe provided to the 'Headers' parameter of the Inveok-WebRequest cmdlet.
|
|
The 'Body' propery is byte[] that can pe provided to the 'Body' parameter of the Inveok-WebRequest cmdlet.
|
|
|
|
.PARAMETER CloudEvent
|
|
Specifies the cloud event object to convert.
|
|
|
|
.PARAMETER ContentMode
|
|
Specifies the cloud event content mode. Structured and Binary content modes are supporterd.
|
|
|
|
.EXAMPLE
|
|
$cloudEvent = New-CloudEvent -Type 'com.example.object.deleted.v2' -Source 'mailto:cncf-wg-serverless@lists.cncf.io' -Id '6e8bc430-9c3a-11d9-9669-0800200c9a66' -Time (Get-Date)
|
|
$cloudEvent | Add-CloudEventJsonData -Data @{ 'key1' = 'value1'; 'key2' = 'value2'; }
|
|
|
|
$cloudEvent | ConvertTo-HttpMessage -ContentMode Binary
|
|
|
|
Converts a cloud event object to Headers and Body formatted in Binary content mode.
|
|
|
|
.EXAMPLE
|
|
$cloudEvent = New-CloudEvent -Type 'com.example.object.deleted.v2' -Source 'mailto:cncf-wg-serverless@lists.cncf.io' -Id '6e8bc430-9c3a-11d9-9669-0800200c9a66' -Time (Get-Date)
|
|
$cloudEvent | Add-CloudEventJsonData -Data @{ 'key1' = 'value1'; 'key2' = 'value2'; }
|
|
|
|
$cloudEvent | ConvertTo-HttpMessage -ContentMode Structured
|
|
|
|
Converts a cloud event object to Headers and Body formatted in Structured content mode.
|
|
|
|
.EXAMPLE
|
|
$httpMessage = New-CloudEvent -Type 'com.example.object.deleted.v2' -Source 'mailto:cncf-wg-serverless@lists.cncf.io' -Id '6e8bc430-9c3a-11d9-9669-0800200c9a66' -Time (Get-Date) | `
|
|
Add-CloudEventJsonData -Data @{ 'key1' = 'value1'; 'key2' = 'value2'; } | `
|
|
ConvertTo-HttpMessage -ContentMode Structured
|
|
|
|
Invoke-WebRequest -Uri 'http://localhost:52673/' -Headers $httpMessage.Headers -Body $httpMessage.Body
|
|
|
|
Sends a cloud event http requests to a server
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(
|
|
Mandatory = $true,
|
|
ValueFromPipeline = $true,
|
|
ValueFromPipelineByPropertyName = $false)]
|
|
[ValidateNotNull()]
|
|
[CloudNative.CloudEvents.CloudEvent]
|
|
$CloudEvent,
|
|
|
|
[Parameter(
|
|
Mandatory = $true,
|
|
ValueFromPipeline = $false,
|
|
ValueFromPipelineByPropertyName = $false)]
|
|
[CloudNative.CloudEvents.ContentMode]
|
|
$ContentMode)
|
|
|
|
PROCESS {
|
|
# Output Object
|
|
$result = New-Object -TypeName PSCustomObject
|
|
|
|
$cloudEventFormatter = New-Object 'CloudNative.CloudEvents.JsonEventFormatter'
|
|
|
|
$HttpHeaderPrefix = "ce-";
|
|
$SpecVersionHttpHeader1 = $HttpHeaderPrefix + "cloudEventsVersion";
|
|
$SpecVersionHttpHeader2 = $HttpHeaderPrefix + "specversion";
|
|
|
|
$headers = @{}
|
|
|
|
# Build HTTP headers
|
|
foreach ($attribute in $cloudEvent.GetAttributes()) {
|
|
if (-not $attribute.Key.Equals([CloudNative.CloudEvents.CloudEventAttributes]::DataAttributeName($cloudEvent.SpecVersion)) -and `
|
|
-not $attribute.Key.Equals([CloudNative.CloudEvents.CloudEventAttributes]::DataContentTypeAttributeName($cloudEvent.SpecVersion))) {
|
|
if ($attribute.Value -is [string]) {
|
|
$headers.Add(($HttpHeaderPrefix + $attribute.Key), $attribute.Value.ToString())
|
|
}
|
|
elseif ($attribute.Value -is [DateTime]) {
|
|
$headers.Add(($HttpHeaderPrefix + $attribute.Key), $attribute.Value.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ'))
|
|
}
|
|
elseif ($attribute.Value -is [Uri] -or $attribute.Value -is [int]) {
|
|
$headers.Add(($HttpHeaderPrefix + $attribute.Key), $attribute.Value.ToString())
|
|
}
|
|
else
|
|
{
|
|
$headers.Add(($HttpHeaderPrefix + $attribute.Key),
|
|
[System.Text.Encoding]::UTF8.GetString($cloudEventFormatter.EncodeAttribute($cloudEvent.SpecVersion, $attribute.Key,
|
|
$attribute.Value,
|
|
$cloudEvent.Extensions.Values)));
|
|
}
|
|
}
|
|
}
|
|
|
|
# Add Headers property to the output object
|
|
$result | Add-Member -MemberType NoteProperty -Name 'Headers' -Value $headers
|
|
|
|
# Process Structured Mode
|
|
# Structured Mode supports non-batching JSON format only
|
|
# https://github.com/cloudevents/spec/blob/v1.0.1/http-protocol-binding.md#14-event-formats
|
|
if ($ContentMode -eq [CloudNative.CloudEvents.ContentMode]::Structured) {
|
|
# Format Body as byte[]
|
|
$contentType = $null
|
|
|
|
# CloudEventFormatter is instance of 'CloudNative.CloudEvents.JsonEventFormatter' from the
|
|
# .NET CloudEvents SDK for the purpose of fomatting structured mode
|
|
$buffer = $cloudEventFormatter.EncodeStructuredEvent($cloudEvent, [ref] $contentType)
|
|
$result | Add-Member -MemberType NoteProperty -Name 'Body' -Value $buffer
|
|
$result.Headers.Add('Content-Type', $contentType)
|
|
}
|
|
|
|
# Process Binary Mode
|
|
if ($ContentMode -eq [CloudNative.CloudEvents.ContentMode]::Binary) {
|
|
$bodyData = $null
|
|
|
|
if ($cloudEvent.DataContentType -ne $null) {
|
|
$result.Headers.Add('Content-Type', $cloudEvent.DataContentType)
|
|
}
|
|
|
|
if ($cloudEvent.Data -is [byte[]]) {
|
|
$bodyData = $cloudEvent.Data
|
|
}
|
|
elseif ($cloudEvent.Data -is [string]) {
|
|
$bodyData = [System.Text.Encoding]::UTF8.GetBytes($cloudEvent.Data.ToString())
|
|
}
|
|
elseif ($cloudEvent.Data -is [IO.Stream]) {
|
|
$buffer = New-Object 'byte[]' -ArgumentList 1024
|
|
|
|
$ms = New-Object 'IO.MemoryStream'
|
|
|
|
try {
|
|
$read = 0
|
|
while (($read = $cloudEvent.Data.Read($buffer, 0, 1024)) -gt 0)
|
|
{
|
|
$ms.Write($buffer, 0, $read);
|
|
}
|
|
$bodyData = $ms.ToArray()
|
|
} finally {
|
|
$ms.Dispose()
|
|
}
|
|
|
|
} else {
|
|
$bodyData = $cloudEventFormatter.EncodeAttribute($cloudEvent.SpecVersion,
|
|
[CloudNative.CloudEvents.CloudEventAttributes]::DataAttributeName($cloudEvent.SpecVersion),
|
|
$cloudEvent.Data, $cloudEvent.Extensions.Values)
|
|
}
|
|
|
|
# Add Body property to the output object
|
|
$result | Add-Member -MemberType NoteProperty -Name 'Body' -Value $bodyData
|
|
}
|
|
|
|
Write-Output $result
|
|
}
|
|
}
|
|
|
|
function ConvertFrom-HttpMessage {
|
|
<#
|
|
.SYNOPSIS
|
|
This function converts a Http Message to a cloud event object
|
|
|
|
.DESCRIPTION
|
|
This function converts a Http Message (Headers and Body) to a cloud event object.
|
|
Result of Invoke-WebRequest that contains a cloud event can be passed as input to this
|
|
function binding the the 'Headers' and 'Content' properties to the 'Headers' and 'Body' paramters.
|
|
|
|
.PARAMETER Headers
|
|
Specifies the Http Headers as a PowerShell hashtable.
|
|
|
|
.PARAMETER Body
|
|
Specifies the Http body as string or byte[].
|
|
|
|
.EXAMPLE
|
|
$httpReponse = Invoke-WebRequest -Uri 'http://localhost:52673/' -Headers $httpMessage.Headers -Body $httpMessage.Body
|
|
$cloudEvent = ConvertFrom-HttpMessage -Headers $httpResponse.Headers -Body $httpResponse.Content
|
|
|
|
Converts a http response to a cloud event object
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(
|
|
Mandatory = $true,
|
|
ValueFromPipeline = $false,
|
|
ValueFromPipelineByPropertyName = $false)]
|
|
[ValidateNotNull()]
|
|
[hashtable]
|
|
$Headers,
|
|
|
|
[Parameter(
|
|
Mandatory = $false,
|
|
ValueFromPipeline = $false,
|
|
ValueFromPipelineByPropertyName = $false)]
|
|
[ValidateNotNull()]
|
|
$Body)
|
|
|
|
PROCESS {
|
|
$HttpHeaderPrefix = "ce-";
|
|
$SpecVersionHttpHeader1 = $HttpHeaderPrefix + "cloudEventsVersion";
|
|
$SpecVersionHttpHeader2 = $HttpHeaderPrefix + "specversion";
|
|
|
|
$result = $null
|
|
|
|
# Always Convert Body to byte[]
|
|
# Conversion works with byte[] while
|
|
# body can be string in HTTP responses
|
|
# for text content type
|
|
if ($Body -is [string]) {
|
|
$Body = [System.Text.Encoding]::UTF8.GetBytes($Body)
|
|
}
|
|
|
|
if ($Headers['Content-Type'] -ne $null) {
|
|
$ContentType = $Headers['Content-Type']
|
|
if ($ContentType -is [array]) {
|
|
# Get the first content-type value
|
|
$ContentType = $ContentType[0]
|
|
}
|
|
|
|
if ($ContentType.StartsWith([CloudNative.CloudEvents.CloudEvent]::MediaType,
|
|
[StringComparison]::InvariantCultureIgnoreCase)) {
|
|
|
|
# Handle Structured Mode
|
|
$ctParts = $ContentType.Split(';')
|
|
if ($ctParts[0].Trim().StartsWith(([CloudNative.CloudEvents.CloudEvent]::MediaType) + ([CloudNative.CloudEvents.JsonEventFormatter]::MediaTypeSuffix),
|
|
[StringComparison]::InvariantCultureIgnoreCase)) {
|
|
|
|
# Structured Mode supports non-batching JSON format only
|
|
# https://github.com/cloudevents/spec/blob/v1.0.1/http-protocol-binding.md#14-event-formats
|
|
|
|
# .NET SDK 'CloudNative.CloudEvents.JsonEventFormatter' type is used
|
|
# to decode the Structured Mode CloudEvents
|
|
|
|
$json = [System.Text.Encoding]::UTF8.GetString($Body)
|
|
$jObject = [Newtonsoft.Json.Linq.JObject]::Parse($json)
|
|
$formatter = New-Object 'CloudNative.CloudEvents.JsonEventFormatter'
|
|
$result = $formatter.DecodeJObject($jObject, $null)
|
|
|
|
$result.Data = $result.Data
|
|
} else {
|
|
# Throw error for unsupported encoding
|
|
throw "Unsupported CloudEvents encoding"
|
|
}
|
|
} else {
|
|
# Handle Binary Mode
|
|
$version = [CloudNative.CloudEvents.CloudEventsSpecVersion]::Default
|
|
if ($Headers.Contains($SpecVersionHttpHeader1)) {
|
|
$version = [CloudNative.CloudEvents.CloudEventsSpecVersion]::V0_1
|
|
}
|
|
|
|
if ($Headers.Contains($SpecVersionHttpHeader2)) {
|
|
if ($Headers[$SpecVersionHttpHeader2][0] -eq "0.2") {
|
|
$version = [CloudNative.CloudEvents.CloudEventsSpecVersion]::V0_2
|
|
} elseif ($Headers[$SpecVersionHttpHeader2][0] -eq "0.3") {
|
|
$version = [CloudNative.CloudEvents.CloudEventsSpecVersion]::V0_3
|
|
}
|
|
}
|
|
|
|
$cloudEvent = New-Object `
|
|
-TypeName 'CloudNative.CloudEvents.CloudEvent' `
|
|
-ArgumentList @($version, $null);
|
|
|
|
$attributes = $cloudEvent.GetAttributes();
|
|
|
|
# Get attributes from HTTP Headers
|
|
foreach ($httpHeader in $Headers.GetEnumerator()) {
|
|
if ($httpHeader.Key.Equals($SpecVersionHttpHeader1, [StringComparison]::InvariantCultureIgnoreCase) -or `
|
|
$httpHeader.Key.Equals($SpecVersionHttpHeader2, [StringComparison]::InvariantCultureIgnoreCase)) {
|
|
continue
|
|
}
|
|
|
|
if ($httpHeader.Key.StartsWith($HttpHeaderPrefix, [StringComparison]::InvariantCultureIgnoreCase)) {
|
|
$headerValue = $httpHeader.Value
|
|
if ($headerValue -is [array]) {
|
|
# Get the first object
|
|
$headerValue = $headerValue[0]
|
|
}
|
|
$name = $httpHeader.Key.Substring(3);
|
|
|
|
# Abolished structures in headers in 1.0
|
|
if ($version -ne [CloudNative.CloudEvents.CloudEventsSpecVersion]::V0_1 -and `
|
|
$headerValue -ne $null -and `
|
|
$headerValue.StartsWith('"') -and `
|
|
$headerValue.EndsWith('"') -or `
|
|
$headerValue.StartsWith("'") -and $headerValue.EndsWith("'") -or `
|
|
$headerValue.StartsWith("{") -and $headerValue.EndsWith("}") -or `
|
|
$headerValue.StartsWith("[") -and $headerValue.EndsWith("]")) {
|
|
|
|
$jsonFormatter = New-Object 'CloudNative.CloudEvents.JsonEventFormatter'
|
|
|
|
$attributes[$name] = $jsonFormatter.DecodeAttribute($version, $name,
|
|
[System.Text.Encoding]::UTF8.GetBytes($headerValue), $null);
|
|
} else {
|
|
$attributes[$name] = $headerValue
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($Headers['Content-Type'] -ne $null -and $Headers['Content-Type'][0] -is [string]) {
|
|
$cloudEvent.DataContentType = New-Object 'System.Net.Mime.ContentType' -ArgumentList @($Headers['Content-Type'][0])
|
|
}
|
|
|
|
# Get Data from HTTP Body
|
|
$cloudEvent.Data = $Body
|
|
|
|
$result = $cloudEvent
|
|
}
|
|
}
|
|
|
|
Write-Output $result
|
|
}
|
|
}
|
|
#endregion HTTP Protocol Binding Conversion Functions |