Registration channel help

I am having trouble figuring out the registration SDK file. When I first ran the app it downloaded a token and said success but now I can’t test it any further cause it has the token and won’t try to get a new one. I have tried setting token = 0 or incomplete as various other people have suggested. I also tried calling the deleteRegistrationToken function that exist but that doesn’t work either. This is my 5th Roku app and it is driving me nuts. If I can’t figure this out, it looks like my days as a Roku developer might be finished.

It looks like it stores the code in the registry, so all you have to do is delete the registry and you’ll be back to the beginning again.

Here’s some code I wrote for a utility channel you can side-load that will allow you to dump the contents of the registry, wipe the whole registry, or wipe individual registry sections. All you really need is the deleteReg function, but if you can’t figure it out it might be easier to just load the whole channel and select the appropriate menu item:

Sub Main ()
    displayMainUI ()
End Sub

'
' UI component for the top-level menu
'
Function displayMainUI () As Void
    contentList = [
        {ShortDescriptionLine1: "Dump the whole registry"},
        {ShortDescriptionLine1: "Wipe the whole registry"},
        {ShortDescriptionLine1: "Delete an individual section"},
    ]
    port = CreateObject ("roMessagePort")
    ui = CreateObject ("roPosterScreen")
    ui.SetMessagePort (port)
    ui.SetListStyle ("flat-category")
    ui.SetContentList (contentList)
    ui.Show ()
    While True
        msg = Wait (0, port)
        If Type (msg) = "roPosterScreenEvent"
            If msg.IsScreenClosed ()
                Exit While
            Else If msg.IsListItemSelected ()
                index = msg.GetIndex ()
                If index = 0
                    dumpRegistryUI ()
                Else If index = 1
                    wipeRegistryUI ()
                Else If index = 2
                    deleteSectionUI ()
                EndIf
            EndIf   
        EndIf
    End While
End Function

'
' UI component for dumping the entire registry
'
Function dumpRegistryUI () As Void
    regText = getRegText ()
    If regText = ""
        displayMessage ("Registry is empty")
    Else
        port = CreateObject ("roMessagePort")
        ui = CreateObject ("roTextScreen")
        ui.SetMessagePort (port)
        ui.SetText (fixup (regText))    ' Use fw3.1 bug workaround
        ui.AddButton (0, "Quit")
        ui.Show ()
        While True
            msg = Wait (0, port)
            If Type (msg) = "roTextScreenEvent"
                If msg.IsScreenClosed ()
                    Exit While
                Else If msg.IsButtonPressed ()
                    ui.Close ()
                EndIf   
            EndIf
        End While
    EndIf
End Function

'
'  UI component for deleting the entire registry
'
Function wipeRegistryUI () As Void
    If confirmUI ("Wipe Registry", "Select 'Wipe Registry' to delete the entire registry")
        deleteReg ("")  ' Delete all sections
    EndIf
End Function

'
' UI component for deleting an individual registry section
'
Function deleteSectionUI () As Void
    regSectionList = getRegSectionList ()
    If regSectionList.Count () = 0
        displayMessage ("Registry is empty")
    Else
        contentList = []
        For Each section In regSectionList
            If section.keyCount = 0
                keyCountStr = "No keys in section"
            Else If section.keyCount = 1
                keyCountStr = "1 key in section"
            Else
                keyCountStr = section.keyCount.ToStr () + " keys in section"
            EndIf
            contentList.Push ({Title: section.name, ShortDescriptionLine1: keyCountStr})
        End For
        port = CreateObject ("roMessagePort")
        ui = CreateObject ("roListScreen")
        ui.SetMessagePort (port)
        ui.SetupBehaviorAtTopRow ("exit")   ' Give fw3.1 users a way back
        ui.SetHeader ("Press 'OK' to delete section")
        ui.SetContent (contentList)
        ui.Show ()
        While True
            msg = Wait (0, port)
            If Type (msg) = "roListScreenEvent"
                If msg.IsScreenClosed ()
                    Exit While
                Else If msg.IsListItemSelected ()
                    section = contentList [msg.GetIndex ()].Title
                    If confirmUI ("Delete Section", "Select 'Delete Section' to delete the " + section + " section")
                        deleteReg (section)
                        ui.Close ()
                    EndIf
                EndIf   
            EndIf
        End While
    EndIf
