mailto: blog -at- heyrick -dot- eu

The Expanse

In what may be a cruel twist of fate, the SyFy network creates what may be one of the best and most richly detailed "hard sci-fi" space operas of recent times, and then gives up on it after three seasons. Because, I guess, wrestling (when has that been sci-fi?) is a bigger draw to the masses than angry Martian settlers (one with a very prominent New Zealand accent!) and belters speaking a peculiar creole on Ceres, and something about a glowing blue "protomolecule".

Fans of the show weren't too happy with this, so they pitched to have somebody else - Netflix, Amazon, somebody... pick up the show.
And so it was Amazon. Last year they dropped the first three seasons on to their Prime Video service, and I marathoned the lot, especially appreciating that it was a space show that didn't treat viewers like morons. That isn't to say that it was perfect - they still made the common mistake of having fusion drives in space making noise, not to mention medical repair facilities healing people in ways that are dangerously close to Star Trek. But other things were portrayed much more realistically than normal for this sort of programme - the head-asplode (railgun shot) during the battle of the MCRN Donnager was very well done. And, that's basically the first few episodes to kick us off into the fraught universe of The Expanse, where an unknown enemy blows up a boring ice hauler called The Canterbury. The survivors put out a message blaming Mars due to finding some Martian tech on a craft they received a distress call from. The survivors are picked up by the aforementioned Donnager, the Martian flagship. It, itself, gets attacked and eventually scuppers itself (in a nuclear blast) to prevent it being taken by unknown enemy. At this point both Earth and Mars are about to go to war over all of this. A bad-ass UN woman (because the UN now runs Earth) lets it leak that Martian stealth technology was used, and surveillance picks up Mars in a panic doing inventory of their technology, to which the UN woman admits to leaking, and says that if they had to call around to find out what's going on, they aren't behind it either.
So, that's like the first three episodes. To describe what happens for the remaining... what is it, thirty? That would take a book. Because of all the factions, the politics, and who is blaming who for what.

So to series four. The first series produced by Amazon. Three things are immediately obvious. The first is that the series is intended to be binge-watched. There's no cold open, no "last time on The Expanse" recap. There's a title sequence that can be automatically skipped, so you can literally just string the episodes end to end and do the lot at once. As I did.
The second thing is the budget. While The Expanse didn't tend to suffer from shonky CGI (it was nothing like as bad as the effects in, say, Maximum Ride), this time around the alien planet looked sublime. I won't say what happens on the planet (spoilers!), suffice to say that you won't be looking at the effects and laughing or cringing. That's what Cats is for.
And, now, for the final and less good part of the Amazon upgrade. Not being made for American cable TV meant that not only could the episodes run as long as they needed and flow naturally and not within the time constraints of programming, but also they could include material of a more adult nature. We finally get to see somebody in an actual bed, which is weird given that it seems half the females on Ceres were in the sex trade. We also have most of the cast dropping F-bombs frequently.
This last part bugs me. Not because I'm averse to swear words... no... how do I say this?

Elizabeth Bennet would never have grabbed Mr. Darcy and yelled "F**k me harder Mister Darcy!". She just would not have. More to her speed would be to casually observe that she was all of a quiver betwixt her nether regions.
A couple of hundred years ago, people didn't use the word f**k. It's a fairly modern thing, that it's all f**k this and f**k that and we're all truly f**ked.
So a few hundred years in the future, in space, on other planets... no, f**k that, they probably won't use the word f**k much in the future.

It's something that Firefly got right. The word "gorram" (corruption of god damn?) was used a lot, and in an effort to get crap past the radar, worse things were exclaimed in bad Chinese.
So to with The Expanse. Why do we have the word f**k being dragged out so much, when one could create all sorts of lovely insults in Belter - Pashang felota! for instance. Or if you'd rather die than identify as a Belter, then how about a nod to the Norwegian of the opening titles with an insult like Mudd reinsdyrpenis (which is pretty much exactly like it looks). Or if we are to notice the Chinese on the walls in various places, we could always go for Yòng xīchénqì xiūrù zìjĭ which means to shame yourself with a vacuum cleaner.
Hundreds of years in the future, colonisation of Mars and a lot of the asteroid belt. Spaceships are a way of life. They can do so much better than "f**k".

 

Season four, it seems, was quite strange in comparison. It is almost as if the entire thing played out in real time, and the majority of it on this one planet. That's not to say there weren't loads of things going on in the background, for which we'll be hoping for a payoff in season five. It's just... I dunno. I guess now that it's done, now that it's been watched, there's just this big empty void until the next set of episodes turn up. In what, a year?
There's a part of me that thinks that they might have it right with Cloak and Dagger. For that, a new episode would be released every Friday. So 12 episodes or whatever, it would stretch out over three months. Give you something to anticipate, to look forward to. Maybe, ultimately, that's better than a big binge?

 

Using the Acorn fetcher

