[SOLVED] Returning value from function with Task

Hello, I am trying to get a content from the web using Task. The Sub works great, except I am having difficulty returning the value from the function. Can somebody help me.

<?xml version="1.0" encoding="utf-8" ?>
 
<component name = "postergridCR" extends = "Task" >
 
  <interface>
    <field id = "postergriduri" type = "string" />
    <field id = "postergridcontent" type = "string"/>
  </interface>
 
  <script type = "text/brightscript" >
    <![CDATA[
 
    sub init()
      m.top.functionName = "getContent"
    end sub
 
    sub getContent()
      readInternet = createObject("roUrlTransfer")
      readInternet.setUrl(m.top.postergriduri)
      postergridcontent = readInternet.GetToString()
      m.top.postergridcontent = postergridcontent
   end sub
 
    ]]>
  </script>
 
</component>

I am trying to return the content from the above function

function getwebcontent(webpage as string)

   m.myObj = createObject("RoSGNode", "postergridCR")
   m.myObj.postergriduri=webpage
   m.myObj.functionName="getcontent"
   m.myObj.control = "RUN"
   return m.myObj.postergridcontent  <<======== How do I return the content ??

end function

Edit: Post marked as solved

What type of content is it? XML, JSON ?

I will wait around for another 15 mins or so and see if you respond.

In case I miss you here is one way and forgive me but I like to use a more standardized code if you will.
contentreader.xml

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

<component name = "ContentReader" extends = "Task" >

  <interface>
    <field id = "contenturi" type = "uri" />
    <field id = "content" type = "node" />
  </interface>

  <script type = "text/brightscript" >

    <![CDATA[

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

    sub getcontent()
      content = createObject("roSGNode", "ContentNode")
      contentxml = createObject("roXMLElement")
      readInternet = createObject("roUrlTransfer")
      readInternet.setUrl(m.top.contenturi)
      contentxml.parse(readInternet.GetToString())
      if contentxml.getName()="Content"
        for each item in contentxml.GetNamedElements("item")
          itemcontent = content.createChild("ContentNode")
          itemcontent.setFields(item.getAttributes())
          end for
          end if
      m.top.content = content
    end sub

    ]]>

  </script>

</component>

the.xml

<component name = "SimplePosterGrid" extends = "Scene" initialFocus = "postergrid" >
  <interface>
    <field id="itemContent" type="node" onChange="showpostergrid"/>
  </interface>
  <script type = "text/brightscript" >

    <![CDATA[

    sub init()
      m.postergrid = m.top.findNode("PosterGrid")
      m.readPosterGridTask = createObject("roSGNode", "ContentReader")
      m.readPosterGridTask.contenturi = "http://yourfilehere.xml"
      m.readPosterGridTask.observeField("content", "showpostergrid")
      m.readPosterGridTask.control = "RUN"
    end sub

    sub showpostergrid()
        m.postergrid.content = m.readPosterGridTask.content
        m.postergrid.setFocus(true)
        end sub

    ]]>

  </script>

  <children>
    <PosterGrid
      id = "PosterGrid"
      basePosterSize = "[ 375, 225 ]"
      numColumns = "4"
      numRows = "3"
      itemSpacing = "[ 50, 75 ]" />
  </children>

</component>

it will be just plain text auth code I have to add to the videoURL before it plays, so was trying to write a function that returns auth code.

You probably want to set an observer on the task and break your function up into 2 pieces; Instead of this

    sub getContent()
      readInternet = createObject("roUrlTransfer")
      readInternet.setUrl(m.top.postergriduri)
      postergridcontent = readInternet.GetToString()
      m.top.postergridcontent = postergridcontent
   end sub

Do something like this:

    sub getContent()
      m.readInternet = createObject("roUrlTransferTask")
      m.readInternet.observeField("content","contentSet")
      m.readInternet.Url = m.top.postergriduri
    end sub

    sub contentSet
      m.top.postergridcontent = m.readInternet.content
   end sub

The task needs to have a top level field “content” that it sets once it has received and processed the server response. As soon as the task sets “content” field (m.top.content from within the task), your brs will pick it up and assign to its own postergridcontent field.

I did what you recommended but got the following error. Also on your code, where is readinternet.getString() ?