End Function

'
' Return a list of all registry sections and the number of keys in each section
'
Function getRegSectionList () As Object
    regSectionList = []
    r = CreateObject ("roRegistry")
    For Each section In r.GetSectionList ()
        rs = CreateObject ("roRegistrySection", section)
        regSectionList.Push ({name: section, keyCount: rs.GetKeyList ().Count ()})
    End For
    Return regSectionList
End Function

'
' Get the contents of a registry section as a text string
'
Function getRegTextSection (sectionName = "" As String) As String
    regText = "Registry Section: " + sectionName + LF ()
    rs = CreateObject ("roRegistrySection", sectionName)
    For Each key In rs.GetKeyList ()
        regText = regText + "    " + key + ": " + rs.Read (key) + LF ()
    End For
    Return regText
End Function

'
' Get the contents of a registry or registry section as a text string
'
Function getRegText (sectionName = "" As String) As String
    regText = ""
    If sectionName = ""
        r = CreateObject ("roRegistry")
        For Each section In r.GetSectionList ()
            regText = regText + getRegTextSection (section) + LF ()
        End For
    Else
        regText = regText + getRegTextSection (sectionName)
    Endif
    Return regText
End Function

'
' Roku 3.1 firmware roTextScreen bug workaround (buttons don't work unless enough text to scroll)
'
Function fixup (regText As String) As String
    fixedText = regText
    lfCount = 0
    ' Count the number of line-ending characters
    For i = 1 To Len (regText)
        If Mid (regText, i, 1) = LF () Then lfCount = lfCount + 1
    End For
    ' Ensure there are at least 18 lines to guarantee a scroll bar appears
    If lfCount < 18 Then fixedText = fixedText + String (18 - lfCount, LF ())
    Return fixedText
End Function

'
' Delete the entire registry or an individual registry section
'
Function deleteReg (section = "" As String) As Void
    r = CreateObject ("roRegistry")
    If section = ""
        For Each regSection In r.GetSectionList ()
            r.Delete (regSection)
        End For
    Else
        r.Delete (section)
    Endif
    r.Flush ()
End Function

'
' Display a confirmation before an irreversible action
'
Function confirmUI (buttonText As String, buttonDesc As String) As Boolean
    confirm = False
    port = CreateObject ("roMessagePort")
    ui = CreateObject ("roMessageDialog")
    ui.SetMessagePort (port)
    ui.SetTitle ("DANGER -- This Action Cannot Be Undone")
    ui.SetText ("Select 'Cancel' to go back")
    ui.SetText (buttonDesc)
    ui.AddButton (0, "Cancel")
    ui.AddButton (1, buttonText)
    ui.Show ()
    While True
        msg = Wait (0, port)
        If Type (msg) = "roMessageDialogEvent"
            If msg.IsScreenClosed ()
                Exit While
            Else If msg.IsButtonPressed ()
                If msg.GetIndex () = 1
                    confirm = True
                EndIf
                ui.Close ()
            EndIf   
        EndIf
    End While
    Return confirm
End Function

'
' Display an informational message
'
Function displayMessage (text As String) As Void
    port = CreateObject ("roMessagePort")
    ui = CreateObject ("roMessageDialog")
    ui.SetMessagePort (port)
    ui.SetTitle (text)
    ui.AddButton (0, "OK")
    ui.Show ()
    While True
        msg = Wait (0, port)
        If Type (msg) = "roMessageDialogEvent"
            If msg.IsScreenClosed ()
                Exit While
            Else If msg.IsButtonPressed ()
                ui.Close ()
            EndIf
        EndIf
    End While
End Function

'
' Line-ending character to use in a text string
'
Function LF () As String : Return Chr (10) : End Function