Something that one expects an operating system to be capable of doing is fetching stuff off the Internet.
It's an activity that RISC OS hasn't traditionally been that strong at, leading people to frequently have to write their own socket level HTTP fetcher or shell out to command line tools such as wget to do the job for them.
One of the complications was that whether or not something was SSL, or "secure", could mean huge changes to the code. The R-Comp SecureSockets module isn't actually that hard to integrate with existing code, it sort of sits in between the existing socket level access and the program sending and receiving data from the remote end.
But, alas, not only is it technically commercial, it also works at sockets level (clue in the name!).

We should expect no less than to be able to make some sort of call to say "fetch this" and have it just get on with doing it.

Turns out, we can. A little set of protocol modules released about the time Acorn created their internet browser "Browse". The modules are a URL fetcher, an HTTP backend, and now thanks to recent development work, an SSL backend that includes the most recent mbedTLS.

Let's get the three modules running:

RMEnsure URL_Fetcher 0.58 RMLoad System:Modules.Network.URL.URL
RMEnsure AcornHTTP   1.03 RMLoad System:Modules.Network.URL.AcornHTTP
RMEnsure AcornSSL    1.04 RMLoad System:Modules.Network.URL.AcornSSL

These three commands will ensure that a recent enough version of the specified module is loaded, and if not, will load it.
You should perform the checks a second time, giving an error if the module isn't loaded and/or recent.

Now for some code for the fetcher. The basics are actually quite simple.

REM >URLFetch
REM by Rick, 2019/12/26

ON ERROR PRINT REPORT$+" at "+STR$(ERL) : END

buffersize% = 256
DIM buffer% buffersize%


PRINT "********************************************"
PRINT "Fetching a blog article (HTTP) - PRESS SPACE"
A = GET
PROCfetch("http://heyrick.eu/blog/index.php?diary=20191224")

PRINT '''"****************************************************"
PRINT    "Fetching ROOL forum recent posts (SSL) - PRESS SPACE"
A = GET
PROCfetch("https://www.riscosopen.org/forum/posts")

PRINT '''"************************************************************"
PRINT    "Fetching blog reference (will fail, redirects) - PRESS SPACE"
A = GET
PROCfetch("https://heyrick.eu/blog/")


