sub Main() print "BrightSign / Nowsignage Installer" update_endpoint = "https://cdn.nowsignage.com/ap-southeast-1/brightsign/5.4.1" videoMode = CreateObject("roVideoMode") width = videoMode.GetResX() height = videoMode.GetResY() screen = CreateObject("roRectangle", 0, 0, width, height) CreateAsciiFileFromBase64String("sd:/install.html", GetEncodedInstallationPage()) config = { inspector_server: { port: 2999 }, brightsign_js_objects_enabled: true, url: "file:///sd:/install.html" } htmlWidget = CreateObject("roHtmlWidget", screen, config) htmlWidget.Show() Sleep(15000) m.port = CreateObject("roMessagePort") data = GetLatestVersionInfo(update_endpoint) Sleep(250) if data <> Invalid title = "Installing NowSignage version " + data.version htmlWidget.PostJSMessage({ title: title }) CreateFileFromUrl(update_endpoint + "/autorun.zip", "sd:/update.zip") Sleep(5000) if HasValidChecksum("sd:/update.zip", data.checksum) PerformInstallation() htmlWidget.PostJSMessage({ loading: false, description: "Download complete. Rebooting ..." }) Sleep(3000) RebootSystem() else DeleteFile("sd:/update.zip") htmlWidget.PostJSMessage({ loading: false, description: "Could not verify file integrity, installation aborted" }) end if else Sleep(1500) htmlWidget.PostJSMessage({ loading: false, description: "Could not contact download server, installation aborted. Please make sure the device is connected to the internet" }) end if while true msg = Wait(1000, m.port) end while end sub function GetEncodedInstallationPage() return "PGh0bWw+CiAgPGJvZHk+CiAgICA8c3R5bGU+CiAgICAgKiB7IG1hcmdpbjogMDsgcGFkZGluZzog" end function sub CreateAsciiFileFromBase64String(filePath, data) byteArray = CreateObject("roByteArray") byteArray.FromBase64String(data) text = byteArray.ToAsciiString() WriteAsciiFile(filePath, text) end sub function GetLatestVersionInfo(baseUrl) data = GetStringFromUrl(baseUrl + "/version.json", 2000) if data = Invalid return Invalid end if return ParseJson(data) end function sub CreateFileFromUrl(url, filePath) urlTransfer = CreateObject("roURLTransfer") urlTransfer.SetURL(url) urlTransfer.SetPort(m.port) urlTransfer.GetToFile(filePath) end sub function GetStringFromUrl(url, timeout) urlTransfer = CreateObject("roURLTransfer") urlTransfer.SetURL(url) urlTransfer.SetPort(m.port) if urlTransfer.AsyncGetToString() event = Wait(timeout, m.port) if type(event) = "roUrlEvent" return event.GetString() elseif event = Invalid urlTransfer.AsyncCancel() end if end if return Invalid end function function HasValidChecksum(filePath, expectedChecksum) checksum = GetChecksum(filePath) return LCase(checksum) = LCase(expectedChecksum) end function function GetChecksum(filePath) byteArray = CreateObject("roByteArray") byteArray.ReadFile(filePath) hashGenerator = CreateObject("roHashGenerator", "SHA256") return hashGenerator.hash(byteArray).ToHexString() end function sub PerformInstallation() 'Unarchiving removes every file, including the pin, 'so let's store it in memory and recreate the file later pin = GetScreenPin() package = CreateObject("roBrightPackage", "sd:/update.zip") package.Unpack("sd:/") DeleteFile("sd:/update.zip") if pin <> Invalid WriteAsciiFile("sd:/pin.txt", pin) end if end sub function GetScreenPin() files = MatchFiles("sd:/", "pin.txt") if files.Count() > 0 return ReadAsciiFile("sd:/pin.txt").Trim() else player = CreateObject("roDeviceInfo") return player.GetDeviceUniqueId() end if return Invalid end function