That program doesn’t seem to be clearing the registry. I deleted the server contents and it is still displaying the old code and incomplete status messages.

Do you have your own server that handles registration or are your just running the SDK example “as is”?

“belltown” wrote:
Do you have your own server that handles registration or are your just running the SDK example “as is”?

I run my own server and have uploaded the SDK example files. Currently it shows the code from getCode and checks getResult but it only does it once. If I change getCode or getResult the app never sees them again.

“tvjay” wrote:
That program doesn’t seem to be clearing the registry. I deleted the server contents and it is still displaying the old code and incomplete status messages.
What program are you talking about – the code I posted to clear the registry? Are you running it as a side-loaded channel in developer mode, and running your SDK example code the same way? What makes you think it doesn’t seem to be clearing the registry? If you select “Dump the whole registry” it should list the registry contents. If you’ve run the registration SDK example there should be a Registry Section named “Authentication” with a key named “RegToken”. If you select “Wipe the whole registry” or “Delete an individual section”, you should be able to delete that section, which you can confirm by selecting “Dump the whole registry” again.

“belltown” wrote:
What program are you talking about – the code I posted to clear the registry? Are you running it as a side-loaded channel in developer mode, and running your SDK example code the same way? What makes you think it doesn’t seem to be clearing the registry? If you select “Dump the whole registry” it should list the registry contents. If you’ve run the registration SDK example there should be a Registry Section named “Authentication” with a key named “RegToken”. If you select “Wipe the whole registry” or “Delete an individual section”, you should be able to delete that section, which you can confirm by selecting “Dump the whole registry” again.

I am running it side-loaded as well as my app. I think it is not clearing because when I run my app it shows an old code and not the current code on my server. Also, I never see the registry contents you mention that I should see. It always returns “registry is empty.”

“tvjay” wrote:

“belltown” wrote:
What program are you talking about – the code I posted to clear the registry? Are you running it as a side-loaded channel in developer mode, and running your SDK example code the same way? What makes you think it doesn’t seem to be clearing the registry? If you select “Dump the whole registry” it should list the registry contents. If you’ve run the registration SDK example there should be a Registry Section named “Authentication” with a key named “RegToken”. If you select “Wipe the whole registry” or “Delete an individual section”, you should be able to delete that section, which you can confirm by selecting “Dump the whole registry” again.

I am running it side-loaded as well as my app. I think it is not clearing because when I run my app it shows an old code and not the current code on my server. Also, I never see the registry contents you mention that I should see. It always returns “registry is empty.”
Most likely, the “Registry is empty” message means that your registry really is empty, and that your channel hasn’t written anything to it. It’s going to be hard to diagnose what’s going on here since you haven’t posted any code from either your Roku channel or your server script. Your best bet is to step through your Roku channel code line by line using the debugger until you find where this “old code” is coming from, why you’re not getting the new code from your server, and why the new code is not being written to the registry if that’s what it should be doing. If you spend some time studying the SDK “example” code, figuring out how it works, then you should be able to write your own code to do whatever you want.

“belltown” wrote:
Most likely, the “Registry is empty” message means that your registry really is empty, and that your channel hasn’t written anything to it. It’s going to be hard to diagnose what’s going on here since you haven’t posted any code from either your Roku channel or your server script. Your best bet is to step through your Roku channel code line by line using the debugger until you find where this “old code” is coming from, why you’re not getting the new code from your server, and why the new code is not being written to the registry if that’s what it should be doing. If you spend some time studying the SDK “example” code, figuring out how it works, then you should be able to write your own code to do whatever you want.

That is kind of what I thought. I am running the standard SDK example code only slightly modified. I uploaded the example webpage code and just want to get it working as is before developing a more complicated backend. I have attached my code and my debugger output. I see the problem with the missing < but since I can’t clear that entry I am stuck.

Current Regscreen:

' *********************************************************
' **  Roku Registration Demonstration App
' **  Support routines
' **  May 2009
' **  Copyright (c) 2009 Roku Inc. All Rights Reserved.
' *********************************************************

