Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promises demo in BrightScript (BRS) #12

Merged
merged 8 commits into from
Dec 22, 2023
2 changes: 2 additions & 0 deletions promises-demo-brightscript/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#ROKU_PWD={YOUR_ROKU_DEVICE_DEV_PASSWORD}
#ROKU_HOST={YOUR_ROKU_DEVICE_IP_ADDRESS}
6 changes: 6 additions & 0 deletions promises-demo-brightscript/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#Visual Studio Code
.vscode
out/

#npm
/node_modules
191 changes: 191 additions & 0 deletions promises-demo-brightscript/components/MainScene.brs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
sub init()
initOnScreenImage()
m.top.observeFieldScoped("simpleResult", "onSimpleResultChange")
m.top.observeFieldScoped("chainResult", "onChainResultChange")
m.top.observeFieldScoped("parallelResult", "onParallelResultChange")

'Uncomment the example below to run...

'Simple single request
' simpleExample("http://ip-api.com/json/")

'Chain requests
' chainExample()

'Parallel requests
' parallelExample()

'Simple single request with error response
' simpleExample("http://invalid--url.com")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love to see a simple UI with a few buttons in it that trigger these various functions. That way devs don't have to uncomment the code to test out a specific flow.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we merge what we have? ...will put this on my todo for the new year.

end sub

function networkRequest(url as string, method = "GET" as string, body = {} as object) as object
promise = promises_create()
task = createObject("roSGNode", "NetworkTask")
task.url = url
task.method = method
task.body = body
task.promise = promise
task.control = "RUN"
return promise
end function

disc7 marked this conversation as resolved.
Show resolved Hide resolved
sub simpleExample(url as string, method = "GET" as string)
disc7 marked this conversation as resolved.
Show resolved Hide resolved
context = {
result: invalid
}

promise = networkRequest(url, method)

promises_onThen(promise, sub(response as object, context = {} as dynamic)
if (response.error = invalid)
context.result = "Your timezone is " + response.timezone
else
'See: https://developer.roku.com/en-gb/docs/references/brightscript/events/rourlevent.md#getresponsecode-as-integer
print "Got a network error response!!!", response.responseCode
end if

m.top.simpleResult = context

end sub, context)

promises_onCatch(promise, sub(response as object, context = {} as dynamic)
print "Caught a Simple promise error!!!", response
end sub, context)

promises_onFinally(promise, sub(response as object, context = {} as dynamic)
print "Simple promise completed!!!"
end sub, context)
end sub

sub chainExample()
disc7 marked this conversation as resolved.
Show resolved Hide resolved
context = {
result: invalid
}

promise = networkRequest("http://ip-api.com/json/")

promises_chain(promise, context).then(function(response, context)
if (response.error = invalid)
disc7 marked this conversation as resolved.
Show resolved Hide resolved
return getTimeApiTimeToFiji(response.timezone)
end if

end function).then(function(response, context)
disc7 marked this conversation as resolved.
Show resolved Hide resolved
if (response.error = invalid)
context.result = getChainResultString(response)
end if

m.top.chainResult = context

end function).catch(function(error, context)
print "Caught an error with the chain promise!!!", error

end function).finally(function(error, context)
print "Chain promise completed!!!", error
end function)
end sub

sub parallelExample()
promises = promises_all([
getIpApiTimeZoneByDomain("google.com")
getIpApiTimeZoneByDomain("netflix.com")
getIpApiTimeZoneByDomain("chatgpt.com")
])
promises_chain(promises).then(function(results)
disc7 marked this conversation as resolved.
Show resolved Hide resolved
m.top.parallelResult = {
result: [
"Google.com's timezone is " + results[0].timezone,
"Netflix.com's timezone is " + results[1].timezone,
"ChatGPT.com's timezone is " + results[2].timezone
]
}

end function).catch(function(error)
print "Caught an error with the parallel promise!!!", error

end function)
end sub

'****************************************************************
'#region *** CALLBACKS
disc7 marked this conversation as resolved.
Show resolved Hide resolved
'****************************************************************

sub onSimpleResultChange(event as object)
print "onSimpleResultChange:"
print event.getData().result
end sub

sub onChainResultChange(event as object)
print event.getData().result
end sub

sub onParallelResultChange(event as object)
for each resultStr in event.getData().result
print resultStr
end for
end sub

'****************************************************************
'#endregion *** CALLBACKS
disc7 marked this conversation as resolved.
Show resolved Hide resolved
'****************************************************************

'****************************************************************
'#region *** HELPER FUNCTIONS
'****************************************************************

function getIpApiTimeZoneByDomain(domain as string) as object
url = "http://ip-api.com/json/" + domain
return networkRequest(url)
end function

function getTimeApiTimeToFiji(fromTimeZone as object) as object
print "Your timezone is " + fromTimeZone
url = "https://timeapi.io/api/Conversion/ConvertTimeZone"
method = "POST"
date = CreateObject("roDateTime")

body = {
"fromTimeZone": fromTimeZone
"dateTime": getFullDate() + " 00:00:00"
"toTimeZone": "Pacific/Fiji"
"dstAmbiguity": ""
}
return networkRequest(url, method, body)
end function

function getFullDate() as string
date = CreateObject("roDateTime")
fullDate = date.getYear().toStr() + "-"

