modules/Downloader/RedashSimple/RedashSimpleDownloader.psm1

using module '..\..\Enums.psm1'
using module '..\..\Helper\ObjectHelper.psm1'
using module '..\..\SessionConfig.psm1'
using module '..\DownloaderBase.psm1'

class RedashSimpleDownloader: Downloader{
    #region Private Properties

    hidden $DATE_FORMAT = 'yyyy-MM-dd HH:mm:ss'

    # Urls to query audit log files
    hidden [string] $urlInit
    hidden [string] $urlInitMatchId = '{0}://{1}/api/queries/{2}/refresh?p_matchId={3}'
    hidden [string] $urlInitDateRange = '{0}://{1}/api/queries/{2}/refresh?p_date_send.start={3}&p_date_send.end={4}'

    hidden [string] $urlJob = '{0}://{1}/api/queries/{2}/jobs/{3}'
    hidden [string] $urlJobTemplate = '{0}://{1}/api/queries/{2}/jobs/{3}'
    hidden [string] $urlResult = '{0}://{1}/api/queries/{2}/results/{3}.{4}'
    hidden [string] $urlResultTemplate = '{0}://{1}/api/queries/{2}/results/{3}.{4}'

    hidden [string] $protocol
    hidden [string] $url
    hidden [string] $token
    hidden [hashtable] $queries

    #endregion

    #region Constructor

    RedashSimpleDownloader([SessionConfig] $config): base($config){
        $this.config = $config

        $this.protocol = $config.downloader.protocol
        $this.url = $config.downloader.url
        $this.token = $config.downloader.token
        $this.fileExtension = $config.downloader.fileExtension

        $this.queries = @{}
        foreach ($source in $config.downloader.sources.PSObject.Properties){
            if ($source.Value){
                $this.queries.Add([SOURCE]($source.Name), $source.Value)
            }
        }
    }

    #endregion

    #region Private Methods

    hidden [hashtable] Download([hashtable] $headers, [SOURCE] $source, [int] $queryId, [bool] $runAsJob){
        $retValue = @{}

        switch ($this.config.queryType){
            ([QUERY_TYPE]::matchId) {
                $this.urlInit = ($this.urlInitMatchId -f @($this.protocol, $this.url, '{0}', $this.config.matchId))
            }
            ([QUERY_TYPE]::datetimeInterval) {
                $this.urlInit = ($this.urlInitDateRange -f @($this.protocol, $this.url, '{0}', `
                    $this.config.afterDateTime.ToString($this.DATE_FORMAT), $this.config.beforeDateTime.ToString($this.DATE_FORMAT)))
            }
            ([QUERY_TYPE]::combined) {
                # Combined mode in this downloader is not supported. Instead of that by match is used
                $this.urlInit = ($this.urlInitMatchId -f @($this.protocol, $this.url, '{0}', $this.config.matchId))
            }
        }

        Write-Host ("Download {0} audit log :: " -f $source) -NoNewline

        if (-not $queryId){
            Write-Host "Missing queryId, aborting download!"
            continue
        }
        $this.urlInit = ($this.urlInit -f $queryId)

        try {
            #Write-Debug ('Url: {0}' -f $this.urlInit)
            $json = Invoke-WebRequest -Method POST -Uri $this.urlInit -Headers $headers | ConvertFrom-Json
        }
        catch {
            throw ('Web request to ''{0}'' has failed: {1}!' -f @($this.urlInit, $_))
        }

        $jobId = $json.job.id
        $this.urlJob = ($this.urlJobTemplate -f @($this.protocol, $this.url, $queryId, $jobId))

        Write-Host ('Waiting for redash {0}' -f $jobId) -NoNewline
        while ($json.job.status -lt 3) {
            Start-Sleep -Seconds 1
            Write-Host '.' -NoNewline

            try {
                $json = Invoke-WebRequest -Method GET -Uri $this.urlJob -Headers $headers
                $json = $json | ConvertFrom-Json
            }
            catch {
                throw 'Problems during the request execution.'
            }
        }

        $this.urlResult = ($this.urlResultTemplate -f @($this.protocol, $this.url, $queryId, $json.job.query_result_id, $this.fileExtension))

        # Job is successfully executed (status: 3)
        if ($json.job.status -eq 3) {
            Write-Host ' :: Downloading' -NoNewline

            $this.fileName = $this.config.getFileName($source, $this.fileExtension)

            try {
                if ($runAsJob){
                    $job = Start-Job -Name ('{0}' -f @($source)) -ScriptBlock {
                        param($url, $headers, $fileName) (
                            Invoke-WebRequest -Method GET -Uri $url -Headers $headers -OutFile $this.fileName -TimeoutSec 300 -UseBasicParsing
                         )} -ArgumentList ($this.urlResult, $headers, $this.fileName)

                    $retValue.Add($source, $job)
                }
                else {
                    Invoke-WebRequest -Method GET -Uri $this.urlResult -Headers $headers -OutFile $this.fileName -TimeoutSec 300 -UseBasicParsing
                }
            }
            catch {
                Write-Host ''
                throw ('Error while downloading the logs, message: {0}' -f $_)
            }

            Write-Host ' :: Saved!'
        }
        else {
            Write-Host ' :: Redash request failed!'
        }
        #Write-Debug ("Redash job: {0} downloaded" -f ($json.job))
        return $retValue
    }

    #endregion

    [hashtable] Download([SOURCE]$source, [bool] $runAsJob){
        $headers = @{
            'Authorization' = ('Key {0}' -f $this.token)
            'cache-control' = 'no-cache'
        }

        if ($this.queries[$source].Count -eq 1) { $queryId = $this.queries[$source] }
        else { $queryId = $this.queries[$source][[int]($this.config.queryType)] }

        return ($this.Download($headers, $source, $queryId, $runAsJob))
    }

}