-
Notifications
You must be signed in to change notification settings - Fork 33
Python Server
Work in progress! This documentation is exclusively for the Python 0.2.0 server.
Below is an example of setting up a barebones server. This implements the CL4 protocol and Scratch cloud variables protocol. When connecting to the server, it will only allow you to connect on the same machine on ws://127.0.0.1:3000
.
You can make the server CL4 exclusive by commenting out all scratch
mentions, or you can make a ready-to-go, self-hosted cloud variable server by commenting out all mentions of clpv4
.
# Import the server
from cloudlink import server
# Import protocols
from cloudlink.server.protocols import clpv4, scratch
# Instantiate the server object
server = server()
# Set logging level
server.logging.basicConfig(
level=server.logging.INFO # See python's logging library for details on logging levels.
)
# Load protocols
clpv4 = clpv4(server)
scratch = scratch(server)
# Start the server!
server.run(ip="127.0.0.1", port=3000)
If you plan on hosting a server for the public, it is recommended to enable SSL for secure websockets. Simply generate an SSL certificate and private key pair using any tool of your choosing (I recommend using Let's Encrypt CertBot), and call upon server.enable_ssl
. Once SSL support is enabled, you will connect to the server using wss://your.server.hostname:port/
. You will no longer be able to connect to the server using insecure websockets.
server.enable_ssl(certfile="cert.pem", keyfile="privkey.pem")
There are various configuration settings you can change.
Integer, Default: -1 (Unlimited).
Set this value to an integer number to limit the maximum number of clients that can connect, regardless of protocol. Leaving the default value, -1, will allow as many clients as (reasonably) possible.
Boolean, Default: True.
If True, the server will warn users if they are resolving multiple clients for a username search.
Boolean, Default: False.
If True, whenever a client sends the handshake command or whenever the client's protocol is identified, the server will send the Message-Of-The-Day from whatever value motd_message is set to.
String, Default: Blank string.
If enable_mod is True, this string will be sent as the server's Message-Of-The-Day.
String, Default: None.
If you use CloudLink behind a tunneling service or reverse proxy, set this value to whatever IP address-fetching request header to resolve valid IP addresses. When set to None, it will utilize the host's incoming network for resolving IP addresses.
Examples include:
x-forwarded-for
cf-connecting-ip
Boolean, Default: True
When True, the server will suppress logging messages relating to the underlying websocket engine, as well as any asyncio-related logging messages. The only messages that will appear in logs will be errors.
CloudLink server comes with support for extending its functionality through decorators and classes. A collection of these various decorator functions are referred to as "extensions" or "plugins".
Adding this chunk of code to your basic server (before calling server.run
) will implement a new command, foo
. To execute this command, connect to the server and send {"cmd": "foo"}
. Each extension to the server must be an asyncio coroutine.
# Example command - client sends { "cmd": "foo" } to the server, this function will execute
@server.on_command(cmd="foo", schema=clpv4.schema)
async def foobar(client, message):
print("Foobar!")
This exception is raised when a client sends an invalid command for a protocol.
@server.on_exception(exception_type=server.exceptions.InvalidCommand, schema=clpv4.schema)
async def invalid_command(client, details):
print(client, "sent an invalid command", details)
This exception is raised when a client sends a disabled command for a protocol.
@server.on_disabled_command(schema=clpv4.schema)
async def disabled_command(client, details):
print(client, "sent a disabled command", details)
This exception is raised when a client sends invalid/malformed JSON.
@server.on_exception(exception_type=server.exceptions.JSONError, schema=clpv4.schema)
async def json_exception(client, details):
print(client, details)
This exception will be raised when a client sends an empty message after their protocol has been identified.
@server.empty_message(exception_type=server.exceptions.EmptyMessage, schema=clpv4.schema)
async def empty_message(client, details):
print(client, details)
This event will fire whenever a client connects, regardless of protocol.
@server.on_connect
async def on_connect(client):
print(client, "Connected!")
This event will fire whenever a client disconnects, regardless of protocol.
@server.on_disconnect
async def on_disconnect(client):
print(client, "Disconnected!")
This event will fire when an error has occurred, regardless of protocol.
@server.on_error
async def on_error(client, errors):
print(client, "encountered an error(s)", errors)
This event will fire when the server identifies a client's protocol. This event will fire only once per connection.
@server.on_protocol_identified(schema=clpv4.schema)
async def protocol_identified(client):
print(client, "is using protocol", clpv4.schema)
This event will execute whenever a client disconnects. This is protocol-specific.
@server.on_protocol_disconnect(schema=clpv4.schema)
async def protocol_disconnect(client):
print(client, "Disconnected...")
You can use this function to send a message to a single client, or a list/set of clients.
- obj- Set of client objects or a single client object.
- message - Dictionary or string. Contains the message to unicast or multicast.
This variant will only send a message to a single client.
- client - A client object.
- message - Dictionary or string. Contains the message to unicast.
This variant will only send a message to a list/set of multiple clients.
- clients - A set of client objects.
- message - Dictionary or string. Contains the message to multicast.
This will send a CloudLink statuscode to a client.
- client - A client object.
- code - Tuple. Specific statuscodes can be obtained by using an attribute of
clpv4.statuscodes
. - details - String (Optional). If provided, it will allow you to provide a client with details on what went wrong, or how to fix an error.
- message - Dictionary (Optional). Provide the
message
argument from a callback to detect listeners. - val - Any (Optional). Adds the
val
key to the statuscode. Use if you need to return info for a specific statuscode (ex. returning a message)
You can use this function to disconnect a single client or a list/set of clients.
- obj - Set of client objects or a single client object.
- code - Integer. Defaults to 1000 (Normal close).
- Reason - String. Defaults to a blank string. Provides a message to the client when the connection is closed.
Creates an origin
value for messages similar to pmsg
, pvar
, or direct
.
- obj - A client object.
If the client object has a username set...
{
"id": String,
"username": String,
"uuid": String
}
Otherwise...
{
"id": String,
"uuid": String
}
In CloudLink, each client is a unique object, and upon connection, each client subscribes to the default
room. Clients may change rooms at any time, but this requires configuration. These functions make this possible. Using these functions, you may implement custom client/room management functionality.
All exceptions are subclasses of clients_manager.exceptions
.
-
ClientDoesNotExist
- This exception is raised when a client object does not exist. -
ClientAlreadyExists
- This exception is raised when attempting to add a client object that is already present. -
ClientUsernameAlreadySet
- This exception is raised when a client attempts to set their friendly username, but it was already set. -
ClientUsernameNotSet
- This exception is raised when a client object has not yet set it's friendly username. -
NoResultsFound
- This exception is raised when there are no results for a client search request. -
ProtocolAlreadySet
- This exception is raised when attempting to change a client's protocol.