PRINT '''"*****"'"Done."

END

:
Okay, we have set up to fetch three things. First, a known blog article on my site, requesting the fetch to use normal unencrypted HTTP.
Secondly, the RISC OS Open forum's recent posts page, this time using SSL.
And, finally, going to my site using just the /blog/ path. This will fail.

The reason why requesting /blog/ on my site fails is not because it is broken, but because there are still outstanding "issues" with the fetcher. When you go to /blog/, my site will issue a redirect (HTTP 302) to the most recent article. The URL fetcher, however, does not follow redirects, nor does it inform you where the redirect is pointing.
You must instead send the request a second time, this time including the necessary incantations to get the fetcher to return the HTTP headers, and parse it out yourself. It's clumsy and stupid and means code duplication. I have asked (on the forum) if it would be possible for the fetcher to extract the new URL and drop it into the data block for the program to pick up. It would make a lot more sense that way. We'll have to see if this gets implemented, but it does seem to be a peculiar omission in the original protocol specification.

Fetching begins by requesting a session handle, and then instructing the fetcher what it is you want fetched.
It is important to note that nothing is actually fetched at this stage. We're just setting things up.

DEFPROCfetch(what$)

  LOCAL session%, status%, reply%, bytesread%

  SYS "URL_Register" TO , session%
  SYS "URL_GetURL", 0, session%, 1, what$
That is the simplest form of the GetURL command. Technically, R0 are flags to point to whether R5 and R6 are special things. R2 is a "method", which is '1' for HTTP GET, and '513' for HTTP GET returning only the request header. R4 is an additional data block if extra things need to be included in the fetch, R5 is normally the size of the R4 data block, and R6 is additional user-agent information. But all of these extras are optional, that shown here is the simple "fetch this" that we want.

Now we come to a loop where we cycle on ReadData. This is where the crux of things happen. Looking up domain names, connecting, and transferring data... this all happens in the background here.

  REPEAT
    SYS "URL_ReadData", 0, session%, buffer%, buffersize% TO ,,,, bytesread%
    SYS "URL_Status", 0, session% TO status%,, reply%
Because of more halfwittery in the protocol description, it is necessary to call ReadData to cause things to happen, and then another SWI to get all the status information that we need. ReadData will return our status word, but it doesn't return the HTTP server response.

The HTTP server response will be '0' while connecting, and '200' once connected. Anything else is a problem.
There are many possible responses, the most well known being 301/302 (redirect), 404 (not found), and 5xx (server error). In this code, anything that isn't 200 OK is rejected as an unexpected error. You should parse the code to return some sort of logical message to the user.

    IF ( (reply% <> 0) AND (reply% <> 200) ) THEN
      PRINT "Unexpected server response "+STR$(reply%)
      SYS "URL_Deregister",, session%
      ENDPROC
    ENDIF

It may also be worth keeping track of elapsed time at this point, whilst the HTTP reply is zero, in order to implement a timeout.

From this point, we pay attention to the URL status word. It defines bits zero to six as follows:

Bit 0Connected to server
Bit 1Request sent
Bit 2Data sent
Bit 3Response received
Bit 4Transfer in progress
Bit 5All data received
Bit 6Transfer aborted

So for the normal course of events, we want to wait until bit 4 is set, and keep on cycling until bit 5 (alone) is set. So here is the code for receiving data during a transfer:

    IF ( status% AND 16 ) THEN
      IF ( bytesread% > 0 ) THEN
        PROCdumpbuffer(bytesread%)
        bytesread% = 0
      ENDIF
    ENDIF
That is to say, if bit 4 is set and there's some data to read, go and deal with it.

We loop until bit 5 (alone) is set:

  UNTIL status% = 32

  IF ( bytesread% > 0 ) THEN
    PROCdumpbuffer(bytesread%)
    bytesread% = 0
  ENDIF

As you can now see, it may be possible to finish a transfer with outstanding data remaining to be read, so we check once more at the end just to be sure nothing is missed.

And, finally...

  SYS "URL_Deregister",, session%
ENDPROC

:

Our dump-buffer is a simple dump-to-screen for the purposes of demonstration. You may prefer to build up data in memory, or write it out to file, whatever...

DEFPROCdumpbuffer(size%)
  FOR l% = 0 TO (size% - 1)
    b% = buffer%?l%
    IF ( (b% < 32) OR (b% = 127) ) THEN
      IF ( (b% <> 10) AND (b% <> 13) ) THEN b% = 46
    ENDIF
    IF (b% <> 13) THEN PRINT CHR$(b%);
    IF (b% = 10) THEN PRINT CHR$(13);
  NEXT
ENDPROC

 

It's not perfect by any stretch of the imagination, but it can provide an SSL-agnostic method of fetching data from remote servers in only a few lines of code.

 

 

Your comments:

Please note that while I check this page every so often, I am not able to control what users write; therefore I disclaim all liability for unpleasant and/or infringing and/or defamatory material. Undesired content will be removed as soon as it is noticed. By leaving a comment, you agree not to post material that is illegal or in bad taste, and you should be aware that the time and your IP address are both recorded, should it be necessary to find out who you are. Oh, and don't bother trying to inline HTML. I'm not that stupid! ☺
 
You can now follow comment additions with the comment RSS feed. This is distinct from the b.log RSS feed, so you can subscribe to one or both as you wish.

David Pilling, 30th December 2019, 22:40
It would be rather exciting to fetch something on RISC OS - SYS "fetch me the head of Alfredo Garcia"
David Pilling, 30th December 2019, 22:41
It would be rather exciting to fetch something on RISC OS - SYS"Fetch me the head of Alfredo Garcia"
David Pilling, 30th December 2019, 22:43
Oh now it looks like I am a double poster - when I'm actually a clumsy clicker - "VALIDATION ERROR" (in red) came up "You must enter the number in reverse" (I know I know). So I did it again. I can only imagine I clicked submit and then double clicked submit again. Nice tidy single click coming up <click>
Rick, 31st December 2019, 01:07
Be careful what you wish for. What would you do if your SWI call did not return an error, and two days later a parcel arrives...with a head inside? 
 
Just pray you didn't run the program multiple times to see why it wasn't working as you expected... :-)
VinceH, 31st December 2019, 11:59
Every time I post, I'm tempted to literally type "<the number> backwards" 
 
But I don't because I'm a big boy now. All grown up and mature. Honest. ;) 
 
(Edit: And in an echo of what David said, I've got a validation error!)
Rick, 31st December 2019, 15:00
Vince - that's why the word "backwards" is in italics, it is an instruction, not a literal "type this". :-) 
 
Works for me - the above comment was sent using Firefox on Android, this one using NetSurf 3.8. It's a simple POST action, so it shouldn't give random errors unless... hmm... <looks at excuse calendar> the phase of the moon is wrong. 
VinceH, 31st December 2019, 18:17
I know - the lack of quotes around that part of the instruction is also a clue - i.e. it doesn't say 'Please type "12345 backwards"' 
 
I still sometimes like to be silly, though. 
 
Um. Except no I don't. As I said. All grown up. Mature. Etc. ;)

Add a comment (v0.10) [help?] . . . try the comment feed!
Your name
Your email (optional)
Validation Are you real? Please type 66477 backwards.
Your comment
Calendar
«   December 2019   »
MonTueWedThuFriSatSun
      
23567
9101112131415
16171819202122
2325272829
30     

Last 5 entries

List all b.log entries

Return to the site index

Geekery

Search

Search Rick's b.log!

PS: Don't try to be clever.
It's a simple substring match.

Etc...

Thank you:
  • Fred
  • Bernard
  • Michael
  • David

Last read at 13:16 on 2020/07/06.

QR code


Valid HTML 4.01 Transitional
Valid CSS
Valid RSS 2.0

 

© 2019 Rick Murray
This web page is licenced for your personal, private, non-commercial use only. No automated processing by advertising systems is permitted.
RIPA notice: No consent is given for interception of page transmission.

 

Have you noticed the watermarks on pictures?
Next entry - 2019/12/31
Return to top of page