Roku Brightscript, Render Thread to Task Thread transfer

655 Views Asked by At

How can we pass Associative Array or SGNode to task thread from render thread without losing the values? In the following example, I am adding the request in a queue in the render thread but when in the go function, which is in the task thread, I try to access the request queue then it gives me an empty queue. How to Solve the issue?

sub init()
  print "UriHandler.brs - [init]"
  m.Port = createObject("roMessagePort")
  m.top.numBadRequests = 0
  m.requestQueue = createObject("roArray", 10, true)
  m.processing = false
  m.top.functionName = "go"
  m.top.control = "RUN"
  m.top.observeField("request", "addToQueue")
end sub

function addToQueue(data)
  m.requestQueue.push(data.getData())
end function 


'Task function
sub go()
  print "UriHandler.brs - [go]"
  ' Holds requests by id
  m.jobsById = {}
  ' UriFetcher event loop
  while true
    msg = wait(0, m.port)
    mt = type(msg)
    print "--------------------------------------------------------------------------"
    print "Received event type '"; mt; "'"
    ' If a request was made
    if mt = "roSGNodeEvent"
      if msg.getField()="request"
        print "got a request"
        if m.requestQueue.count()>0
          ProcessRequest(m.requestQueue.shift())
        end if
      else
        print "Error: unrecognized field '"; msg.getField() ; "'"
      end if
    ' If a response was received
    else if mt="roUrlEvent"
      processResponse(msg)
    ' Handle unexpected cases
    else
     print "Error: unrecognized event type '"; mt ; "'"
    end if
  end while
end sub

' function ProcessNextRequest()
'   request = m.requestQueue.shift()
'   ProcessRequest(request)
'   print "setting processing false"
' end function

function ProcessRequest(request as Object) as Boolean
  print "HTTPHandler - [addRequest]"
  if type(request) = "roAssociativeArray"
    print request
    context = request.context
      if type(context) = "roSGNode"
      parameters = context.parameters
      if type(parameters)="roAssociativeArray"
        headers = parameters.headers
        method = parameters.method
        uri = parameters.uri
        bodyString = ""
        if method = "POST" or method = "PUT"
          body = parameters.body
          bodyString = body.toStr()
        end if
        if type(uri) = "roString"
          urlXfer = createObject("roUrlTransfer")
          urlXfer.SetCertificatesFile("common:/certs/ca-bundle.crt")
          urlXfer.InitClientCertificates()
          urlXfer.setPort(m.Port)
          urlXfer.setUrl(uri)
         ' Add headers to the request
          for each header in headers
            urlXfer.AddHeader(header, headers.lookup(header))
          end for
          print "headers are " headers
          'should transfer more stuff from parameters to urlXfer
          idKey = stri(urlXfer.getIdentity()).trim()
          'Make request based on request method
          'AsyncGetToString returns false if the request couldn't be issued
          if method = "POST" or method = "PUT" or method = "DELETE"
            urlXfer.setRequest(method)
            ok = urlXfer.AsyncPostFromString(bodyString)
          else
            ok = urlXfer.AsyncGetToString()
          end if
          if ok then
            m.jobsById[idKey] = {
              context: request
              xfer: urlXfer
            }
          else 
            print "send not successful"
          end if
          print "Initiating transfer '"; idkey; "' for URI '"; uri; "'"; " succeeded: "; ok
        else
          print "Error: invalid uri: "; uri
          m.top.numBadRequests++
        end if
      else
        print "Error: parameters is the wrong type: " + type(parameters)
        return false
      end if
      else
      print "Error: context is the wrong type: " + type(context)
          return false
      end if
  else
    print "Error: request is the wrong type: " + type(request)
    return false
  end if
  print "--------------------------------------------------------------------------"
  return true
end function

'Received a response
sub processResponse(msg as Object)
  idKey = stri(msg.GetSourceIdentity()).trim()
  job = m.jobsById[idKey]
  if job <> invalid
    context = job.context
    parameters = context.context.parameters
    uri = parameters.uri
    print "Response for transfer '"; idkey; "' for URI '"; uri; "'"
    result = {
      code:    msg.GetResponseCode(),
      headers: msg.GetResponseHeaders(),
      content: msg.GetString(),
    }
    print result
    print "response headers"
    print result.headers
    job.context.context.response = result
    m.jobsById.delete(idKey)
  else
    print "Error: event for unknown job "; idkey
  end if
  ' ProcessNextRequest()
  print "--------------------------------------------------------------------------"
end sub`
1

There are 1 best solutions below

1
juliomalves On

You can create a custom task component which extends the Task node, with the additional interface fields you need.

<?xml version="1.0" encoding="UTF-8"?>

<component name="CustomTask" extends="Task">
    <interface>
        <field id="aaField" type="assocarray"/>
        <field id="nodeField" type="node" />
    </interface>
</component>
sub init()
    m.top.functionName = "getContent"
end sub

sub getContent()
    ? m.top.aaField ' Prints the associative array passed
    ? m.top.nodeField ' Prints the SG node passed
end sub

You can then create an instance of the newly created task node and pass the data you want to its fields.

contentNode = createObject("roSGNode", "ContentNode")
m.someTask = createObject("roSGNode", "CustomTask")
m.someTask.aaField = { hello: "world" }
m.someTask.nodeField = contentNode
m.someTask.control = "run"