Proxy/ConfigLoader.ps1

function Save-FRPConfig {
    [CmdletBinding()]  
    param(
        [Alias('s')]
        [Parameter(Mandatory)]
        [string]$Secret,

        [Alias('i')]
        [Parameter(Mandatory)]
        [string]$Identity,

        [Alias('r')]
        [Parameter(Mandatory)]
        [string]$Remote,

        [Alias('p')]
        [string]$Path = (Join-Path -Path $InstallationPath -ChildPath "config.yaml")
    )

    # Импортируем модуль powershell-yaml
    try {
        Import-Module powershell-yaml -ErrorAction Stop
    }
    catch {
        Write-Error "Error loading module powershell-yaml: $_"
        return
    }

    # Формируем данные и конвертируем в YAML
    $data = @{
        secret   = $Secret
        identity = $Identity
        remote   = $Remote
    }

    try {
        $yaml = $data | ConvertTo-Yaml
        $yaml | Out-File -FilePath $Path -Encoding utf8
        Write-Verbose "Config saved to '$Path'"
    }
    catch {
        Write-Error "Error converting to YAML: $_"
    }
}

function Get-FRPConfig {
    [CmdletBinding()]  
    param(
        [Alias('p')]
        [Parameter(Mandatory)]
        [string]$Path
    )

    # Проверяем, что файл существует
    if (-not (Test-Path -Path $Path -PathType Leaf)) {
        Throw "Файл не найден: $Path"
    }

    # Импортируем модуль powershell-yaml
    try {
        Import-Module powershell-yaml -ErrorAction Stop
    }
    catch {
        Write-Error "Error loading module powershell-yaml: $_"
        return
    }

    try {
        # Читаем содержимое файла и конвертируем из YAML
        $yamlContent = Get-Content -Path $Path -Raw -Encoding utf8
        $config = $yamlContent | ConvertFrom-Yaml
        return $config
    }
    catch {
        Write-Error "Error converting to YAML: $_"
    }
}

function Expand-Macros {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string] $Text,

        [Parameter(Mandatory)]
        [hashtable] $Variables
    )

    # Заменяем все вхождения ${VAR} на значение из $Variables
    return ($Text -replace '\$\{(\w+)\}', {
        param($match)
        $name = $match.Groups[1].Value
        if ($Variables.ContainsKey($name)) {
            return [string]$Variables[$name]
        }
        else {
            throw "Variable '$name' not found in hashtable."
        }
    })
}

function Expand-ObjectMacros {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [psobject] $Object,

        [Parameter(Mandatory)]
        [hashtable] $Variables
    )

    # Рекурсивно обходим структуры PS (словарь, массив, примитив)
    switch ($Object) {
        { $_ -is [string] } {
            return Expand-Macros -Text $Object -Variables $Variables
        }
        { $_ -is [System.Collections.IDictionary] } {
            foreach ($key in $Object.Keys) {
                $Object[$key] = Expand-ObjectMacros -Object $Object[$key] -Variables $Variables
            }
            return $Object
        }
        { $_ -is [System.Collections.IEnumerable] } {
            # Для списков и массивов
            $result = @()
            foreach ($item in $Object) {
                $result += Expand-ObjectMacros -Object $item -Variables $Variables
            }
            return $result
        }
        default {
            # Не строка, не коллекция — возвращаем как есть
            return $Object
        }
    }
}

function envsubst {
  param(
    [Parameter(ValueFromPipeline)]
    
        [string]
        $InputObject
    )

  Get-ChildItem Env: | Set-Variable
  $ExecutionContext.InvokeCommand.ExpandString($InputObject)
}

function Get-InitConfig {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string] $Path,

        [Parameter(Mandatory)]
        [hashtable] $Variables
    )

    # Читаем исходный YAML в текст
    $rawYaml = Get-Content -Path $Path -Raw -ErrorAction Stop

    # Сначала подставляем макросы прямо в тексте (если нужно в ключах/комментариях и т.п.)
    $expandedYamlText = Expand-Macros -Text $rawYaml -Variables $Variables

    # Конвертируем в PS-объект
    $yamlObject = ConvertFrom-Yaml -YamlString $expandedYamlText

    # Рекурсивно разворачиваем макросы в самих значениях (если они появились уже после парсинга)
    return Expand-ObjectMacros -Object $yamlObject -Variables $Variables
}