---
# System prepended metadata

title: CloudLink

---

# CloudLink

![CloudLink Suite Banner](https://i.imgur.com/gAhJxVu.png)

## Welcome!
Welcome to the official documentation for the CloudLink Suite!

Please keep the comments clean. Information pretaining to the extension and the server can be found here.

Note that these docs contain stability levels. You can view the information about stability levels here:
:::::spoiler
&nbsp;
::::success
**Stable**
3 (Stable)
2.5 (Stable/Subject to Change)
2 (Subject to Change)
::::
::::warning
**Experimental**
1 (Experimental)
::::
::::info
**Draft/Not Usable**
0 (Draft)
::::
::::danger
**Deprecated**
-1 (Not Recommended)
-2 (Deprecated)
::::
:::::

# Extension
## Loading the extension
::::success
**Stability:** 3 (Stable)
::::

To use CloudLink, you will need to load it in a Scratch Mod. You can use one of the following to load CloudLink:

### Automatically loaded
[• TurboWarp](https://turbowarp.org/editor?extension=https://mikedev101.github.io/cloudlink/B3-0.js)
[• SheepTester's E羊icques](https://sheeptester.github.io/scratch-gui/?url=https://mikedev101.github.io/cloudlink/B3-0.js)

### Manual loading required
[• Ogadaki's Adacraft](https://adacraft.org/studio/)
Open the Editor, Click on the "Extensions" button (it looks like this): ![extensions button](https://i.imgur.com/RRfzPHx.png) and click on "CloudLink".

## Extension Basics
::::info
**Stability:** 0 (Draft)
::::

### Getting started
[**Learn more on how to correctly start a CloudLink connection.**](https://hackmd.io/G9q1kPqvQT6NrPobjjxSgg?view#Example-Connection-Setup)


## Blocks index
::::success
**Stability:** 3 (Stable)
::::

### Connect to (ws://localhost:3000/)
![connect0](https://i.imgur.com/0KyQwST.png)
This block allows you to connect to any server IP. By default, it will allow you to connect to CloudLink running on your computer's localhost on port 3000 *(see the server section for more details)*.

You can put in any server address that starts with ```wss://```.

*(For security purposes, web browsers don't allow you to use server URLs that start with```ws://```, as these connections aren't secure. The only exception to this rule is the localhost/127.0.0.1.)*

### Connect to (Server)
![connect1](https://i.imgur.com/nDjVrCt.png)

This block allows you to connect to a publically accessible server. The list is only updated when the extension is loaded. When the extension is loaded, a fetch request is sent and will download a string of JSON from GitHub, containing an array of all the available servers to use. From there, you can simply select a server through the menu button on the block, and run the block to connect. 

To implement a user-friendly server selector, use the Server List reporter, the JSON parser block, and the Connect to IP block.

This block is intended for testing/development purposes only and shouldn't be used in production. ***Server list subject to change.***

### Disconnect
![disconnect](https://i.imgur.com/Bqtlgxg.png)
This block terminates the connection to the server. Should be self-explanitory. 

### Set (A name) as username
![setname](https://i.imgur.com/e1B0xXH.png)
This block sets your username on the link. This will only work when you are connected to a server.

The block only allows the username to be set when the input meets the following criteria:

1. The input is no longer than 20 characters.
2. The input cannot be blank.
3. The input cannot contain a username that already exists on the link *(username conflicts)*
4. The input cannot be a reserved ID:
    * %CA% - CloudAccount services
    * %CC% - CloudCoin services
    * %CD% - CloudDisk services
5. The connection must be established and working.
6. The username has not been set previously.

The username block can only be used once per connection. To change your username, you must disconnect from the link and reconnect.

### Send (Apple)
![sendgl](https://i.imgur.com/7gDLhFq.png)
This block sends general-purpose packets to everyone (including you) connected on the link.

The block supports the following datatypes:

* String (ASCII, UTF, etc.)
* Int/Float (Numbers)
* JSON ({"foo": "bar"})

The packet will be sent under the following criteria:
1. The data input cannot be larger than 1 KB in size (1000 characters/bytes)

### Send (Apple) to (A name)
![sendpl](https://i.imgur.com/3Ugh779.png)

Like the "Send (A name)" block, this block allows you to send general-purpose packets to specific usernames.

The packet supports all the same datatypes as it's counterpart, and only allows the packet to be send under the following criteria:

1. The username input cannot be blank.
2. The username input contains a username present on the link.
3. The data input cannot be larger than 1 KB in size (1000 characters/bytes)

### Send Var (Apple) with Data (Banana)
![sendvargl](https://i.imgur.com/rIPQEgB.png)
Like the "Send (Apple)" block, it allows you to send general-purpose packets to everyone (including you) on the link, however, this data is sent as a custom variable.

By specifying a name and setting a value, you can send an infinite amount of custom variables.

Like the "Send (Apple)" block, it supports all the same datatypes.

The packet will be sent, under the following criteria:

1. The variable name input cannot be blank.
2. The variable data input cannot be larger than 1 KB in size (1000 characters/bytes)

On the receiving end, if the variable doesn't exist, it will be created and it's value will be written. Variables will survive as long as the connection is established and running. All variable data will be destroyed when the connection is lost or the "Disconnect" block is used.

### Send Var (Apple) to (A name) with Data (Banana)
![sendvarpl](https://i.imgur.com/J63NGcg.png)
Like the "Send (Apple) to (A name)" block, it allows you to send general-purpose packets to specific usernames, however, this data is sent as a custom variable.

By specifying a name and setting a value, you can send an infinite amount of custom variables.

Like the "Send Var (Apple) with Data (Banana)" block, it supports all the same datatypes.

The packet will be sent, under the following criteria:

1. The variable name input cannot be blank.
2. The username input must cannot be blank.
3. The username input contains a username present on the link.
4. The variable data input cannot be larger than 1 KB in size (1000 characters/bytes)

### Reset Got New [Global/Private/Direct/Status Code] data
![resetgotnewg/pdata](https://i.imgur.com/hrgjRc8.png)
This block resets the "Got New [Global/Private/Direct/Status Code] Data?" reporter's value to False. 

You can use this block to signify that a new Global/Private stream packet has been handled and that the code should wait for a new packet.

### Reset Got New [Global/Private] var (Apple) data
![resetgotnewg/pvardata](https://i.imgur.com/4JIlLlJ.png)
This block resets the "Got New [Global/Private] var (Apple) Data?" reporter's value to False. 

You can use this block to signify that a new Global/Private variable packet has been handled and that the code should wait for a new packet.

### Send command (cmd) (id) (val)
![customcmdblock](https://i.imgur.com/Uv9ZPK7.png)
This block is a custom command block, which allows you to interact with CloudLink to a greater degree than before. You can write your own commands for CloudLink Server and use this block to interface with those commands. [**See more information on how to use this block.**](https://hackmd.io/G9q1kPqvQT6NrPobjjxSgg?view#Sending-and-Getting-packets)

## Reporters index
::::success
**Stability:** 3 (Stable)
::::

### Global data
![gdatavar](https://i.imgur.com/MGjxvnR.png)
This reporter returns the output of the global data stream. It is automatically updated whenever someone on the link uses the "Send (Apple)" block.

### Private data
![pdatavar](https://i.imgur.com/VVGytuo.png)
This reporter returns the output of your private data stream. It is automatically updated whenever someone on the link uses the "Send (Apple) to (A name)" block, and that the username has been set to yours.

### Direct data
![ddatavar](https://i.imgur.com/l9X2fM8.png)
This reporter returns the output of the direct data stream between the client and CloudLink server. It is automatically updated whenever the server sends information directly to the client.

### Link status
![linkstate](https://i.imgur.com/cO68gNQ.png)
This reporter returns the state of the extension as well as the state of the connection. It returns a int. value in this list:

| Value | Description |
| -------- | -------- |
| 0 | Extension started |
| 1 | Connecting to server |
| 2 | Connected |
| 3 | Disconnected |

### Status Code
![statuscodevar](https://i.imgur.com/gzmnHoO.png)
This reporter returns the output of the current status code of the server. The output is updated when CloudLink server handles a request. [**You can view an entire list of possible codes here.**](https://hackmd.io/G9q1kPqvQT6NrPobjjxSgg?view#Status-Codes)

### Usernames
![usernames](https://i.imgur.com/TdiBxQU.png)
This reporter returns the current list of all connected users (Any username that has % at the beginning/end will be filtered out). The output is a string array, separated by a semicolon (;).

Example:
```A name; Another name; apple; banana; MikeDEV; TheLongestUsername;```

### My username
![myusername](https://i.imgur.com/HbbdFlh.png)
This reporter returns the currently set username for your client. It's value is set when the "Set (A name) as username" is used.

### Extension version
![extvers](https://i.imgur.com/qzp6dyO.png)
This reporter returns the current version number of the extension.

### Server version
![servers](https://i.imgur.com/AvWXyXH.png)
This reporter returns the current version number of the server.

### Server List
![srvrlist](https://i.imgur.com/i1YiBJW.png)
This block returns a string of JSON containing the available public servers to use. This block is recommended for implementing a server selector. Block will be set immediately when the extension is loaded and the latest server list data has been fetched.

### [Global/Private] var (Apple) data
![g/pvardata](https://i.imgur.com/ZSCJLzQ.png)
This block returns the output of the variable within the specified data stream. It is automatically updated whenever someone on the link uses the "Send Var (Apple) with Data (Banana)" (Global) or the "Send Var (Apple) to (A name) with Data (Banana)" (Private) block.

### JSON Parser
![jsonparser](https://i.imgur.com/nprse8V.png)
This block returns the output of parsed JSON.

## Boolean index
::::success
**Stability:** 3 (Stable)
::::

### Connected?
![connected](https://i.imgur.com/ClMl7A0.png)
This boolean returns true if the link state is connected (2), and returns false otherwise.

You can use this block to syncronize connections.

### Username synced?
![usernamesynced](https://i.imgur.com/vBI8QLt.png)
This boolean returns true if the username has been set on the server and has been relayed to all clients.

You can use this block to syncronize connections.

### Got new [Global/Private/Direct/Status Code] Data?
![gotnewg/pdata](https://i.imgur.com/vqzvAu5.png)
This boolean returns true if there is new data present on the Global/Private/Direct/Status Code data streams. It's value(s) are reset when the "Reset Got New [Global/Private/Direct/Status Code] data" block is used.

You can use this block to wait for new packets and perform functions when a new Global/Private stream packet is received.

### Got new [Global/Private] Var (Apple) Data?
![gotnewg/pvardata](https://i.imgur.com/pG44y8U.png)
This boolean returns true if there is new data present on the global/private variables. It's value(s) are reset when the "Reset Got New [Global/Private] var (Apple) data" block is used.

You can use this block to wait for new packets and perform functions when a new Global/Private variable packet is received.

### ID (Another name) Connected?
![idconnected](https://i.imgur.com/1SLapw9.png)
This boolean returns true if the specified username exists on the link.

You can use this block to check if a server is online or that a certain user is connected.

# Python Server/Client Quickstart Guide
::::success
**Stability:** 2.5 (Stable/Subject to change)
::::

## Installing CloudLink
CloudLink can be downloaded and imported as a python module. To install CloudLink, you can:

### 1. Install CloudLink from pypi
*     py -m pip install cloudlink (on Windows)
*     python3.9 -m pip install cloudlink (on Linux/Unix)

### 2. Directly downloading the latest build from GitHub
Simply download [cloudlink.py](https://github.com/MikeDev101/cloudlink/blob/master/cloudlink/cloudlink.py) and place it into your development environment's directory or into the directory where you'll be using it.

## Dependencies
**CloudLink has 2 dependencies**, which are [`websocket-server`](https://github.com/Pithikos/python-websocket-server) and [`websocket-client`](https://github.com/websocket-client/websocket-client
). Install these libraries to get CloudLink to work.

## Instanciating CloudLink
To instanciate CloudLink in your project, simply add the following lines of code:

`from cloudlink import CloudLink`
`cl = CloudLink()`

From here, CloudLink will be accessable as part of the "cl" object. From there, you can do whatever you need CloudLink to do.

## Basic usage

::::danger
# **Protect yourself from security exploits!**

If you are exposing CloudLink to the internet, a good suggestion is to use a reputable **tunneling or reverse proxy service.** Also be sure to install CloudLink into a virtual environment or on a up-to-date machine!

For details on supported services, please see this [**GitHub Issue.**](https://github.com/MikeDev101/cloudlink/issues/9)
::::

### Starting a server
At the very end of your code, add `cl.server()`. This will start running CloudLink in server mode, which creates a new websocket server on `ws://127.0.0.1:3000/`.

`from cloudlink import CloudLink`
`cl = CloudLink()`
`cl.server()`

::::warning
**DO NOT INCLUDE ANY CODE AFTER STARTING THE CLOUDLINK SERVER, AS IT WILL NOT RUN. CLOUDLINK SERVER WILL BLOCK ANY OTHER CODE FROM RUNNING.**

*...or, you can just run CloudLink in another thread. But that's some otherworldly stuff there.*
::::

#### Custom Ports
You can specify the port number CloudLink will host on by specifying the optional "port" parameter.

`cl.server(port = 42069)`
* In this example, we are specifying CloudLink to run on port 42069.

#### Custom IPs
Like the "port" parameter, you can also specify the IP address CloudLink will run on using the optional "ip" parameter.

`cl.server(ip = "0.0.0.0")`
* In this example, we are specifying CloudLink to run on the local machine on IP 0.0.0.0, which will allow CloudLink to be accessable over the local network.
* This is required if you want to run CloudLink on Repl.

### Running as a Client
Like with CloudLink server, you can run the module as a client, which will emulate the likes of the Scratch extension. As you can probably tell, simply add `cl.client()` to run as a client.

`from cloudlink import CloudLink`
`cl = CloudLink()`
`cl.client()`

By default, leaving this function with no extra parameters will connect to CloudLink on the Localhost on port 3000, or `ws://127.0.0.1:3000/`.

#### Connecting to an external server or custom IP
You can specify the server IP to connect to by adding the "ip" parameter.

`cl.client(wss://cloudlink-sample-server.mikedev101.repl.co/)`
* This example will tell CloudLink to connect to the CloudLink sample server, hosted on Repl.

#### URL formatting
The server IP must be formatted using the following:

`(ws or wss)://(subdomain).(hostname).(top level domain):(port number (if needed))/`

::::warning
It is not recommended to connect to an insecure websocket server (ws://). Ideally, you should connect to a secure websocket server (wss://).
::::

### Callbacks

::::info
**Both CloudLink Client and CloudLink server can have callback bindings.**

The `on_packet` binding **will function differently** in CloudLink Server than CloudLink Client.

If running as a **server**, CloudLink will only run your function if the server gets a `direct` command. 

**See CloudLink Protocol Reference for more details about commands.**
::::

Notice that while running the above scripts, nothing really happens in the console. That's because nothing else is happening! If you want to get CloudLink to do things, you'll need to bind some callbacks.

Binding callbacks is simple, as all you need to do is run:

`cl.callback("(CALLBACK ID)", (A FUNCTION IN YOUR CODE))`

`from cloudlink import CloudLink`
`cl = CloudLink()`
`def got_a_message_for_you(message):`
`    print(message)`
`cl.callback("on_packet", got_a_message_for_you)`
`cl.client()`
* In this example, we are telling CloudLink to bind the function "got_a_message_for_you" to CloudLink's built-in callback function "on_packet." Every time CloudLink gets a new message, it will run the function "got_a_message_for_you", with a "message".

::::warning
**As mentioned above, do NOT run any other code after starting the server or client, as it will not run.**

Add your `cl.callback()` function(s) BEFORE calling `cl.server()` or `cl.client()`.
::::

### Debugging mode
CloudLink is designed to be as resilient and stable as possible, so even tiny exceptions will get caught, which might be problematic when you are debugging your code.

If you are running into code troubles and can't figure out why, you can pass along the "debug" parameter while instanciating CloudLink.

`from cloudlink import CloudLink`
`cl = CloudLink(debug = true)`

From here, CloudLink will start spitting out everything that occurs when you run a server or start a client.

::::info
It is recommended to enable the `debug` parameter in a production server environment for info if you encounter server problems.
::::

# Python Client/Server API Reference

::::success
**Stability:** 2.5 (Stable/Subject to change)
::::

### API Methods
| Method | Description | Takes | Returns | Supported modes |
| -------- | -------- | -------- | -------- | -------- |
| `server()` | Runs CloudLink in server mode. | (Optional) ip: Str. Type, Specifies the IP to bind to run CloudLink server on. (Optional) port: Int. Type, Specifies the port # to listen to. | None | None |
| `client()` | Runs CloudLink in client mode. | (Optional) ip: Str. Type, specifies the Server IP to connect to, not specifying this parameter will default to `ws://127.0.0.1:3000/` | None | None |
| `stop()` | Shuts down the server or disconnects the client. | (Optional) abrupt: Bool. Type, if true the server will forcefully terminate, leaving false or not specifying this parameter will default to graceful shutdown, this parameter only works if running in Server mode. | None | Client and Server |
| `callback()` | Binds a function for callbacks. | callback_id: Str. Type, the ID of the callback to bind to. function: Function Type, the function to run code when this callback is used | Depends on function. **See Callback IDs for more info.** | Client and Server |
| `sendPacket()` | Sends JSON packets. | msg: Dict type, see CLPv3 table for more info. | None | Client and Server |
| `setMOTD()` | Sends JSON packets. | enable: Bool type, can be set to true to enable Message-Of-The-Day, false to disable. motd: Str. type, the message to broadcast as the Message-Of-The-Day | None | Server only |
| `getUsernames()` | Returns the current username list. | None | List | Client and Server |
| `getIPofUsername()` | Returns the IP address of a username. | user: Str. Type, the username of the client to get the IP address from. | Str | Server only |
| `getIPofObject()` | Returns the IP address of a client using it's memory object instead of a username. | obj: Dict. Type, the memory address reference to a websocket client. | Str | Server only |
| `trustedAccess()` | Enables or disables Trusted Access on the server. | enable: Bool. Type, turns on/off the feature. keys: List Type, the list of valid keys, only supports strings. | None | Server only |
| `untrust()` | Manually untrusts a client. | obj: Dict. Type, the memory address reference to a websocket client. | None | Server only |
| `loadIPBlocklist()` | Loads a list of blocked IPs. | blist: List Type, a list containing strings of IP addresses to block. | None | Server only |
| `blockIP()` | Blocks an IP address. | ip: Str. Type, the IP address to block. | None | Server only |
| `unblockIP()` | Unblocks an IP address. | ip: Str. Type, the IP address to unblock. | None | Server only |
| `getIPBlocklist()` | Gets the current IP blocklist. | None | List | Server only |

### Callback IDs
| Callback ID | Returns | Description |
| -------- | -------- | -------- |
| `on_packet` | Message (JSON, String, Number) | Returns data when a new message is received. **If the packet is JSON, the`cmd` parameter is the `direct` command, and the client does not have a username set up, it will return with the client's dict. memory object  instead for the `origin`.** |
| `on_error` | Error (String, Client Only), None (Server) | Returns error info if an error occurs. |
| `on_connect` | Client (Object, Server only), None (Client) | Runs code when the server gets a new user connected, or the client has connected to the server. |
| `on_close` | Client (Dict, Server only), None (Client) | Runs code when the server detects a disconnect or when the client closes the connection. |

# CloudLink Protocol Reference
::::success
**Stability:** 2.5 (Stable/Subject to change)
::::
## Example Connection Setup
This is an example of a proper CloudLink connection setup.

#### For servers WITHOUT Trusted Access enabled
1. A client connects to a server.
2. The server sends the client the [**MOTD (if enabled), and it's CloudLink version number.**](https://hackmd.io/G9q1kPqvQT6NrPobjjxSgg?view#On-connection)
3. The server sends over the username list.

`{`
`    "cmd": "ulist",`
`    "val": "something; another boring name; foobar;"`
`}`

4. The server sends over the current "Global Data" value.

`{`
`    "cmd": "gmsg",`
`    "val": "Hello, world!"`
`}`


5. The client reports it's [**client type.**](https://hackmd.io/G9q1kPqvQT6NrPobjjxSgg?view#Specifying-Client-Type)

`{`
`    "cmd": "direct",`
`    "val": {"cmd": "type", "val": "(scratch/py/js)"}`
`}`

6. The client specifies a username using the "setid" command.

`{`
`    "cmd": "setid",`
`    "val": "(Username)"`
`}`

7. [**The server and client, as well as all the other clients, can now begin communication.**](https://hackmd.io/G9q1kPqvQT6NrPobjjxSgg?view#Sending-and-Getting-packets)
8. The client can close it's websocket connection to disconnect.

#### For servers WITH Trusted Access enabled
1. A client connects to a server and sends over it's IP address and client type.

`{`
`    "cmd": "direct",`
`    "val": {"cmd": "ip", "val": "(IP ADDRESS)"}`
`}`

`{`
`    "cmd": "direct",`
`    "val": {"cmd": "type", "val": "(scratch/py/js)"}`
`}`

2. The server will send over the [**MOTD (if enabled), CloudLink version number**](https://hackmd.io/G9q1kPqvQT6NrPobjjxSgg?view#On-connection), and status code `I:112 | Trusted Access enabled`. The server will be listening for only `direct` packets or `gmsg` packets. Any other packet will return with `E:115 | Refused`.

`{`
`    "cmd": "statuscode",`
`    "val": "I:112 | Trusted Access enabled"`
`}`

3. The client can either:
    A. Send a TA Key over the Direct link:
    `{`
    `    "cmd": "direct",`
    `    "val": "(KEY)"`
    `}`
    B. Send a TA Key over the Global data stream link (The "Send (Apple)" block):
    `{`
    `    "cmd": "gmsg",`
    `    "val": "(KEY)"`
    `}`
4. If the key is valid, the server will return with status code `I:100 | OK` and send over the username list and current "Global Data" value.

`{`
`    "cmd": "ulist",`
`    "val": "something; another boring name; foobar;"`
`}`

`{`
`    "cmd": "gmsg",`
`    "val": "Hello, world!"`
`}`

5. The client specifies a username using the "setid" command.

`{`
`    "cmd": "setid",`
`    "val": "(Username)"`
`}`

6. [**The server and client, as well as all the other clients, can now begin communication.**](https://hackmd.io/G9q1kPqvQT6NrPobjjxSgg?view#Sending-and-Getting-packets)
7. The client can close it's websocket connection to disconnect.


## Uniform Packet Layout (UPL)
Ever since CloudLink 0.1.6, a feature called UPL (Uniform Packet Layout) was introduced to make life easier for developers. 

Before UPL, you had to stringify JSON if you had nested JSON because of the limitations of Scratch. However, starting with 0.1.7, UPL has been improved so that anyone with basic knowledge of JSON and websockets can interface with a CloudLink server.

The basic specifications of CloudLink UPL are as follows:

1. There must be a command parameter.
2. There must be a value input/output parameter.
3. If needed, there must be an ID to get an Origin from.
4. If other parameters are specified, they must be compatible with it's respective command.
5. Other parameters that are not needed will be ignored.

### Packet limitations and restrictions
Some things to note:

1. `val` cannot be larger than 1000 Characters (1KB) in size. Packets with `val` larger than 1KB will be rejected by the server. If a packet specifies `name`, it must not be larger than 100 characters.
2. Attempting to spoof the packet `id` or `origin` will likely end in being overridden by the server.
3. The server has been designed to catch all possible errors/exceptions and will return a code under typical networking conditions.

## Sending and Getting packets
As part of CloudLink's UPL (Uniform Packet Layout), sending packets is as simple as formatting some JSON to the following:

`{`
`"cmd": "(Command)", `
`"val": (Payload), `
`"id": "(Username)"`
`}`

This command will return as the following on the other end *(if it's a private data command)*:

`{`
`"cmd": "(Command)", `
`"val": (Payload), `
`"origin": "(Packet origin, username)"`
`}`

If the packet is not a private data command, it will not include the "origin" parameter.

`{`
`"cmd": "(Command)", `
`"val": (Payload), `
`}`

**Global stream variable** packets can be sent/will return with the following:
`{`
`"cmd": "gvar", `
`"val": (Payload), `
`"name": "(Variable name)"`
`}`

**Private stream variable** packets can be sent with the following:
`{`
`"cmd": "pvar", `
`"val": (Payload), `
`"name": "(Variable name)"`
`}`

and will return with:
`{`
`"cmd": "pvar", `
`"val": (Payload), `
`"name": "(Variable name)",`
`"origin": "(Packet origin, username)"`
`}`

::::danger
**Because of a security explot found in past versions of CloudLink, specifying the `origin` parameter manually will be overriden by the server.**
::::

## Packet Parameters
| Parameter | Description | Datatypes |
| -------- | -------- | -------- |
| cmd | Packet's command/function. **See Commands Reference (CloudLink Only) for more info.** | String |
| val | Packet/variable data. | String, Int, Float, Dict/JSON |
| id | Packet recipient's username, **dependent on Packet command, see Commands Reference (CloudLink Only) for more info.** | String |
| origin | Packet origin's username, **automatically added by server and cannot be specified manually, depends upon the existence/requirement of the "id" parameter.** | String |
| name | Variable name (**Only used for `gvar` and `pvar`**) | String |

## Commands Reference (CloudLink Only)
| Command (`cmd`) | Description | Takes (sending `val`) | Gives (receiving `val`) | Requires `id` parameter? (Yes -> Returns with `origin` parameter) | Sends from |
| - | - | - | - | - | - |
| `gmsg`  | Global data stream  | Dict/JSON, String, Float, Int.  | Dict/JSON, String, Float, Int. | No | Client or Server |
| `pmsg`  | Private data stream  | Dict/JSON, String, Float, Int.  | Dict/JSON, String, Float, Int. | Yes | Client or Server |
| `gvar`  | Global data stream variable  | Dict/JSON, String, Float, Int.  | Dict/JSON, String, Float, Int. | No | Client or Server |
| `pvar`  | Private data stream variable  | Dict/JSON, String, Float, Int.  | Dict/JSON, String, Float, Int. | Yes | Client or Server |
| `ulist` | Username list | Not applicable | String (Turbowarp, split with semicolons (`;`) to convert to list) or List (Python) | No | Server only |
| `direct` | Direct server-to-client and client-to-server communications, **see Direct COMMs Reference** | Dict/JSON, String, Float, Int. | Dict/JSON, String, Float, Int. | Yes | Client or Server |
| `setid` | Sets username for client and enables private/direct COMMs | String | Not Applicable | Not Applicable | Client only |
| `statuscode` | Returns server state info when any packet is handled (Kinda like [**HTTP status codes**](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)). **See Status Codes for more info.** | Not Applicable | String | Not Applicable | Server only |

## Direct COMMs Reference

::::info
If you have set a callback for `on_packet` in CloudLink Server, it will only listen for packets that uses the `direct` command. This reference below will provide more details on how to use this feature.
::::

### Client-side
#### On connection
When the client connects to the server, it will send (at most 2) packets with the `direct` command. Both will look something like this:

`{`
`"cmd": "direct",`
`"val": {"cmd": "vers", "val": "(Version string, ex. '0.1.7')"}`
`}`

The first packet is the version number reporter. This tells the client what version of CloudLink Server it has. This can be used to check if a client or server is out of date.

`{`
`"cmd": "direct",`
`"val": {"cmd": "motd", "val": "(Message-Of-The-Day, ex. 'Hello, world!')"}`
`}`

The second packet will return the Message-Of-The-Day (if the server admin chooses to enable it). This is just for fun, and does nothing important.

#### Custom commands
This feature allows you to use custom command handlers in CloudLink server. This assumes you know what you're doing.

`{`
`"cmd": "direct",`
`"val": {"cmd": "(CUSTOM COMMAND)", "val": (PAYLOAD)}`
`}`

The second packet will return the Message-Of-The-Day (if the server admin chooses to enable it). This is just for fun, and does nothing important.

#### Specifying Client Type
Clients need to specify it's type. This helps with managing packets to help prevent hiccups. When the CloudLink Scratch Client connects, it will send over this JSON to the server:

`{`
`"cmd": "direct",`
`"val": {"cmd": "type", "val": "scratch"}`
`}`

...which tells the server that it will need to stringfify any nested JSON it finds. As for the Python client, it will send over:

`{`
`"cmd": "direct",`
`"val": {"cmd": "type", "val": "py"}`
`}`

...which tells the server that it doesn't need to stringfify any nested JSON it finds.

If you use CloudLink In a Browser, it must send over the following:

`{`
`"cmd": "direct",`
`"val": {"cmd": "type", "val": "js"}`
`}`

...which also tells the server that it doesn't need to stringfify any nested JSON it finds.

::::warning
You can specify a custom client type by simply changing the nested `val`'s value. But if you use a custom client type, **be warned that it will assume that your client can interpret nested JSON without stringification. Scratch cannot process nested JSON well, so this feature is to prevent hiccupps.**
::::

#### Sending data directly to CloudLink Server
You can send custom data directly to the server using the following JSON:

`{`
`"cmd": "direct",`
`"val": (Payload)`
`}`

and you can write custom commands with this feature.

### Server-side
When a client sends a packet with the `direct` command, it will return the following output to the `on_packet` callback function:

`{`
`"val": (Payload),`
`"origin": (Packet origin's username or dict. memory object)`
`}`

You can use this feature to write custom command handlers to further expand CloudLink's functionality.

For example, you can write a custom command for `ducks`.
`{`
`"val": {"cmd": "ducks", "val": "quack"},`
`"origin": (Packet origin's username or dict. memory object)`
`}`

from there, you can simply read back the values of `on_packet` and it will return with:

`{`
`"cmd": "ducks",`
`"val": "quack",`
`"origin": (Packet origin's username or dict. memory object)`
`}`

## Status Codes
::::info
This reference will only be for the `statuscode` command. This table will provide more details on the state of the CloudLink Server.
::::

### Status Code Formatting
`(Type):(Code) | (Description)`

#### Formatting info
| Type | Code | Description |
| -------- | -------- | -------- |
| Letter (`E` for Error, `I` for Info)| 3-Digit Int. (ex. `123`), describes the info/error in machine-readable format| String, describes the info/error in a human-readable format |

### Codes
| `Code` | `Type` | Description |
| -------- | -------- | -------- |
| `I:000` | `Test` | A test info code for debugging functions. |
| `I:100` | `OK` | The server handed the request correctly. |
| `E:101` | `Syntax` | The packet was not formatted correctly (Bad JSON?) or has missing parameters. |
| `E:102` | `Datatype` | The packet contained a parameter that was not the correct datatype. |
| `E:103` | `IDNotFound` | The client attempted to send/route a packet to an ID that currently doesn't exist. |
| `E:104` | `InternalServerError` | The server suffered an internal error. |
| `E:105` | `Loop` | While handing the request, the server predicted a loop would occur and has stopped the request. |
| `E:106` | `RateLimit` | The server is ratelimiting the request because the request has been used too many times too quicky. |
| `E:107` | `TooLarge` | The packet `val` or `name` is too large to safely use. |
| `E:108` | `BrokenPipe` | The server suffered a broken pipe error internally. |
| `E:109` | `EmptyPacket` | The server got an empty packet, which is basically useless. |
| `E:110` | `IDConflict` | The server refused to set the client's ID as it would conflict with an existing ID. |
| `E:111` | `IDSet` | The server refused to set the client's ID as it has already been set. |
| `I:112` | `TAEnabled` | The server has TA enabled, and is requesting the client to send a key. |
| `E:113` | `TAInvalid` | The server refused the key as it was invalid. |
| `E:114` | `TAExpired` | The server refused the key as it has expired. |
| `E:115` | `Refused` | The server refused to handle the packet. This can happen if the server has blocked your IP address or you attempted to send a packet while not authorized on a Trusted Access server. |
| `E:116` | `IDRequired` | The server cannot process the command without a username set for the client. |
| `E:117` | `TATrustLost` | The server has lost trust in the user. |
| `E:118` | `Invalid` | The command was invalid for the custom commands feature. |
| `E:119` | `Blocked` | The server has blocked the user's IP address and will refuse any packets it receives. |
| `E:120` | `IPRequired` | The server requires the client's IP address to gain trust. |