lib/Brokers.ps1

function New-TMBroker {
    <#
    .SYNOPSIS
    Creates a new TMBroker class object

    .DESCRIPTION
    This function

    .PARAMETER TMSession
    The name of the TransitionManager sesssion to use with the new Broker

    .PARAMETER TMEvent
    A TMEvent class object representing the TransitionManager Event in which the Broker will be operating

    .PARAMETER TaskId
    The Id of the Broker task

    .PARAMETER TimeoutMinutes
    The amount of time in minutes that the Broker can run before automatically terminating its execution

    .PARAMETER PauseSeconds
    The amount of time in seconds that the Broker should pause in between processing subject tasks

    .PARAMETER Parallel
    Switch: This switch will have the broker run multiple parallel runspaces for subjects it encounters.

    .PARAMETER Throttle
    Required when Parallel is used. This Parameter controls how many concurrent threads the Broker will be allowed to use


    .EXAMPLE
    # Login to TransitionManager
    $SessionSplat = @{
        SessionName = 'Broker'
        Server = ([URI]$ActionRequest.options.callback.siteUrl).host
        Credential = (Get-StoredCredential TM)
        Project = $ActionRequest.task.project.name
        Passthru = $true
        Parallel = $true
        Throttle = 8
    }
    $Session = New-TMSession @SessionSplat

    # Get the Event
    $TMEvent = Get-TMEvent -TMSession 'Broker' -Name $ActionRequest.task.event.name -ProjectId $ActionRequest.options.projectId

    # Create a new Broker
    $Broker = New-TMBroker -TMSession 'Broker' -TMEvent $TMEvent -TaskId $ActionRequest.task.id

    .OUTPUTS
    A TMBroker class object
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false, Position = 0)]
        [String]$TMSession = 'Default',

        [Parameter(Mandatory = $true, Position = 1)]
        [TMEvent]$TMEvent,

        [Parameter(Mandatory = $false, Position = 2)]
        [Int]$TaskId,

        [Parameter(Mandatory = $false)]
        # [ArgumentCompleter({ [TMBrokerSubjectScope]::ValidTypes })]
        # [ValidateScript( { $_ -in [TMBrokerSubjectScope]::ValidTypes } )]
        [Alias('Type')]
        [String]$SubjectScopeType = 'Inline',

        [Parameter(Mandatory = $false)]
        # [ArgumentCompleter({ [TMBrokerSubjectScope]::ValidTaskProperties })]
        # [ValidateScript( { $_ -in [TMBrokerSubjectScope]::ValidTaskProperties } )]
        [Alias('TaskProperty')]
        [String]$SubjectScopeTaskProperty = 'Title',

        [Parameter(Mandatory = $false)]
        [Alias('MatchingCriteria')]
        [String[]]$SubjectScopeMatchingCriteria,

        [Parameter(Mandatory = $false)]
        [Int]$TimeoutMinutes = 120,

        [Parameter(Mandatory = $false)]
        [Int]$PauseSeconds = 15,

        [Parameter()]
        [Switch]$Parallel,

        [Parameter(Mandatory = $false)]
        [Int]$Throttle = 8
    )


    # Get the session configuration
    Write-Verbose 'Checking for cached TMSession'
    $TMSessionConfig = $global:TMSessions[$TMSession]
    Write-Debug 'TMSessionConfig:'
    Write-Debug ($TMSessionConfig | ConvertTo-Json -Depth 5)
    if (-not $TMSessionConfig) {
        throw "TMSession '$TMSession' not found. Use New-TMSession command before using features."
    }

    # Initialize a new broker
    $Broker = [TMBroker]::new(
        $SubjectScopeType,
        $SubjectScopeTaskProperty,
        $SubjectScopeMatchingCriteria,
        $TimeoutMinutes,
        $PauseSeconds,
        $Parallel.IsPresent,
        $Throttle
    )

    # Load the TM Session into the broker
    $Broker.TMSession = $TMSessionConfig

    ## Add the TM Event supplied by the invocation
    if ($TMEvent) {
        $Broker.TMSession.UserContext.event = @{
            Id   = $TMEvent.id
            Name = $TMEvent.Name
        }
    }
    ## User Context event can be null. Add the property if it is
    if ([string]::IsNullOrWhiteSpace($Broker.TMSession.UserContext.event.id)) {
        $Broker.TMSession.UserContext.event = @{
            Id   = $Broker.TMSession.UserContext.event.id
            Name = $Broker.TMSession.UserContext.event.Name
        }
    }

    # Load the Event's data into the broker
    $Broker.GetEventData()

    # Fill the task data if a Task Id was provided
    if ($TaskId) {
        $Broker.GetTaskData($TaskId)
    }

    # Return the new broker
    $Broker
}