if date.getMonth() < 10
fullDate += "0"
end if
fullDate += date.getMonth().toStr() + "-"

if date.getDayOfMonth() < 10
fullDate += "0"
end if
fullDate += date.getDayOfMonth().toStr()

return fullDate
end function

function getChainResultString(data as object) as object
currentDay = 25
fijiDay = data.conversionResult.day
fijiHour = data.conversionResult.hour
aheadOrBehind = "ahead"
if (fijiDay > currentDay) then aheadOrBehind = "behind"
return "Fiji is " + fijiHour.toStr() + " hours " + aheadOrBehind + " of your timezone!"
end function

sub initOnscreenImage()
'Setting the image size based on the Roku device UI resolution
resolutionName = LCase(createObject("roDeviceInfo").getUIResolution().name)
backgroundImage = m.top.findNode("backgroundImage")
backgroundImage.uri = backgroundImage.uri.replace("{size}", resolutionName)
end sub

'****************************************************************
'#endregion *** HELPER FUNCTIONS
'****************************************************************
13 changes: 13 additions & 0 deletions promises-demo-brightscript/components/MainScene.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<component name="MainScene" extends="Scene">
<script type="text/brightscript" uri="MainScene.brs"/>
<script type="text/brightscript" uri="pkg:/source/promises.brs"/>
<interface>
<field id="simpleResult" type="assocarray"/>
<field id="chainResult" type="assocarray"/>
<field id="parallelResult" type="assocarray"/>
</interface>
<children>
<Poster id="backgroundImage" uri="pkg:/images/splash-screen_{size}.png"/>
</children>
</component>
55 changes: 55 additions & 0 deletions promises-demo-brightscript/components/NetworkTask.brs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
sub init()
m.port = CreateObject("roMessagePort")
m.REQUEST_TIMEOUT = 5
m.top.functionName = "makeRequest"
end sub

sub makeRequest()
try
result = getNetworkResult(m.top.url, m.top.method, m.top.body)
if (result.data <> invalid)
result = ParseJson(result.data)
end if
promises_resolve(result, m.top.promise)
catch e
promises_reject(e, m.top.promise)
end try
end sub

function getNetworkResult(url as string, method as string, body as object) as object
urlTransfer = CreateObject("roUrlTransfer")
urlTransfer.setUrl(url)
urlTransfer.setRequest(method)
urlTransfer.setCertificatesFile("common:/certs/ca-bundle.crt")
urlTransfer.initClientCertificates()
urlTransfer.setMessagePort(m.port)
urlTransfer.setPort(m.port)
urlTransfer.setMinimumTransferRate(1, m.REQUEST_TIMEOUT)
if (method = "GET")
urlTransfer.asyncGetToString()
else
urlTransfer.addHeader("Accept", "application/json")
urlTransfer.addHeader("Content-Type", "application/json")
body = FormatJSON(body)
urlTransfer.asyncPostFromString(body)
end if

msg = wait(0, m.port)
if type(msg) = "roUrlEvent"

responseCode = msg.getResponseCode()
responseString = msg.getString()

if responseCode = 200
return {
data: responseString
}
else
return {
error: true
responseCode: responseCode
data: invalid
}
end if
end if
end function
11 changes: 11 additions & 0 deletions promises-demo-brightscript/components/NetworkTask.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?rokuml version="1.0" encoding="utf-8"?>
<component name="NetworkTask" extends="Task">
<script type="text/brightscript" uri="NetworkTask.brs"/>
<script type="text/brightscript" uri="pkg:/source/promises.brs"/>
<interface>
<field id="url" type="string"/>
<field id="method" type="string"/>
<field id="body" type="assocarray"/>
<field id="promise" type="node"/>
</interface>
</component>
6 changes: 6 additions & 0 deletions promises-demo-brightscript/components/Promise.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<component name="promises_Promise" extends="Node">
<interface>
<field id="promiseState" type="string" value="pending" alwaysNotify="true" />
</interface>
</component>
<!--//# sourceMappingURL=./Promise.xml.map -->
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions promises-demo-brightscript/manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Channel Details
title=Promises Demo BrightScript (BRS)
major_version=1
minor_version=0
build_version=0

# Channel Assets
mm_icon_focus_sd=pkg:/images/channel-poster_sd.png
mm_icon_focus_hd=pkg:/images/channel-poster_hd.png
mm_icon_focus_fhd=pkg:/images/channel-poster_fhd.png

# Splash Screen + Loading Screen Artwork
splash_screen_sd=pkg:/images/splash-screen_sd.jpg
splash_screen_hd=pkg:/images/splash-screen_hd.jpg
splash_screen_fhd=pkg:/images/splash-screen_fhd.jpg
splash_color=#808080
splash_min_time=0

# Resolution
ui_resolutions=fhd
15 changes: 15 additions & 0 deletions promises-demo-brightscript/source/main.brs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
sub Main(args as object)
screen = createObject("roSGScreen")
m.port = createObject("roMessagePort")
screen.setMessagePort(m.port)
screen.createScene("MainScene")
screen.show()

while(true)
msg = wait(0, m.port)
msgType = type(msg)
if (msgType = "roSGScreenEvent")
if msg.isScreenClosed() then return
end if
end while
end sub
Loading