space_ex v0.5.1 SpaceEx.Stream
Enables data to be streamed as it changes, instead of polled repeatedly.
Streams are an efficient way to repeatedly retrieve data from the game. In most situations where you find yourself asking for the same piece of data over and over, you’re probably better off using a stream. This will reduce the load on both ends and make your code run faster.
However, if your code checks the value infrequently (e.g. once per second or less), but the value is changing constantly (altitude, current time, etc.), you should consider either using polling, or reducing the stream’s rate.
Creating streams
To set up a stream, you can use the SpaceEx.Stream.stream/2
macro to wrap a
procedure call.
Alternatively, you can use SpaceEx.Procedure.create/1
to create a reference
to the procedure you want to run, and then pass that to
SpaceEx.Stream.create/2
.
Stream lifecycle
Generally, multiple requests to stream the exact same data will be detected by the kRPC server, and each request will return the same stream.
This would ordinarily be a problem for a multi-process environment like
Erlang. If one process calls shutdown/1
, it might remove a stream that
other processes are currently using.
To prevent this, when you create a stream, you also create a bond between
that stream and your current process. Calling shutdown/1
will break that
bond, but the stream will only actually shut down if all bonded processes
are no longer alive.
Streams will also automatically shut down if all bonded processes terminate.
Example usage
require SpaceEx.Stream
stream =
SpaceEx.SpaceCenter.ut(conn)
|> SpaceEx.Stream.stream()
# Equivalent:
stream =
SpaceEx.SpaceCenter.ut(conn)
|> SpaceEx.Procedure.create()
|> SpaceEx.Stream.create()
SpaceEx.Stream.get(stream) # 83689.09043863538
Process.sleep(100)
SpaceEx.Stream.get(stream) # 83689.1904386354
Process.sleep(100)
SpaceEx.Stream.get(stream) # 83689.29043863542
# You can also create a nifty "magic variable" shorthand:
ut = SpaceEx.Stream.get_fn(stream)
ut.() # 83689.29043863544
Process.sleep(100)
ut.() # 83689.39043863546
Process.sleep(100)
ut.() # 83689.49043863548
# You can even create both the stream and the shortcut at once:
{stream, ut} =
SpaceEx.SpaceCenter.get_ut(conn)
|> SpaceEx.Stream.stream_fn()
SpaceEx.Stream.get(stream) # 83689.49043863541
ut.() # 83689.49043863541
Link to this section Summary
Functions
Creates a stream, and optionally starts it
Get (and decode) the current value from a stream
Returns an anonymous function that can be used to query the stream
Detach from a stream, and shut it down if possible
Set the update rate of a stream
Start a previously added stream
Creates a stream directly from function call syntax
Creates a stream and query function directly from function call syntax
Wait for the stream value to change
Link to this section Functions
Creates a stream, and optionally starts it.
procedure
should be a SpaceEx.Procedure
structure. The stream’s value
will be the result of calling this procedure over and over (with the same
arguments each time).
See the module documentation for usage examples.
Options
:start
— whenfalse
, the stream is created, but not started. Default:start: true
.:rate
— the stream’s update rate, in updates per second. Default: unlimited.
Get (and decode) the current value from a stream.
This will retrieve the latest stream value and decode it. (Because streams can receive hundreds of updates every second, stream values are not decoded until requested.)
Note that if a stream has not received any data yet, this function will block
for up to timeout
milliseconds (default: 5 seconds) for the first
value to arrive.
A timeout usually indicates that the stream was created with start: false
,
and it was not subsequently started before the timeout expired.
Returns an anonymous function that can be used to query the stream.
This function can make code cleaner, by emulating a sort of “magic variable”
that constantly updates itself to the current value. For example, if you
assign apoapsis = SpaceEx.Stream.get_fn(apo_stream)
, you can now use
apoapsis.()
to get the up-to-date value at any time.
Detach from a stream, and shut it down if possible.
Streams will not shut down until all processes that depend on this stream have exited or have called this function. This is to prevent streams unexpectedly closing for all processes, just because one of them is done.
Set the update rate of a stream.
rate
is the number of updates per second. Setting the rate to 0
or nil
will remove all rate limiting and update as often as possible.
Start a previously added stream.
If a stream is created with start: false
, you can use this function to
choose when to start receiving data.
Creates a stream directly from function call syntax.
This is equivalent to calling SpaceEx.Procedure.create/1
and SpaceEx.Stream.create/2
.
Example
stream =
SpaceEx.SpaceCenter.Flight.mean_altitude(flight)
|> SpaceEx.Stream.stream()
SpaceEx.Stream.get(stream) # 76.64177794696297
Creates a stream and query function directly from function call syntax.
This is equivalent to calling SpaceEx.Procedure.create/1
,
SpaceEx.Stream.create/2
, and SpaceEx.Stream.get_fn/1
, all in sequence.
Returns a tuple containing the stream and the getter function.
Example
{stream, altitude} =
SpaceEx.SpaceCenter.Flight.mean_altitude(flight)
|> SpaceEx.Stream.stream_fn()
altitude.() |> IO.inspect # 76.64177794696297
Wait for the stream value to change.
This will wait until a new stream value is received, then retrieve it and
decode it. It will block for up to timeout
milliseconds (default:
forever, aka :infinity
), after which it will throw an exit
signal.
You can technically catch this exit signal with try ... catch :exit, _
,
but it’s not generally considered good practice to do so. As such, wait/2
timeouts should generally be reserved for “something has gone badly wrong”.
Example
paused = SpaceEx.SpaceCenter.paused(conn) |> SpaceEx.Stream.stream()
SpaceEx.Stream.wait(paused) # returns true/false the next time you un/pause