'******************************************************
'Perform the registration flow
'
'Returns:
'    0 - We're registered. Proceed
'    1 - We're not registered. The user cancelled the process.
'    2 - We're not registered. There was an error
'******************************************************

Function doRegistration() As Integer

   'xml responses are static, but there are a few flavours available for testing
   'Generic case: getRegResult (always returns success)
   'Failure case: getRegResult_failure (always returns failure)
   'Success case: getRegResult_success (always returns success)

    m.UrlBase         = "http://www.303north.com/Roku"
    m.UrlGetRegCode   = m.UrlBase + "/getRegCode"
    m.UrlGetRegResult = m.UrlBase + "/getRegResult"
    m.UrlWebSite      = "http://www.303north.com/Roku"

    m.RegToken = loadRegistrationToken()
    if isLinked() then
        print "device already linked, skipping registration process" 
        'return 0
    endif

    regscreen = displayRegistrationScreen()

    'main loop get a new registration code, display it and check to see if its been linked
    while true
        
        duration = 0

        sn = GetDeviceESN() 
        regCode = getRegistrationCode(sn)

        'if we've failed to get the registration code, bail out, otherwise we'll
        'get rid of the retrieving... text and replace it with the real code       
        if regCode = "" then return 2
        regscreen.SetRegistrationCode(regCode)
        print "Enter registration code " + regCode + " at " + m.UrlWebSite + " for " + sn

        'make an http request to see if the device has been registered on the backend
        while true
            'sleep(5000) ' to simulate going to computer and typing in regcode
                
            status = checkRegistrationStatus(sn, regCode)
            if status < 3 return status

            getNewCode = false
            retryInterval = getRetryInterval()
            retryDuration = getRetryDuration()
            print "retry duration "; itostr(duration); " at ";  itostr(retryInterval);
            print " sec intervals for "; itostr(retryDuration); " secs max"
          
            'wait for the retry interval to expire or the user to press a button
            'indicating they either want to quit or fetch a new registration code
            while true
                print "Wait for " + itostr(retryInterval)
                msg = wait(retryInterval * 1000, regscreen.GetMessagePort())
                duration = duration + retryInterval
                if msg = invalid exit while

                if type(msg) = "roCodeRegistrationScreenEvent"
                    if msg.isScreenClosed()
                        print "Screen closed"
                        return 1
                    elseif msg.isButtonPressed()
                        print "Button pressed: "; msg.GetIndex(); " " msg.GetData()
                        if msg.GetIndex() = 0
                            regscreen.SetRegistrationCode("retrieving code...")
                            getNewCode = true
                            exit while
                        endif
                        if msg.GetIndex() = 1 return 1
                    endif
                endif
            end while
            
            if duration > retryDuration exit while
            if getNewCode exit while

            print "poll prelink again..."
        end while
    end while

End Function

'********************************************************************
'** display the registration screen in its initial state with the
'** text "retrieving..." shown.  We'll get the code and replace it
'** in the next step after we have something on-screen for the user 
'********************************************************************
Function displayRegistrationScreen() As Object

    regsite   = "go to " + m.UrlWebsite
    regscreen = CreateObject("roCodeRegistrationScreen")
    regscreen.SetMessagePort(CreateObject("roMessagePort"))

    regscreen.SetTitle("")
    regscreen.AddParagraph("Please link your Roku player to your account by visiting")
    regscreen.AddFocalText(" ", "spacing-dense")
    regscreen.AddFocalText("From your computer,", "spacing-dense")
    regscreen.AddFocalText(regsite, "spacing-dense")
    regscreen.AddFocalText("and enter this code to activate:", "spacing-dense")
    regscreen.SetRegistrationCode("retrieving code...")
    regscreen.AddParagraph("This screen will automatically update as soon as your activation completes")
    regscreen.AddButton(0, "Get a new code")
    regscreen.AddButton(1, "Back")
    regscreen.Show()

    return regscreen

