dev.core.tunnel.psm1

Import-Module "$PSScriptRoot\dev.core.utils.psm1" -DisableNameChecking;

$TunnelAppFolder = "$Home\AppData\Local\DevPowerShell\dev.core.tunnel";
$TunnelPackagesFolder = "${TunnelAppFolder}\packages";
$TunnelAppVersion = "1.0.0";

#
# Private functions
#

function Install-TunnelApp
{
    [CmdletBinding()]
    param ();

    $TunnelAppPath = "$TunnelPackagesFolder\HttpTunnel.${TunnelAppVersion}";
    if (!(Test-Path -Path $TunnelAppPath -PathType Container))
    {
        Write-Verbose "Installing http tunnel $TunnelAppVersion...";

        $DownloadLink = "https://github.com/Yaming-Hub/HttpTunnel/raw/main/file/HttpTunnel.${TunnelAppVersion}.nupkg";

        Invoke-WebRequest -Uri $DownloadLink -Method Get -OutFile "$TunnelPackagesFolder\HttpTunnel.${TunnelAppVersion}.zip";

        Expand-Archive -Path "$TunnelPackagesFolder\HttpTunnel.${TunnelAppVersion}.zip" -DestinationPath "$TunnelPackagesFolder\HttpTunnel.${TunnelAppVersion}";
    }
}

<#
{
  "Forward": {
    "TunnelHost": "localhost",
    "TunnelPort": 6000,
    "Apps": [F
      {
        "Port": 6001,
        "Path": "/F"
      }
    ],
    "UrlReplaceRules": [
      {
        "Name": "Replace :6001/B to :7001/B",
        "Pattern": "https://localhost:6001/B",
        "Replacement": "https://localhost:7001/B"
      }
    ]
  },
  "Backward": {
    "TunnelPort": 6000,
    "Apps": [
      {

        "Port": 6001,
        "Path": "/B"
      }
    ],
    "UrlReplaceRules": [
      {
        "Name": "Replace :6001/F to :7001/F",
        "Pattern": "https://localhost:6001/F",
        "Replacement": "https://localhost:7001/F"
      }
    ]
  }
}
#>



function New-TunnelSetting
{
    [CmdletBinding()]
    param([Parameter(Mandatory=$true)][int]$TunnelPort);

    $setting = [PSCustomObject]@{
        TunnelPort = $TunnelPort;
        Apps = @();
        UrlReplaceRules = @();
    };

    $setting.PSTypeNames.Insert(0, "Tunnel.Setting");

    return $setting;
}



#
# Public functions
#


function New-TunnelForwardSetting
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)][string]$TunnelHost, 
        [Parameter(Mandatory=$true)][int]$TunnelPort);

    $setting = New-TunnelSetting -TunnelPort $TunnelPort;
    $setting | Add-Member -MemberType NoteProperty -Name "TunnelHost" -Value $TunnelHost | Out-Null;
    $setting.PSTypeNames.Insert(0, "Tunnel.ForwardSetting");

    return $setting;
}

function New-TunnelBackwardSetting
{
    [CmdletBinding()]
    param([Parameter(Mandatory=$true)][int]$TunnelPort);

    $setting = New-TunnelSetting -TunnelPort $TunnelPort;
    $setting.PSTypeNames.Insert(0, "Tunnel.BackwardSetting");

    return $setting;
}


function Add-TunnelApp
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)][PSTypeName("Tunnel.Setting")]$Setting,
        [int]$Port,
        [string]$Path);

    # Normalize the path to "/", "/Path", "/The/Path" format.
    if (!$Path)
    {
        $Path = "/";
    }
    elseif (!$Path.StartsWith("/"))
    {
        $Path = "/" + $Path;
    }

    if ($Path -ne "/")
    {
        $Path = $Path.TrimEnd("/");
    }

    $setting.Apps += [PSCustomObject]@{ Port = $Port; Path = $Path };

    return $setting;
}


function Add-TunnelReplaceRule
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)][PSTypeName("Tunnel.Setting")]$Setting,
        [string]$Name,
        [string]$Pattern,
        [string]$Replacement);

    $setting.UrlReplaceRules += [PSCustomObject]@{ Name = $Name; Pattern = $Pattern; Replacement = $Replacement };

    return $setting;
}