Member function not found in BrightScript Component or interface. (runtime error &hf4) in pkg:/components/MainScene/task.xml(22)
022: readInternet.observeField(“content”,“contentSet”)

New field id added

  <interface>
    <field id = "postergriduri" type = "string" />
    <field id = "postergridcontent" type = "string"/>
    <field id = "content" type = "string" />
  </interface>

Also on your code, where is readinternet.getString() ?
That belongs in the task, not in the render thread.
As far as that error, you’d have to include more of your code. It works on my Roku :grinning_face_with_smiling_eyes:

Thank you. Sorry I think I need more help here. Here is my code.
getContent() is in task, and I still don’t get it why .getString() is not there. Also not sure where is "roURLtransferTask " object from on your code. Sorry I am a noob :slightly_smiling_face:

Task.xml

<?xml version="1.0" encoding="utf-8" ?>
 
<component name = "postergridCR" extends = "Task" >
 
<interface>
    <field id = "postergriduri" type = "string" />
    <field id = "postergridcontent" type = "string"/>
    <field id = "content" type = "string" />
</interface>
 
  <script type = "text/brightscript" >

    <![CDATA[
 
sub init()
    m.top.functionName = "getData"
end sub
 
 sub getContent()
      m.readInternet = createObject("roUrlTransfer")
      m.readInternet.observeField("content","contentSet")
      m.readInternet.Url = m.top.postergriduri
end sub

sub contentSet()
      m.top.postergridcontent = m.readInternet.content
end sub

   
   
    ]]>

  </script>
</component>

scenegraph.brs

getwebcontent ("http://example.com")

function getwebcontent(webpage as string)

   m.myObj = createObject("RoSGNode", "postergridCR")
   m.myObj.postergriduri=webpage
   m.myObj.functionName="getcontent"
   m.myObj.control = "RUN"
   return m.myObj.postergridcontent

end function

Think I goofed you up by giving you render thread code mixed in with your task code, and now you put the render thread code into the task.
This stuff belongs in your page brs (not task brs) the task brs will have the getString you’re asking about.

function getwebcontent(webpage as string)
   m.myObj = createObject("RoSGNode", "postergridCR")
   m.myObj.postergriduri=webpage
   m.myObj.functionName="getcontent"
   m.myObj.observeField("postergridcontent","gotContent")   '<===================== CREATE OBSERVER BEFORE RUN'
   m.myObj.control = "RUN"
end function

sub gotContent()
    content = m.myObj.postergridcontent   '<==================  callback triggered when task sets m.top.postergridcontent'
end sub

Thank you very much, I am almost there but something is not working. gotContent() works and m.top.content value is set.

sub gotContent()
    m.top.content = m.haamro.HTTPcontent
    print m.top.content <======== This works
end sub

However, when I use getWebcontent function from other function/sub, m.top.content is set invalid. Is it because of the time it is taking to load the content ?

function myotherfunction(url)
getWebContent (url)
print m.top.content  <======= this does not work
end function

Although you say it works, I’m not certain you’re doing it right without seeing the rest of the code. this wasn’t mentioned earlier; Is m.haamro your task and inside that task it’s setting m.top.HTTPcontent ?

m.haamro.HTTPcontent

In the last case where it isn’t working, it’s because you are trying to look at m.top.content immediately instead of waiting for the content to be set in the “gotContent” callback.

Here is my code, did some update on getData

MyTask.xml

<component name = "haamroContent" extends = "Task" >
 
  <interface>
    <field id = "HTTPurl" type = "string" />
    <field id = "HTTPcontent" type = "string" />
  </interface>
 
  <script type = "text/brightscript" >

    <![CDATA[
 
    sub init()
      m.top.functionName = "getData"
    end sub
 
  function getData()
    url = m.top.HTTPurl
    http = createObject("roUrlTransfer")
    http.RetainBodyOnError(true)
    port = createObject("roMessagePort")
    http.setPort(port)
    http.setCertificatesFile("common:/certs/ca-bundle.crt")
    http.InitClientCertificates()
    http.enablehostverification(false)
    http.enablepeerverification(false)
    http.setUrl(url)
    if http.AsyncGetToString() Then
      msg = wait(10000, port)
      if (type(msg) = "roUrlEvent")
        'HTTP response code can be <0 for Roku-defined errors
        if (msg.getresponsecode() > 0 and  msg.getresponsecode() < 400)
          m.top.HTTPcontent = msg.getstring()
        else
          ? "feed load failed: "; msg.getfailurereason();" "; msg.getresponsecode();" "; m.top.HTTPurl
          m.top.HTTPcontent = ""
        end if
        http.asynccancel()
      else if (msg = invalid)
        ? "feed load failed."
        m.top.HTTPcontent =""
        http.asynccancel()
      end if
    end if
end function
   
    ]]>

  </script>

 
