Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
dan_shneider
Visitor

More server requests on task element

Hey,
I do some server requests in a task. eventually I get the final response with the videos I need to display. that's fine. I send a callback to the VideoGridScene.
Now, I need to request something again from the server. let's say, when the video pauses.
My task has a property with the Video node, and I get the 'pause' event.
But, on that point, I cannot access the registry to get some values nor can I request 
Errors:
'Dot' Operator attempted with invalid BrightScript Component or interface reference. (runtime error &hec)
and
BRIGHTSCRIPT: ERROR: roUrlTransfer: class PLUGIN|MARKUP on thread RENDER: pkg:/components/Task.xml(378)
BRIGHTSCRIPT: ERROR: roMessagePort: Trying to construct a message port on a non-plugin thread: pkg:/components/Task.xml(379)

What am I doing wrong?
0 Kudos
14 REPLIES 14
EnTerr
Roku Guru

Re: More server requests on task element

Hard to read your tea leafs but seems as if you are trying to use some components that are "haram" 🙂 in RSG (render thread, specifically). Seeing that "Task.xml" is mentioned, you are probably doing it before spawning a task thread.

See also https://sdkdocs.roku.com/display/sdkdoc ... pt+Support
0 Kudos
dan_shneider
Visitor

Re: More server requests on task element

"EnTerr" wrote:
Hard to read your tea leafs but seems as if you are trying to use some components that are "haram" 🙂 in RSG (render thread, specifically). Seeing that "Task.xml" is mentioned, you are probably doing it before spawning a task thread.

See also https://sdkdocs.roku.com/display/sdkdoc ... pt+Support

