functions/private/Invoke-KlippyHttpRequest.ps1
|
function Invoke-KlippyHttpRequest { <# .SYNOPSIS Performs HTTP requests to Moonraker for file operations. .DESCRIPTION Handles GET/POST/DELETE requests for file uploads, downloads, and management. Supports streaming downloads, multipart uploads, and authentication. .PARAMETER Printer The printer object. .PARAMETER Endpoint The API endpoint path (e.g., "/server/files/gcodes/file.gcode"). .PARAMETER Method HTTP method. Default is GET. .PARAMETER Body Request body for POST requests. .PARAMETER OutFile Path to save downloaded file (for streaming downloads). .PARAMETER InFile Path to file to upload. .PARAMETER ContentType Content type for the request. .PARAMETER QueryParameters Hashtable of query parameters. .PARAMETER Timeout Request timeout in seconds. Default is 300 (5 minutes for large files). .PARAMETER NoNormalize Skip PascalCase normalization of JSON response. .EXAMPLE Invoke-KlippyHttpRequest -Printer $printer -Endpoint "/server/files/list" -QueryParameters @{root="gcodes"} .EXAMPLE Invoke-KlippyHttpRequest -Printer $printer -Endpoint "/server/files/gcodes/test.gcode" -OutFile "C:\temp\test.gcode" .OUTPUTS PSCustomObject or file path for downloads. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [PSCustomObject]$Printer, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Endpoint, [Parameter()] [ValidateSet('GET', 'POST', 'DELETE')] [string]$Method = 'GET', [Parameter()] $Body, [Parameter()] [string]$OutFile, [Parameter()] [string]$InFile, [Parameter()] [string]$ContentType, [Parameter()] [hashtable]$QueryParameters, [Parameter()] [ValidateRange(1, 3600)] [int]$Timeout = 300, [Parameter()] [switch]$NoNormalize ) # Build URI $baseUri = $Printer.Uri.TrimEnd('/') $endpoint = $Endpoint.TrimStart('/') $uri = "$baseUri/$endpoint" # Add query parameters if ($QueryParameters -and $QueryParameters.Count -gt 0) { $queryParts = @() foreach ($key in $QueryParameters.Keys) { $value = $QueryParameters[$key] if ($null -ne $value) { $queryParts += "$key=$([System.Uri]::EscapeDataString($value.ToString()))" } } if ($queryParts.Count -gt 0) { $uri = "$uri`?$($queryParts -join '&')" } } # Build headers $headers = @{} if ($Printer.ApiKey) { $headers['X-Api-Key'] = $Printer.ApiKey } Write-Verbose "[$($Printer.PrinterName)] HTTP $Method $uri" try { $invokeParams = @{ Uri = $uri Method = $Method Headers = $headers TimeoutSec = $Timeout ErrorAction = 'Stop' } # Handle file upload if ($InFile) { if (-not (Test-Path -Path $InFile -PathType Leaf)) { throw "File not found: $InFile" } $fileName = Split-Path -Path $InFile -Leaf # Use multipart form data for file uploads $fileBytes = [System.IO.File]::ReadAllBytes($InFile) $boundary = [System.Guid]::NewGuid().ToString() $bodyLines = @( "--$boundary", "Content-Disposition: form-data; name=`"file`"; filename=`"$fileName`"", "Content-Type: application/octet-stream", "", [System.Text.Encoding]::GetEncoding("ISO-8859-1").GetString($fileBytes), "--$boundary--" ) $bodyContent = $bodyLines -join "`r`n" $invokeParams['Body'] = $bodyContent $invokeParams['ContentType'] = "multipart/form-data; boundary=$boundary" } # Handle JSON body elseif ($Body) { if ($Body -is [hashtable] -or $Body -is [PSCustomObject]) { $invokeParams['Body'] = ($Body | ConvertTo-Json -Depth 10 -Compress) $invokeParams['ContentType'] = 'application/json' } else { $invokeParams['Body'] = $Body if ($ContentType) { $invokeParams['ContentType'] = $ContentType } } } # Handle file download if ($OutFile) { # Ensure directory exists $outDir = Split-Path -Path $OutFile -Parent if ($outDir -and -not (Test-Path -Path $outDir -PathType Container)) { $null = New-Item -Path $outDir -ItemType Directory -Force } $invokeParams['OutFile'] = $OutFile Invoke-RestMethod @invokeParams Write-Verbose "File saved to: $OutFile" return $OutFile } # Standard request $response = Invoke-RestMethod @invokeParams # Extract result if wrapped $result = if ($response.result) { $response.result } else { $response } # Normalize unless disabled if (-not $NoNormalize -and ($result -is [PSCustomObject] -or $result -is [array])) { $result = ConvertTo-KlippyPascalCaseObject -InputObject $result } return $result } catch { $errorMessage = "HTTP request failed: $($_.Exception.Message)" # Try to extract API error details if ($_.ErrorDetails.Message) { try { $errorDetails = $_.ErrorDetails.Message | ConvertFrom-Json if ($errorDetails.error.message) { $errorMessage = "[$($Printer.PrinterName)] $($errorDetails.error.message)" } elseif ($errorDetails.message) { $errorMessage = "[$($Printer.PrinterName)] $($errorDetails.message)" } } catch { # Ignore JSON parsing errors } } throw $errorMessage } } |