</component>

myfunction.brs

function getHTMLContent(webpage as string)

   m.haamro = createObject("RoSGNode", "haamroContent")
   m.haamro.HTTPurl=webpage
   m.haamro.functionName="getdata"
   m.haamro.ObserveField("HTTPcontent","gotContent")
   m.haamro.control = "RUN"
  
end function

sub gotContent()
    m.top.content = m.haamro.HTTPcontent   '<==================  callback triggered // content is set on Scene (myfunction.xml)  where I will be using my function
   print m.top.content <--- this is working and prints the output
end sub

function GrabWOD(webpage as string)    <==== This is the function I am trying to call from other functions

    getHTMLcontent(webpage)   <-- calling my getHTMLcontent function, which triggers gotContent
    html=m.top.content    <-- isn't m.top.content now set ??
    
    print html <-- not working
   return html <-- not working

end function

thank you for all your help.

I think you’re almost there, But you can’t expect m.top.content to be set immediately after you call the task. You need to wait for a callback and process it there.

html=m.top.content ← isn’t m.top.content now set ??

no, result will be in “m.haamro.HTTPcontent” in “gotContent” sub, not here, and not in “m.top.content”. If you don’t want to / can’t re-use gotContent sub, then you can set a new different observer on m.haamro to handle the response differently than gotContent:

m.haamro.ObserveField("HTTPcontent","newDifferentFunction")

...

sub newDifferentFunction()
    m.top.content = m.haamro.HTTPcontent
    ' or '
    html = m.haamro.HTTPcontent
    print html
end sub

Here is the more complete solution with your code:

function getHTMLContent(webpage as string)
   m.haamro = createObject("RoSGNode", "haamroContent")
   m.haamro.HTTPurl=webpage
   m.haamro.functionName="getdata"
   m.haamro.ObserveField("HTTPcontent","gotContent")
   m.haamro.control = "RUN"
end function

sub gotContent()
    m.top.content = m.haamro.HTTPcontent
   print m.top.content '<--- this is working and prints the output'
end sub

function GrabWOD(webpage as string)
   m.haamro.HTTPurl=webpage
   m.haamro.ObserveField("HTTPcontent","newDifferentFunction")
   m.haamro.control = "RUN"
   ' This function can never see the response from the task, it has to use the observeField callback to get it'
end function

sub newDifferentFunction()
    m.top.content = m.haamro.HTTPcontent
    ' or '
    html = m.haamro.HTTPcontent
    print html
end sub

Getting HTTPcontent works great ! Thank you very much for making it possible. But how do I return the HTTPContent value from the function itself so that I can use it elsewhere

function show_web_content (webpage)
   ......
 return webcontent
end function

function getHTMLContent(webpage as string)   <=== HTTPcontent is not set yet so I cannot return its value from this function
   m.haamro = createObject("RoSGNode", "haamroContent")
   m.haamro.HTTPurl=webpage
   m.haamro.functionName="getdata"
   m.haamro.ObserveField("HTTPcontent","gotContent")
   m.haamro.control = "RUN"
end function

function gotContent() <=== this function is called from above, so not sure how do I return the value from this function to the main function that is making HTTP Request.
    m.top.content = m.haamro.HTTPcontent
   print m.top.content
end function

Are you calling this code from Main or from a node?
Assuming this is inside a node, then after you assign m.top.content to the current node’s (lets call it NODE) content field, that will be visible externally via NODE.content
Would need to see more code / what you’re trying to do to give you exact steps.

Maybe this will help, from inside a node the fields are referenced by “m.top.FIELDNAME” and from outside the same node, the fields can be retrieved via NODE.FIELDNAME where NODE is the node object, usually preceded by “m.” so it can be referenced throughout the current scope.

Thank you very much.

Please delete this, replied here instead of another post by error.