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 Get-InitConfig { [CmdletBinding()] param ( [Parameter(Mandatory)] [string]$Path ) # Ensure the 'powershell-yaml' module is available if (-not (Get-Module -ListAvailable -Name powershell-yaml)) { throw "Module 'powershell-yaml' is required. Install it via 'Install-Module powershell-yaml'." } Import-Module powershell-yaml # Session cache: @{ Path => @{ LastWriteTime, Data } } if (-not $script:__YamlCache) { $script:__YamlCache = @{} } $resolvedPath = (Resolve-Path $Path).Path $lastWrite = (Get-Item $resolvedPath).LastWriteTimeUtc # Return cached if unchanged if ($script:__YamlCache.ContainsKey($resolvedPath)) { $entry = $script:__YamlCache[$resolvedPath] if ($entry.LastWriteTime -eq $lastWrite) { return $entry.Data } } # Parse YAML $raw = Get-Content $resolvedPath -Raw $parsed = ConvertFrom-Yaml $raw # Build custom macros from 'variables:' section $macros = @{} if ($parsed.variables) { foreach ($var in $parsed.variables) { if ($var.name -and $var.value) { $val = [Environment]::ExpandEnvironmentVariables($var.value) $macros[$var.name] = $val } } } # Recursive expander: ENV vars, custom macros, then normalize paths function Expand-Values($obj) { if ($obj -is [hashtable]) { $h = @{} foreach ($k in $obj.Keys) { if ($k -eq 'variables') { continue } $h[$k] = Expand-Values($obj[$k]) } return $h } elseif ($obj -is [System.Collections.IEnumerable] -and -not ($obj -is [string])) { return $obj | ForEach-Object { Expand-Values($_) } } elseif ($obj -is [string]) { # 1) Expand Windows ENV vars (%VAR%) $s = [Environment]::ExpandEnvironmentVariables($obj) # 2) Expand each custom macro foreach ($name in $macros.Keys) { $val = $macros[$name] $nameEsc = [regex]::Escape($name) # Windows style: %MacroName% $patternWin = [regex]::Escape("%$name%") $s = $s -replace $patternWin, $val # UNIX style: ${MacroName} $patternBr = [regex]::Escape('${') + $nameEsc + [regex]::Escape('}') $s = $s -replace $patternBr, $val # UNIX style: $MacroName (word boundary after) $patternSi = [regex]::Escape('$') + $nameEsc + '\b' $s = $s -replace $patternSi, $val } # 3) Normalize path separators and resolve # a) Turn all forward-slashes into backslashes $s = $s -replace '/', [System.IO.Path]::DirectorySeparatorChar # b) Let GetFullPath clean up things like '..' try { $s = [System.IO.Path]::GetFullPath($s) } catch { # leave as-is if not a valid path } return $s } else { return $obj } } $expanded = Expand-Values($parsed) # Cache and return $script:__YamlCache[$resolvedPath] = @{ LastWriteTime = $lastWrite Data = $expanded } return $expanded } |