Consuming terminal resources
Terminal resources are small single-purpose console applications that can be launched and closed by REST clients. We interact with terminal resources using the WebSocket protocol, and to launch a terminal resource, we make a GET request to the given resource, and include a WebSocket handshake – so that the server can initiate a WebSocket connection for the terminal.
The easiest way to initiate a WebSocket connection with a RESTable API while testing, is to use a command line tool like wscat, but something like this Chrome extension works fine too if you prefer to work with a web browser.
To test things out, let’s make a request to the RESTable.Shell terminal resource on RESTable service. For this we can use this wscat command:
1
wscat -c "wss://myapp.com/api/shell"
This will launch the RESTable.Shell terminal resource, which will let you navigate around the available resources of the server. For more information about the RESTable.Shell resource, see this documentation.
General features of terminal resources
Terminal resources are small, encapsulated command-line applications, that are instantiated for each request that target them. Each such instance can run independently from other instances. Each connected WebSocket has exaxly one terminal resource assigned to it at all times. RESTable will instantiate terminal resources and assign WebSockets to them – a terminal resource can never assign itself to some WebSocket. When a terminal is done with a given WebSocket connection, it must redirect it to a different terminal, for example RESTable.Shell. The Shell is the only terminal resource that can close WebSocket connections. The client can always close the terminal by either using a global command or by simply closing the WebSocket connection from their end.
WebSocket headers
Each WebSocket connected to RESTable has a set of headers, that are copied from the WebSocket upgrade request. In the case of the RESTable.Shell resource resource, these are also used in all subsequent requests from that resource. We can read or modify the headers of the WebSocket by using the #INFO global command.
Terminal resource properties
Each terminal resource declares a set of instance properties that define its state. A common use case for these properties is to define settings that determine the behavior of the terminal resource. Just like with properties of entity resources, terminal resource properties can be read-only. Properties of terminal resources should be documented along with the terminal resource.
There are two ways to set the values of a terminal resource’s properties.
- By including an assignment as a condition in the initial
GETrequest to the terminal resource. - By using the
#TERMINALglobal command with a JSON object as argument.
The example below will demonstrate both these methods.
Example
Let’s look at the properties of the RESTable.Shell resource:
| Property name | Type | Description |
|---|---|---|
| Query | string |
Determines the current location of the shell, and the URI for subsequent requests |
| Unsafe | boolean |
Is the shell currently in unsafe mode? (see the unsafe meta-condition) |
| WriteHeaders | boolean |
Should the shell include headers when writing output? |
| AutoOptions | boolean |
Should the shell automatically send an OPTIONS command after each successful navigation? |
| AutoGet | boolean |
Should the shell automatically send an GET command after each successful navigation? |
Each instance of this terminal resource will contain its own set of values for these properties. They act as the settings of the Shell instance.
We can instantiate the Shell resource by making a WebSocket upgrade request with /shell as URI, and we can optionally include assignments to the terminal’s properties by adding conditions to the URI. To launch a Shell instance with AutoGet and WriteHeaders both set to true, for example, we can use this URI with the WebSocket upgrade request:
1
/shell/autoget=true&writeheaders=true
We can also use the #TERMINAL global command to set the properties of the current terminal once it’s launched. As argument we use a JSON object describing the changes to make. To set AutoGet and WriteHeaders to true for a running Shell instance, we can run the following global command:
1
2
3
4
5
6
7
8
9
10
> #TERMINAL {"AutoGet": true, "WriteHeaders": true}
< Terminal updated
< {
"Query": "/console",
"Unsafe": false,
"WriteHeaders": true,
"AutoOptions": false,
"AutoGet": true,
"StreamBufferSize": 16000000
}
For more information on global commands, see the next section.
Global commands
Global commands are text commands available in all terminal resources, that lets the client perform high-level operations such as setting terminal properties, switching terminals and get metadata about the WebSocket connection.
#TERMINAL
Returns the properties of the current terminal. An optional JSON object can be used as argument to update the properties of the terminal. See this section for an example.
#INFO
Returns an object describing the current WebSocket connection. An optional JSON object can be used as argument to update the contents of the object. The returned object has the following properties:
| Property name | Type | Default value | Description |
|---|---|---|---|
| Host | string (read-only) |
"" |
The host of the WebSocket connection |
| WebSocketId | string (read-only) |
"" |
The unique ID of the WebSocket connection |
| IsSSLEncrypted | boolean(read-only) |
false |
Is the WebSocket connection secure? |
| ClientIP | string (read-only) |
"0.0.0.0" |
The IP of the connected client |
| ConnectedAt | string (read-only) |
"0001-01-01 00:00:00" |
The date and time when the connection was established |
| CurrentTerminal | string (read-only) |
"" |
The type name of the current terminal resource attached to this WebSocket |
| CustomHeaders | object |
{} |
The custom headers for this WebSocket. Other headers, such as Authorization, cannot be viewed or modified here |
The content of CustomHeaders can be changed. To add a header X-MyHeader with value "MyValue", we can use the following global command:
1
2
3
4
5
6
7
8
9
10
11
12
13
> #INFO {"CustomHeaders": {"X-MyHeader": "MyValue"}}
< Profile updated
< {
"Host": "localhost:5001",
"WebSocketId": "Aw",
"IsEncrypted": true,
"ClientIP": "127.0.0.1",
"ConnectedAt": "2021-10-20 15:44:31",
"CurrentTerminal": "RESTable.Shell",
"CustomHeaders": {
"X-MyHeader": "MyValue"
}
}
#SHELL
Running this command redirects the WebSocket to the RESTable.Shell resource.
#DISCONNECT
Running this command closes the WebSocket connection and disposes all attached resources.