function Get-TMBrokerTaskData {
    <#
    .SYNOPSIS
    Gets information about the Tasks that will be managed by the Broker

    .DESCRIPTION
    This function will load the following information into the provided Broker object:
        - The Broker's Task information
        - The Init Task (if present)
        - Information on each of the subject tasks that are to be managed by the Broker

    .PARAMETER Broker
    A TMBroker object that has been loaded with TMSession and TMEvent data

    .PARAMETER TaskId
    The Id of the Broker task

    .EXAMPLE
    Get-TMBrokerTaskData -Broker $Broker -TaskId $ActionRequest.task.id

    .OUTPUTS
    None
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
        [TMBroker]$Broker,

        [Parameter(Mandatory = $true, Position = 1)]
        [Int]$TaskId
    )

    if (-not $Broker.EventData) {
        throw "The Broker has not been loaded with Event data. Use either the New-TMBroker command or the Broker's GetEventData() method"
    }

    $Broker.GetTaskData($TaskId)
}


function Get-TMBrokerCache {
    <#
    .SYNOPSIS
    Loads the Broker with a data cache by executing the Init Task

    .DESCRIPTION
    This function will populate the Broker's data cache by executing the Init Task (if present)

    .PARAMETER Broker
    The TMBroker object that will be updated with cache data

    .EXAMPLE
    # Load the cache if there's an init task
    if ($Broker.Init) {
        Get-TMBrokerCache -Broker $Broker
    }

    .OUTPUTS
    None
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
        [TMBroker]$Broker
    )


    begin {

    }

    process {
        if (-not $Broker.TMSession) {
            throw "The Broker has not been loaded with a TM Session. Use either the New-TMBroker command or load the Broker's TMSession property"
        }

        if (-not $Broker.EventData) {
            throw "The Broker has not been loaded with Event data. Use either the New-TMBroker command or the Broker's GetEventData() method"
        }

        if (-not $Broker.Task -or -not $Broker.Subjects) {
            throw "The Broker has not been loaded with Task data. Use either the Get-TMBrokerTaskData command or the Broker's GetTaskData() method"
        }

        if (-not $Broker.Init) {
            throw "The Broker has not been loaded with an Init Task. Use either the Get-TMBrokerTaskData command or the Broker's GetInitTask() method"
        }

        ## Run the Init Task
        $Broker.PopulateCache()
    }
}
function Start-TMBroker {
    <#
    .SYNOPSIS
    Runs the Broker to execute the subject tasks in its scope

    .DESCRIPTION
    This function will execute the Broker. This will, in turn, execute all of the Subject Tasks in its scope.

    .PARAMETER Broker
    The TMBroker object that will be updated with cache data

    .EXAMPLE
    # Start the Broker
    Start-TMBroker -Broker $Broker

    .OUTPUTS
    None
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
        [TMBroker]$Broker
    )


    begin {

    }

    process {
        if (-not $Broker.TMSession) {
            throw "The Broker has not been loaded with a TM Session. Use either the New-TMBroker command or load the Broker's TMSession property"
        }

        if (-not $Broker.EventData) {
            throw "The Broker has not been loaded with Event data. Use either the New-TMBroker command or the Broker's GetEventData() method"
        }

        if (-not $Broker.Task) {
            throw 'The Broker does not have a task assigned.'
        }
        if (-not $Broker.Subjects -and -not $Broker.ServiceSubjects) {
            throw "The Broker has not been loaded with Task data. Use either the Get-TMBrokerTaskData command or the Broker's GetTaskData() method"
        }

        ## Run the Broker
        $Broker.Run()
    }
}