End Function

'********************************************************************
'** Fetch the prelink code from the registration service. return
'** valid registration code on success or an empty string on failure
'********************************************************************
Function getRegistrationCode(sn As String) As String

    if sn = "" then return ""

    http = NewHttp(m.UrlGetRegCode)
    http.AddParam("partner", "roku")
    http.AddParam("deviceID", sn)
    http.AddParam("deviceTypeName", "roku")

    rsp = http.Http.GetToString()
    xml = CreateObject("roXMLElement")
    print "GOT: " + rsp
    print "Reason: " + http.Http.GetFailureReason()

    if not xml.Parse(rsp) then
        print "Can't parse getRegistrationCode response"
        ShowConnectionFailed()
        return ""
    endif

    if xml.GetName() <> "result"
        Dbg("Bad register response: ",  xml.GetName())
        ShowConnectionFailed()
        return ""
    endif

    if islist(xml.GetBody()) = false then
        Dbg("No registration information available")
        ShowConnectionFailed()
        return ""
    endif

    'default values for retry logic
    retryInterval = 30  'seconds
    retryDuration = 900 'seconds (aka 15 minutes)
    regCode       = ""

    'handle validation of response fields 
    for each e in xml.GetBody()
        if e.GetName() = "regCode" then
            regCode = e.GetBody()  'enter this code at website
        elseif e.GetName() = "retryInterval" then
            retryInterval = strtoi(e.GetBody())
        elseif e.GetName() = "retryDuration" then
            retryDuration = strtoi(e.GetBody())
        endif
    next

    if regCode = "" then
        Dbg("Parse yields empty registration code")
        ShowConnectionFailed()
    endif

    m.retryDuration = retryDuration
    m.retryInterval = retryInterval
    m.regCode = regCode

    return regCode

End Function

'******************************************************************
'** Check the status of the registration to see if we've linked
'** Returns:
'**     0 - We're registered. Proceed.
'**     1 - Reserved. Used by calling function.
'**     2 - We're not registered. There was an error, abort.
'**     3 - We're not registered. Keep trying.
'******************************************************************
Function checkRegistrationStatus(sn As String, regCode As String) As Integer

    http = NewHttp(m.UrlGetRegResult)
    http.AddParam("partner", "roku")
    http.AddParam("deviceID", sn)
    http.AddParam("regCode", regCode)

    print "checking registration status"

    while true
        rsp = http.Http.GetToString()
        xml = CreateObject("roXMLElement")
        if not xml.Parse(rsp) then
            print "Can't parse check registration status response"
            ShowConnectionFailed()
            return 2
        endif

        if xml.GetName() <> "result" then
            print "unexpected check registration status response: ", xml.GetName()
            ShowConnectionFailed()
            return 2
        endif

        if islist(xml.GetBody()) = true then
            for each e in xml.GetBody()
			
			    if e.GetName() = "customerId" then
                    customerId = strtoi(e.GetBody())
					
                elseif e.GetName() = "creationTime" then
                    creationTime = strtoi(e.GetBody())
			
                elseif e.GetName() = "regToken" then
                    token = strtoi(e.GetBody())

                    if token <> "" and token <> invalid then
                        print "obtained registration token: " + validstr(token)
                        saveRegistrationToken(token) 'commit it
                        m.RegistrationToken = token
                        showCongratulationsScreen()
                        return 0
                    else
                        return 3
                    endif

                endif
            next
        endif
    end while

    print "result: " + validstr(regToken) +  " for " + validstr(customerId) + " at " + validstr(creationTime) 

    return 3

End Function

'***************************************************************
' The retryInterval is used to control how often we retry and
' check for registration success. its generally sent by the
' service and if this hasn't been done, we just return defaults 
'***************************************************************
Function getRetryInterval() As Integer
    if m.retryInterval < 1 then m.retryInterval = 30
    return m.retryInterval
End Function

