Private/Http.psm1

#!/usr/bin/env pwsh
using namespace System
using namespace System.Collections.Generic

using module ./Auth.psm1
using module ./Constants.psm1
using module ./Enums.psm1

class HttpMethod {
  static [string] $Get = "GET"
  static [string] $Post = "POST"
  static [string] $Patch = "PATCH"
  static [string] $Put = "PUT"
  static [string] $Delete = "DELETE"
}

class Response {
  [int] $StatusCode
  [string] $Content
  [System.Collections.IDictionary] $Headers

  Response([int]$statusCode, [string]$content, [System.Collections.IDictionary]$headers) {
    $this.StatusCode = $statusCode
    $this.Content = $content
    $this.Headers = $headers
  }
}

class TwilioRequest {
  hidden static [string] $DEFAULT_REGION = "us1"

  [string] $Method
  [System.Uri] $Uri
  [string] $Username
  [string] $Password
  [AuthStrategy] $AuthStrategy
  [string] $Region
  [string] $Edge
  [string[]] $UserAgentExtensions

  [List[KeyValuePair[string, string]]] $QueryParams
  [List[KeyValuePair[string, string]]] $PostParams
  [List[KeyValuePair[string, string]]] $HeaderParams

  [TwilioContentType] $ContentType
  [string] $Body

  TwilioRequest([string]$method, [string]$url) {
    $this.Method = $method
    $this.Uri = [System.Uri]::new($url)
    $this.QueryParams = [List[KeyValuePair[string, string]]]::new()
    $this.PostParams = [List[KeyValuePair[string, string]]]::new()
    $this.HeaderParams = [List[KeyValuePair[string, string]]]::new()
  }

  [void] SetAuth([string]$username, [string]$passw0rd) {
    $this.Username = $username
    $this.Password = $passw0rd
    $this.AuthStrategy = $null
  }

  [void] SetAuth([AuthStrategy]$authStrategy) {
    $this.AuthStrategy = $authStrategy
    $this.Username = $null
    $this.Password = $null
  }

  [System.Uri] buildUri() {
    if ($null -ne $this.Region -or $null -ne $this.Edge) {
      $uriBuilder = [System.UriBuilder]::new($this.Uri)
      $pieces = $uriBuilder.Host.Split('.')
      $product = $pieces[0]
      $domain = $pieces[($pieces.Length - 2)..($pieces.Length - 1)] -join "."

      $localRegion = $this.Region
      $localEdge = $this.Edge

      if ($pieces.Length -eq 4) {
        # product.region.twilio.com
        if ($null -eq $localRegion) { $localRegion = $pieces[1] }
      } elseif ($pieces.Length -eq 5) {
        # product.edge.region.twilio.com
        if ($null -eq $localEdge) { $localEdge = $pieces[1] }
        if ($null -eq $localRegion) { $localRegion = $pieces[2] }
      }

      if ($null -ne $localEdge -and $null -eq $localRegion) {
        $localRegion = [TwilioRequest]::DEFAULT_REGION
      }

      $parts = @($product, $localEdge, $localRegion, $domain) | Where-Object { ![string]::IsNullOrEmpty($_) }
      $uriBuilder.Host = $parts -join "."
      return $uriBuilder.Uri
    }
    return $this.Uri
  }

  [System.Uri] ConstructUrl() {
    $uriResult = $this.buildUri()
    if ($this.QueryParams.Count -gt 0) {
      $qs = @()
      foreach ($pair in $this.QueryParams) {
        $qs += ([System.Web.HttpUtility]::UrlEncode($pair.Key) + "=" + [System.Web.HttpUtility]::UrlEncode($pair.Value))
      }
      return [System.Uri]::new($uriResult.AbsoluteUri + "?" + ($qs -join "&"))
    }
    return $uriResult
  }

  [byte[]] EncodePostParams() {
    if ($this.PostParams.Count -eq 0) { return @() }
    $ps = @()
    foreach ($pair in $this.PostParams) {
      $ps += ([System.Web.HttpUtility]::UrlEncode($pair.Key) + "=" + [System.Web.HttpUtility]::UrlEncode($pair.Value))
    }
    return [System.Text.Encoding]::UTF8.GetBytes(($ps -join "&"))
  }

  [void] AddQueryParam([string]$name, [string]$value) {
    $this.QueryParams.Add([KeyValuePair[string, string]]::new($name, $value))
  }

  [void] AddPostParam([string]$name, [string]$value) {
    $this.PostParams.Add([KeyValuePair[string, string]]::new($name, $value))
  }

  [void] AddHeaderParam([string]$name, [string]$value) {
    $this.HeaderParams.Add([KeyValuePair[string, string]]::new($name, $value))
  }
}