MikeDEV
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
1
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# 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   ::::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. |

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully