Skip to content

GERTi API

Major General Relativity edited this page Aug 8, 2020 · 8 revisions

GERTi (Globally Engineered Routing Technology internal) handles passing messages between computers in a network, and for integration into other networks. GERTi networks connect to other GERTi networks and other GERTe services through a GERTe Gateway which bridges a GERTi network to the GERTe network. This page documents the GERTi API. An example program can be found at https://github.com/GlobalEmpire/GERT/blob/master/GERTi/GERTiTestApplication.lua . Documentation on how to phsyically set up a GERTi network can be found at https://github.com/GlobalEmpire/GERT/wiki/Setting-up-a-GERT-Network . Documentation on the GERTi backend can be found at https://github.com/GlobalEmpire/GERT/wiki/Custom-GERTi-Implementations .

Terms:

GERTc address: Globally Engineered Routing Technology complete: This is the designation for a GERTi network connected to the GERTe internetwork through the GERTiMNC. A GERTc address is a universally unique address specifying a particular GERTi computer on a GERTe endpoint. 0000.1999:0123.0456 would mean GERTi client 0123.0456 on the GERTe endpoint 0000.1999

GERTiAPI: The API is the frontend of GERTi. It, and the backend, resides in GERTiClient.lua, and consists of the functions developers can call.

GERTi MNC: The Master Network Controller. Only one can exist per network, and it controls all the clients, converts address, and can participate in connection pathfinding. It runs GERTiMNC.lua. It also links the GERTi network to the GERTe network if GERTe functionality is enabled.

GERTi Node: Each computer running GERTiClient.lua

Connection ID Connection ID's are functionally equivalent to OC modem ports, or TCP ports. They are named Connection ID's and not ports to avoid confusion with standard OC modem ports.

 

The GERTi API:

For programs and users to interact with GERTi (and GERTe), they will need to use the GERTiClient API in their programs. To do so, merely include GERTiClient.lua in your /lib folder, require the API, and it will automatically load and try to join a network. Documentation of each public function in the API follows:

GERTi.getAddress(): floating point number

This returns the GERTi address of the client. It will be in the format of xxxx.yyyy, with leading 0's deleted. Examples include: 0.1 and 105.4091. Addresses start at 0.1 and increment up to 4095.4095, which allows for over 16 million clients connected to a single GERTi network.

GERTi.getConnections():table

This returns a table of all currently open connections on the computer, whether it is the origination or destination. Connections are subtabled based on a Connection Index, which is formed in the manner of Origination.."|"..Destination.."|"..ConnectionID. There are sub indexes of origin, destination, ID. If the connection's destination is the computer calling getConnection, the order sub index is available, and it can be used to determine how many packets have been received. If the connection's destination is not the computer calling getConnections, nextHop and port sub indexes are available. They describe the modem address and modem port of the next node in the connection path. An example would be:

local myTable = GERTi.getConnections()
local connectionDestination = myTable["0.1|0.2|1"]["order"]

This will get the number of packets received originating from the computer with an address of 0.1, with a destination of the computer with an address of 0.2, and with a connectionID of 1.

GERTi.getNeighbors(): table

This returns a table of neighboring GERTi Clients that can be directly contacted. The table is indexed by the GERTi address of each computer, with the subfields being "add" for the modem address, "port" for the port used to connect to that computer (useful for telling whether it is a modem or tunnel connection), and "tier" being the tier of the computer, ranging from 1 to 3 inclusive for other clients. A lower number indicates that it is logically closer to the MNC.

local myTable = GERTi.getNeighbors()
local node1 = myTable[0.1]
print("Node modem address is "..node1["add"]..", the port is "..node1["port"]..", and the tier is "..node1["tier"])

GERTi.getVersion(): string and formatted string

This returns a string with the version number, and a string with the version number listed according to semantic versioning (Major.Minor.Patch). local versionString, versionNumber = GERTi.getVersion() print("Version String is "..versionString)

The above example will accept both the string and semantic string from the function. The first string may be formatted like "GERTi v1.2 Release" or "GERTi v1.2 Hotfix 1", but the second string will always return with a version formatted in accordance with semantic versioning.

GERTi.send(): does not return

This function allows you to send messages directly to a neighboring computer. This offers lower latency than opening a socket, but does not offer buffering and only works with computers that can directly speak to each other. The function takes two arguments.

  1. Destination: The GERT address of the receiving computer.
  2. Data: The data you want to send. It must be transmittable over a modem card, so unserialized tables and functions are not supported. To send a table, please serialize it first and then use GERTi.send()

GERTi.send(0.1, "Hello!")

The above example will send a message to the neighboring computer of 0.1, with the connectionID -1, and with the message "Hello." A computer on the receiving end merely needs to listen to GERTData events to see the message. For information on using the event system, please see the "Using Events" section of this page.

GERTi.broadcast(): does not return

This function emulates modem.broadcast() but with GERTi packets. Calling this function will send a GERTData packet to all neighboring computers over a modem connection.

GERTi.broadcast("Hello")

The above example will broadcast "Hello" to every computer with a modem connection to the sender. The connection ID on the receiving computer will be -1.

GERTi.openSocket(): socket object

This is the main function used with GERTi to open a socket to another computer to read and write data. Further details on how to manage a socket afterwards is covered in the Managing Sockets section of this page. openSocket takes 2 arguments.

  1. The GERT address of the destination. This may either be a GERTc address (e.g. 1865.1731:0.1) if you want to talk across GERTe, or a GERTi address (e.g. 1.105) for talking on the same GERTi network.
  2. ConnectionID. Optional. If a specific ID is required, like when a computer needs to open a socket to another computer that has opened a socket first, it may be an integer. If a specific ID is not required, a value need not be passed in. ConnectionIDs are like ports, see Terms for explanation.

Note, older programs include a third parameter in between the two listed here. This is still supported, but it is deprecated and will be removed in a future release

Example:

local socket1 = GERTi.openSocket(0.2, 5)
local socket2 = GERTi.openSocket("1095.1095:1096.1096", 1500)

The first line will open a socket over the local GERTi network to the computer with an address of 0.2, and on Connection ID 5. The second line will open a socket over the GERTe internetwork to GERTe endpoint 1095.1095, and the GERTi Node on that endpoint with the address of 1096.1096. The Connection ID in that connection is 1500

GERT events

GERT uses 2 events to allow for asynchronous networking and message processing.

  1. GERTConnectionID (eventName, originAddress, connectionID) This event is fired whenever a connection is opened to the computer. In addition to the event name, it provides the originAddress and connectionID parameters, which identify what computer open the connection and what connectionID they used. This can be useful for a server providing services, as it can wait for a client to open a connection, and then open a socket to the client with the same connectionID.
local newSocket
local function waitForSocket(eventName, originAddress, connectionID)
  print("Received an incoming connection from computer: "..originAddress.." with connectionID: "..connectionID)
  newSocket = GERTi.openSocket(originAddress, true, connectionID)
end
event.listen("GERTConnectionID", waitForSocket)
  1. GERTData (eventName, originAddress, connectionID, [data]) This event is fired whenever a Data packet is delivered to this computer. It only fires on the endpoints of a connection, not any intermediary relays. If the packet is part of a connection between two computers, the last data argument is omitted, and the message must be read by a socket connected to the origin computer over the same address.
local function waitForData(eventName, originAddress, connectionID)
  print("Received and incoming data packet from computer: "..originAddress.." for connectionID: "..connectionID)
  local data = socket1:read()
  print(data[1])
end
event.listen("GERTData", waitForData)

This function will fire whenever a data packet is received by the computer. A more advanced function can incorporate address and connectionID sorting so that only the correct socket gets read. After the function is called, it prints the origin address and connectionID, then reads the socket. The data is then printed to the screen. For more details on operating sockets, please see the following section.

local function waitForData(eventName, originAddress, connectionID, data)
  print("Received and incoming data packet from computer: "..originAddress.." for connectionID: "..connectionID)
  print("The received data is: "..data)
end
event.listen("GERTData", waitForData)

This function will also fire whenever a data packet is received by the computer, but it assumes that the incoming data packet was sent by calling GERTi.send() on the transmitting computer. As GERTi.send() does not rely on sockets, the data is embedded into the event as the 4th argument. The function retrieves that and prints the data directly. GERTi.send() data packets always have a Connection ID of -1, so they can be filtered accordingly.

  1. GERTConnectionClose (eventName, originAddress, destinationAddress, ID) This event is fired whenever a connection is closed, with either the origination or destination being this node. Programs can monitor this event to ensure that they can react appropriately to unexpected connection closures. It will return 4 arguments, the first being the event name, the second being the GERTi address where the connection is originating from, the third being the GERTi address where the connection is made to, and the fourth being the connection ID. Either the origination or destination addresses will be the node getting the event.

Managing a GERT Socket

For the purposes of this section, we will assume you have a socket variable named "socket," with a destination of address 0.2, and an origination of address 0.1. The connection ID for this socket is 1. After opening the socket, you interact with the data stream by calling functions provided by the socket. A GERT socket supports 3 simple operations.

  1. socket:read([flag]) This function is to read data from the socket. If no data packets are available or there is no incoming connection from the other end yet, an empty table is returned. Otherwise, a table of data packets with numerical indices from 1 to 20 is returned. If the flag 2 is passed, the read will not be destructive. Otherwise, the buffer will be cleared on each read. If 20 stored packets are present in the socket buffer when another one arrives, the oldest packet will be dropped and the others will be pushed forward in the queue. GERTi supports message re-ordering, and if a message is received and determined to be out of order, the buffer will be re-ordered accordingly. If maximum reliability is desired, a slight delay before destructively reading the buffer to allow for all messages to be received and ordered is recommended.
local data = socket:read(2)
print("The first data packet is: "..data[1])
local data = socket:read()
print("The queue is now flushed, and the first data packet is: "..data[1])
  1. socket:write(data) This function is to write data to the socket. It will accept any data that can be sent over a regular modem message, but tables must be serialized first and functions are not accepted.
local data = "My program works."
socket:write(data)

This will transmit the string to the computer on the other end of the socket, where it can be read and processed.

  1. socket:close() This function will close the socket. Closing a socket before your program ends is recommended for housekeeping. GERT will automatically close a socket when a computer shuts down, but if the computer runs out of power or the case button is pushed, proper shutdown is not possible. Calling socket:close() prevents the possibility of any unusual and undefined behavior.
Clone this wiki locally