Not sure I understood (I did understand the Haram part 🙂
Anyhow, I guess what I am saying is that I need a task node that can act as a continuous server.
Task.xml is just a sample. that's not the real name of the node of course. my function within the task sends the result to the observer gets it and all is good.[/font][/color]
My question was actually about next step: I need to send more requests according to the player event (star, stop, pause and so on...).[/font][/color]
0 Kudos
belltown
Roku Guru

Re: More server requests on task element

Do you have any code showing how you're trying to do this?
0 Kudos
dan_shneider
Visitor

Re: More server requests on task element

"belltown" wrote:
Do you have any code showing how you're trying to do this?

Sure. this is how I init the Task:
m.babatorTask = createObject("RoSGNode", "BabatorTask")
   m.babatorTask.observeField("babator_recommendations", "OnRecommendationsFetched")
   m.babatorTask.babator_api_key = "API_KEY"
   m.babatorTask.video_player = m.VideoGrid.liveVideo.Video
   m.babatorTask.control = "RUN"


And this is the task code (part of it):
<?xml version = "1.0" encoding = "utf-8" ?> 

<!--********** B A B A T O R **********-->

<component name = "BabatorTask" extends = "Task" >
 
  <interface>
  <field id = "babator_api_url" type = "string" />
  <field id = "babator_api_key" type = "string" />
    <field id = "babator_recommendations" type = "string" />
    <field id = "video_player" type="node"/>
  </interface> 

  <script type = "text/brightscript" >

    <![CDATA[

    sub init()
      m.top.functionName = "startBabator"
    end sub

function startBabator()
userRequest = CreateObject("roUrlTransfer")
   port = CreateObject("roMessagePort")
   userRequest.SetMessagePort(port)
   userRequest.SetUrl(url)
   userRequest.AddHeader("x-api-key",m.top.babator_api_key)
   userRequest.AddHeader("x-is-native","true") 
 
   if (userRequest.AsyncGetToString())
   
       while (true)
           msg = wait(0, port)
           if (type(msg) = "roUrlEvent")
               code = msg.GetResponseCode()
               print "user response code: " + code.ToStr()
               
               if (code = 200) 'response OK
                   
                   m.top.babator_recommendations = msg.GetString()
               else
                   print "ERROR in user request: " + userRequest.GetFailureReason()    
               endif
           else if (event = invalid) 'response is invalid
               print "invalid !!!"
               userRequest.AsyncCancel()
           endif
           exit while
       end while
   endif
   return invalid
    
    end function
    
   

0 Kudos
belltown
Roku Guru

Re: More server requests on task element

To use a Task as a continuous server, use the port form of ObserveField(), specifying an roMessagePort used to wait for changes on each item that you wish to observe. You can use the same port you use for your roUrlTransfer object. In the Task thread code, define a message loop that calls Wait() on the port. If an observed field changes, an roSGNodeEvent message is received. Call GetField() and GetData() on this message to get the name of the field that changed and its value. You only need to set the Task's control field to "RUN" one time, to start it up. Thereafter, it will handle observed field changes each time they occur in its main Wait loop.
0 Kudos
EnTerr
Roku Guru

Re: More server requests on task element

How do we explain the bizarre "colonics"?
BRIGHTSCRIPT: ERROR: roUrlTransfer: class PLUGIN|MARKUP on thread RENDER: pkg:/components/Task.xml(378)
BRIGHTSCRIPT: ERROR: roMessagePort: Trying to construct a message port on a non-plugin thread: pkg:/components/Task.xml(379)

Seems awfully peculiar - could this be caused by assigning a Video node to a Task field?
Not something i would have tried but it shouldn't bind the task spawned to the render thread, right?

PS. Why is the diagnostic text so weird? Is it trying to say that PLUGIN and MARKUP are mutually exclusive flags? I am guessing #378 is `userRequest = CreateObject("roUrlTransfer")`? Why is this the RENDER thread if it's in the Task runner function?
0 Kudos
dan_shneider
Visitor

Re: More server requests on task element

"EnTerr" wrote:
How do we explain the bizarre "colonics"?
BRIGHTSCRIPT: ERROR: roUrlTransfer: class PLUGIN|MARKUP on thread RENDER: pkg:/components/Task.xml(378)
BRIGHTSCRIPT: ERROR: roMessagePort: Trying to construct a message port on a non-plugin thread: pkg:/components/Task.xml(379)

Seems awfully peculiar - could this be caused by assigning a Video node to a Task field?
Not something i would have tried but it shouldn't bind the task spawned to the render thread, right?

PS. Why is the diagnostic text so weird? Is it trying to say that PLUGIN and MARKUP are mutually exclusive flags? I am guessing #378 is `userRequest = CreateObject("roUrlTransfer")`? Why is this the RENDER thread if it's in the Task runner function?

Yes, #378 is  CreateObject("roUrlTransfer")
0 Kudos
dan_shneider
Visitor

Re: More server requests on task element

"belltown" wrote:
To use a Task as a continuous server, use the port form of ObserveField(), specifying an roMessagePort used to wait for changes on each item that you wish to observe. You can use the same port you use for your roUrlTransfer object. In the Task thread code, define a message loop that calls Wait() on the port. If an observed field changes, an roSGNodeEvent message is received. Call GetField() and GetData() on this message to get the name of the field that changed and its value. You only need to set the Task's control field to "RUN" one time, to start it up. Thereafter, it will handle observed field changes each time they occur in its main Wait loop.

Not so sure I understood what should I do in the Scene level & in the task level. any code snippet?
0 Kudos
belltown
Roku Guru

Re: More server requests on task element

Here's a very simplified example that illustrates the concept. Note that I don't include the Video node as a field in the Task node as you've done. That just seems weird to me. It makes more sense to keep the Video node contained within the Render thread and communicate any state changes that the Task needs to know about via an interface field on the Task node that only contains the information the Task needs to know (i.e. the video state in this case). The Task just prints out any changes to the Video state by observing its interface field. You can add your own code to use your roUrlTransfer object to send that data where it needs to go.

Test.xml:

<?xml version="1.0" encoding="UTF-8"?>
<component name="Test" extends="Scene">
 <script type="text/brightscript" uri="pkg:/components/Test.brs" />
 <children>
   <Video id="videoNode">
     <ContentNode role="content"
       url="https://archive.org/download/Plan9FromOuterSpace1958/Plan-9-from-Outer-Space.mp4"
       title="Test Video" />
   </Video>
   <TaskServer id="taskServerNode" />
 </children>
</component>


Test.brs:

sub init()
   m.taskServerNode = m.top.findNode("taskServerNode")
   m.taskServerNode.ObserveField("stateOutput", "onTaskStateOutput")
   m.videoNode = m.top.findNode("videoNode")
   m.videoNode.SetFocus(true)
   m.videoNode.ObserveField("state", "onVideoState")
   m.videoNode.control = "play"
end sub

sub onVideoState()
   m.taskServerNode.stateInput = m.videoNode.state
end sub

sub onTaskStateOutput()
   print "Task state: "; m.taskServerNode.stateOutput
end sub

function onKeyEvent(key as string, press as boolean) as boolean
   handled = false
   if press
       if key = "play"
           if m.videoNode.state = "playing"
               m.videoNode.control = "pause"
           else if m.videoNode.state = "paused"
               m.videoNode.control = "resume"
           else if m.videoNode.state = "stopped"
               m.videoNode.control = "play"
           end if
           handled = true
       end if
   end if
   return handled
end function


TaskServer.xml:

<?xml version="1.0" encoding="UTF-8"?>
<component name="TaskServer" extends="Task">
 <script type="text/brightscript" uri="pkg:/components/TaskServer.brs" />
 <interface>
   <field id="stateInput" type="string" alwaysNotify="true" />
   <field id="stateOutput" type="string" alwaysNotify="true" />
 </interface>
</component>


TaskServer.brs:

sub init()
   m.top.functionName = "taskRun"
   m.top.control = "RUN"
end sub

function taskRun() as void
   port = CreateObject("roMessagePort")
   m.top.ObserveField("stateInput", port)
   while true
       msg = Wait(0, port)
       if Type(msg) = "roSGNodeEvent"
           field = msg.GetField()
           state = msg.GetData()
           if field = "stateInput"
               print "stateInput: "; state
               m.top.stateOutput = state
           end if
       end if
   end while
end function
0 Kudos