Plan for network support

From OHRRPGCE-Wiki
Jump to navigation Jump to search


Examples/Studies[edit]

These example applications help to figure out what interface we want, both to work to eventually when the interpreter can handle it, and in the near term.

Client uploads and retrieves private data[edit]

This is a train-of-thought. First, let's assume a new script interpreter.

Using request-response[edit]

Client side

server := connect to server("ohrserver.hamsterrepublic.com:4444")
if (server.connected == false) then (...)  # error handling
anything := {"last played": [system day, system month, system year]}
send request(server, "write", {"username":"Bob", "data":anything})
# ... on another day:
request := send request(server, "read", {"username":"Bob"})
wait for request(request)
if (request.failed) then (...) # error handling
data := request.data["last played"]
show string(sprintf("You last played on %d/%d/%d", data[0], data[1], data[2]))

Maybe that should be "send request(server, ["read", {"username":"Bob"}])" instead.

Server side: authenticated and unauthenticated send-and-request can be a standard server type provided without any coding needed. We could consider how you're write it manually in a HamsterSpeak interpreter running on the server, but that would require a whole 'nother interface for handling connections and data storage, so will be left out for now.

Without explicit requests (streams)[edit]

If a slightly more specialised message format is used the above could become:

server := connect to server("ohrserver.hamsterrepublic.com:4444")
if (server.connected == false) then (...)  # error handling
anything := {"last played": [system day, system month, system year]}
send data(server, ["write", "Bob", anything])
# ... on another day:
send data(server, ["read", "Bob"])
data := wait for data(server)
if (not(data)) then (...) # error handling
data := data["last played"]
show string(sprintf("You last played on %d/%d/%d", data[0], data[1], data[2]))

Server pseudocode (the stream is stateless in this case):

for message in socket.input:
    if message[0] == "write":
        datastore.write(key=message[1], value=message[2])
    elif message[0] == "read":
        socket.send(datastore.read(key=message[1]))

In the existing script interpreter[edit]

As the 'stream' example above shows, we can do away with using dicts in this example, and code messages as an array of objects which are either strings or integers:

send data(server, ["write", "user:Bob data:last played", system day, system month, system year])

Now the first element of the array is a message type, and for "write" and "read" the 2nd element is the key and thereafter is data.

Next we need to get rid of the need for arrays, while still keeping all data grouped together as a single message. I suppose send data could just take multiple arguments and implicitly place them in an array:

send data(server, "write", "user:Bob data:last played", system day, system month, system year)

Finally, all strings have to be replaced with string IDs, while avoiding ambiguity in "send data" arguments. Ideally we'd mark the string ids as strings rather than ints, writing for example:

$0="write"
$1="user:Bob data:last played"
send data(server, strid(0), strid(1), system day, system month, system year)

But that's still ambiguous because whatever strid returns is still just an int. So it would be necessary to "box" the ints instead, but we don't want to clutter up the real (future) "send data" command with that kind of nonsense. We should add a temporary to-be-obsoleted command instead. And if we're doing all this boxing, maybe we just tag the type of every argument, for consistency

send typed data(server, type:str, $0="write", type:str, $1="user:Bob data:last played", type:int, system day, type:int, system month, type:int, system year)

It looks like putting everything in a single call isn't very nice (and doesn't allow a flexible array length), so we'll need commands to start a message, add to it, and send it afterall:

start server message(server)
add int to message(message, data)
add string to message(message, data)
add slice to message(message, data)   # etc
finish message(message)

See Also[edit]