'**************************************************************
' The retryDuration is used to control how long we attempt to 
' retry. this value is generally obtained from the service
' if this hasn't yet been done, we just return the defaults 
'**************************************************************
Function getRetryDuration() As Integer
    if m.retryDuration < 1 then m.retryDuration = 900
    return m.retryDuration
End Function

'******************************************************
'Load/Save RegistrationToken to registry
'******************************************************

Function loadRegistrationToken() As dynamic
    m.RegToken =  RegRead("RegToken", "Authentication")
    if m.RegToken = invalid then m.RegToken = ""
    return m.RegToken 
End Function

Sub saveRegistrationToken(token As String)
    RegWrite("RegToken", token, "Authentication")
End Sub

Sub deleteRegistrationToken()
    RegDelete("RegToken", "Authentication")
    m.RegToken = ""
End Sub

Function isLinked() As Dynamic
    if Len(m.RegToken) > 0  then return true
    return false
End Function

'******************************************************
'Show congratulations screen
'******************************************************
Sub showCongratulationsScreen()
    port = CreateObject("roMessagePort")
    screen = CreateObject("roParagraphScreen")
    screen.SetMessagePort(port)

    screen.AddHeaderText("Congratulations!")
    screen.AddParagraph("You have successfully linked your Roku player to your account")
    screen.AddParagraph("Select 'start' to begin.")
    screen.AddButton(1, "start")
    screen.Show()

    while true
        msg = wait(0, screen.GetMessagePort())

        if type(msg) = "roParagraphScreenEvent"
            if msg.isScreenClosed()
                print "Screen closed"
                exit while                
            else if msg.isButtonPressed()
                print "Button pressed: "; msg.GetIndex(); " " msg.GetData()
                exit while
            else
                print "Unknown event: "; msg.GetType(); " msg: "; msg.GetMessage()
                exit while
            endif
        endif
    end while
End Sub

Debugger output:


------ Running ------
showHomeScreen | msg =  | index = 0
GOT: <result>
    <status>incomplete</status>
    <regCode>fgfgddsf/regCode>
    <retryInterval>30</retryInterval>
    <retryDuration>900</retryDuration>
</result>

Reason:
Can't parse getRegistrationCode response
Connection Failed
DIALOG1: Can't connect to video service - We were unable to connect to the service.  Please try again in a few minutes.
Button pressed:  0  

Current getRegCode:

<result>
    <status>incomplete</status>
    <regCode>fgfgd</regCode>
    <retryInterval>30</retryInterval>
    <retryDuration>900</retryDuration>
</result>

That malformed xml response is being returned by your server. You don’t “clear it” in your Roku.

“belltown” wrote:
That malformed xml response is being returned by your server. You don’t “clear it” in your Roku.

Okay, I got it working successfully once by changing the folder name from /Roku to /Test. The code you gave me now works to clear it beautifully.

The problem I am still having is that once it gets the code it won’t get another code because something is caching the result. I deleted the app from the Roku, changed the folder from Test to Test3 and it still pulls the same regcode. Here is the debugger output that shows even though the server has the regCode as 99994 it pulled abcd.


------ Running ------
showHomeScreen | msg =  | index = 0
GOT: <result>
    <status>incomplete</status>
    <regCode>abcd</regCode>
    <retryInterval>30</retryInterval>
    <retryDuration>900</retryDuration>
</result>

Reason:
Enter registration code abcd at http://www.303north.com/Test3 for 13C2CU068971
checking registration status
<result>
    <status>failure</status>
    <regToken></regToken>
    <customerId>154932</customerId>
    <creationTime>2009-06-30 01:00:00.000</creationTime>
</result>
 3
retry duration 0 at 30 sec intervals for 900 secs max
Wait for 30

The 'GOT: ’ output is what was read from your server. If you think your server is returning a different code then it could be that the Roku has cached the http response, in which case try making the query string unique (e.g. by appending a timestamp to the request).

Well I setup my own virtual server inside my house instead of using my domain.com server and now everything is working like I expect. I wonder what domain.com is/was doing to cause my issues.