function Start-Tunnel
{
    [CmdletBinding()]
    param(
        [PSTypeName("Tunnel.ForwardSetting")]$ForwardSettings,
        [PSTypeName("Tunnel.BackwardSetting")]$BackwardSettings,
        [Parameter(Mandatory=$true)][string]$Path,
        [switch]$PauseOnStart
    );

    if (!$ForwardSettings -and !$BackwardSettings)
    {
        throw "Neither ForwardSettings nor BackwardSettings is specified";
    }

    $ExecutionGuid = New-Guid;
    $ExecutionPath = "$Path\$ExecutionGuid";
    $ExecutionAppPath = "$Path\$ExecutionGuid\app";
    $ExecutionDataPath = "$Path\$ExecutionGuid\data";
    $TunnelAppPath = "$TunnelPackagesFolder\HttpTunnel.${TunnelAppVersion}";

    New-Item -Path $ExecutionAppPath -ItemType Container -Force | Out-Null;
    New-Item -Path $ExecutionDataPath -ItemType Container -Force | Out-Null;

    # Copy execution file under.
    Copy-Item -Path "$TunnelAppPath\lib\net5.0\*.*" -Destination $ExecutionAppPath;

    # Generate appsettings.json file
    $mode = @()
    if ($BackwardSettings) { $mode += "backward" };
    if ($ForwardSettings) { $mode += "forward" };

    $ShouldPauseOnStart = if ($PauseOnStart) { $true } else { $false };
    $Settings = [PSCustomObject]@{
        "PauseOnStart" = $ShouldPauseOnStart;
        "mode" = ($mode -join ",");
        "Forward" = $ForwardSettings;
        "BackwardSettings" = $BackwardSettings;
    };

    $appSettingsJson = ConvertTo-Json -InputObject $Settings -Depth 32;
    Set-Content -Path "$ExecutionAppPath\appsettings.json" -Value $appSettingsJson;

    $cmd = "${env:SystemRoot}\System32\cmd.exe";

    Write-Host "Execution Path: $ExecutionAppPath";
    Start-Process -FilePath $cmd -ArgumentList @("/c", "dotnet.exe", "$ExecutionAppPath\httptunnel.dll") -WorkingDirectory $ExecutionAppPath;
}


#
# Module Initialization
#

New-DirectoryIfNotExist -Path $TunnelPackagesFolder | Out-Null;

Install-TunnelApp;


<# Test script
$ForwardSettings = New-TunnelForwardSetting -TunnelHost 10.68.32.200 -TunnelPort 444 `
    | Add-TunnelApp -Port 444 -Path "/sts" `
    | Add-TunnelApp -Port 444 -Path "/dsapi" `
    | Add-TunnelApp -Port 444 -Path "/actions" `
    | Add-TunnelApp -Port 444 -Path "/DWEngineV2B2" `
    | Add-TunnelApp -Port 444 -Path "/ecp" `
    | Add-TunnelApp -Port 444 -Path "/swss" `
    | Add-TunnelApp -Port 444 -Path "/search" `
    | Add-TunnelApp -Port 444 -Path "/TaskEnrichment" `
    | Add-TunnelApp -Port 444 -Path "/userknowledgebase" `
    | Add-TunnelReplaceRule -Name ExchangelabsToLocalhost -Pattern "https://exchangelabs\.live-int\.com" -Replacement "https://localhost" `
    | Add-TunnelReplaceRule -Name 443To444 -Pattern "https://([\w\d\.\-_]+)(:443)?/" -Replacement "https://`$1:444/";
 
$BackwardSettings = New-TunnelBackwardSetting -TunnelPort 444 `
    | Add-TunnelApp -Port 444 -Path "/WeveNovaB2" `
    | Add-TunnelReplaceRule -Name LocalhostToExchangelabs -Pattern "https://localhost" -Replacement "https://exchangelabs.live-int.com";
 
Run-Tunnel -ForwardSettings $ForwardSettings
#>


Export-ModuleMember -Function New-TunnelForwardSetting;
Export-ModuleMember -Function New-TunnelBackwardSetting;
Export-ModuleMember -Function Add-TunnelApp;
Export-ModuleMember -Function Add-TunnelReplaceRule
Export-ModuleMember -Function Start-Tunnel;