-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* New: Added CL4 client mode. * New: Added client-example.py * Change: Renamed example.py to server-example.py * Enhancement: Code restructure. Server and client modes are now in separate modules. * Enhancement: Optimized callback binding system. * Enhancement: Optimized built-in command loading system. * Enhancement: Guard cases are used (where applicable) as an effort to improve code readability. * Bugfix: Fixed a bug that would sometimes have duplicate user IDs in a room. * Reversion: Modified websocket server will return to using a counter-based ID system. I've been able to get the existing size-based system to bug out from time to time.
- Loading branch information
MikeDEV
committed
Sep 10, 2022
1 parent
555a7ec
commit ce61b59
Showing
18 changed files
with
1,065 additions
and
313 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
from cloudlink import Cloudlink | ||
|
||
class demoCallbacksClient: | ||
""" | ||
demoCallbacksClient | ||
This is an example of Cloudlink's callback system. | ||
""" | ||
|
||
def __init__(self, cloudlink): | ||
# To use callbacks, you will need to initialize your callbacks class with Cloudlink. This is required. | ||
self.cloudlink = cloudlink | ||
|
||
# Below are templates for binding generic callbacks. | ||
|
||
def on_packet(self, message): # Called when any packet is received, regardless of packet command. | ||
print("on_packet fired!") | ||
|
||
def on_connect(self): # Called when the client is connected to the server. | ||
print("on_connect fired!") | ||
self.cloudlink.sendGlobalMessage("this is a test") | ||
self.cloudlink.setUsername("test") | ||
|
||
def on_close(self, close_status_code, close_msg): # Called when the client is disconnected from the server. | ||
print("on_close fired!") | ||
|
||
def on_error(self, error): # Called when the client encounters an exception. | ||
print("on_error fired!") | ||
|
||
# Below are templates for binding command-specific callbacks. | ||
|
||
def on_direct(self, message:any): # Called when a packet is received with the direct command. | ||
print("on_direct fired!") | ||
#pass | ||
|
||
def on_version(self, version:str): # Called when a packet is received with the server_version command. | ||
print("on_version fired!") | ||
# pass | ||
|
||
def on_motd(self, motd:str): # Called when a packet is received with the motd command. | ||
print("on_motd fired!") | ||
# pass | ||
|
||
def on_ip(self, ip:str): # Called when a packet is received with the client_ip command. | ||
print("on_ip fired!") | ||
# pass | ||
|
||
def on_ulist(self, ulist:list): # Called when a packet is received with the ulist command. | ||
print("on_ulist fired!") | ||
# pass | ||
|
||
def on_statuscode(self, code:str): # Called when a packet is received with the statuscode command. | ||
print("on_statuscode fired!") | ||
# pass | ||
|
||
def on_gmsg(self, message:str): # Called when a packet is received with the gmsg command. | ||
print("on_gmsg fired!") | ||
# pass | ||
|
||
def on_gvar(self, var_name:str, var_value:any): # Called when a packet is received with the gvar command. | ||
print("on_gvar fired!") | ||
# pass | ||
|
||
def on_pvar(self, var_name:str, var_value:any, origin:any): # Called when a packet is received with the pvar command. | ||
print("on_pvar fired!") | ||
# pass | ||
|
||
def on_pmsg(self, value:str, origin:any): # Called when a packet is received with the pmsg command. | ||
print("on_pmsg fired!") | ||
# pass | ||
|
||
def on_ping(self, value:str, origin:any): # Called when the client is being pinged by another client (It will automatically respond to the ping, this is just used for diagnostics). | ||
print("on_ping fired!") | ||
# pass | ||
|
||
if __name__ == "__main__": | ||
# Initialize Cloudlink. You will only need to initialize one instance of the main cloudlink module. | ||
cl = Cloudlink() | ||
|
||
# Create a new client object. This supports initializing many clients at once. | ||
client = cl.client(logs=True) | ||
|
||
# Create demo callbacks. You can only initialize callbacks after you have initialized a cloudlink client object. | ||
dummy = demoCallbacksClient(client) | ||
|
||
# Bind demo callbacks | ||
client.callback(client.on_packet, dummy.on_packet) | ||
client.callback(client.on_connect, dummy.on_connect) | ||
client.callback(client.on_close, dummy.on_close) | ||
client.callback(client.on_error, dummy.on_error) | ||
|
||
# Bind template callbacks | ||
client.callback(client.on_direct, dummy.on_direct) | ||
client.callback(client.on_version, dummy.on_version) | ||
client.callback(client.on_motd, dummy.on_motd) | ||
client.callback(client.on_ip, dummy.on_ip) | ||
client.callback(client.on_ulist, dummy.on_ulist) | ||
client.callback(client.on_statuscode, dummy.on_statuscode) | ||
client.callback(client.on_gmsg, dummy.on_gmsg) | ||
client.callback(client.on_gvar, dummy.on_gvar) | ||
client.callback(client.on_pvar, dummy.on_pvar) | ||
client.callback(client.on_pmsg, dummy.on_pmsg) | ||
client.callback(client.on_ping, dummy.on_ping) | ||
|
||
# Command disabler. Simply pass a list of strings containing CLPv4 commands to ignore. | ||
#client.disableCommands(["gmsg"]) | ||
|
||
# Connect to the server and run the client. | ||
client.run(ip="ws://127.0.0.1:3000/") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
from .cloudlink import Cloudlink | ||
from .cloudlink import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .client import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import websocket as WebsocketClient | ||
from .clientRootHandlers import clientRootHandlers | ||
from .clientInternalHandlers import clientInternalHandlers | ||
|
||
class client: | ||
def __init__(self, parentCl, enable_logs=True): | ||
# Read the CloudLink version from the parent class | ||
self.version = parentCl.version | ||
|
||
# Init the client | ||
self.motd_msg = "" | ||
self.sever_version = "" | ||
self.ip_address = "" | ||
self.motd_msg = "" | ||
self.userlist = {} | ||
self.myClientObject = {} | ||
|
||
self.linkStatus = 0 | ||
self.failedToConnect = False | ||
self.connectionLost = False | ||
self.connected = False | ||
|
||
# Init modules | ||
self.supporter = parentCl.supporter(self, enable_logs, 2) | ||
self.clientRootHandlers = clientRootHandlers(self) | ||
self.clientInternalHandlers = clientInternalHandlers(self) | ||
|
||
# Load built-in commands (automatically generates attributes for callbacks) | ||
self.builtInCommands = [] | ||
self.customCommands = [] | ||
self.disabledCommands = [] | ||
self.usercallbacks = {} | ||
self.supporter.loadBuiltinCommands(self.clientInternalHandlers) | ||
|
||
# Create API | ||
self.loadCustomCommands = self.supporter.loadCustomCommands | ||
self.disableCommands = self.supporter.disableCommands | ||
self.sendPacket = self.supporter.sendPacket | ||
self.sendCode = self.supporter.sendCode | ||
self.log = self.supporter.log | ||
self.callback = self.supporter.callback | ||
|
||
# Create default callbacks | ||
self.usercallbacks = {} | ||
self.on_packet = self.clientRootHandlers.on_packet | ||
self.on_connect = self.clientRootHandlers.on_connect | ||
self.on_close = self.clientRootHandlers.on_close | ||
self.on_error = self.clientRootHandlers.on_error | ||
|
||
# Callbacks for command-specific events | ||
self.on_direct = self.clientInternalHandlers.direct | ||
self.on_version = self.clientInternalHandlers.server_version | ||
self.on_motd = self.clientInternalHandlers.motd | ||
self.on_ip = self.clientInternalHandlers.client_ip | ||
self.on_ulist = self.clientInternalHandlers.ulist | ||
self.on_statuscode = self.clientInternalHandlers.statuscode | ||
self.on_gmsg = self.clientInternalHandlers.gmsg | ||
self.on_gvar = self.clientInternalHandlers.gvar | ||
self.on_pvar = self.clientInternalHandlers.pvar | ||
self.on_pmsg = self.clientInternalHandlers.pmsg | ||
self.on_ping = self.clientInternalHandlers.ping | ||
|
||
self.log("Cloudlink client initialized!") | ||
|
||
def run(self, ip="ws://127.0.0.1:3000/"): | ||
# Initialize the Websocket client | ||
self.log("Cloudlink client starting up now...") | ||
self.wss = WebsocketClient.WebSocketApp( | ||
ip, | ||
on_message = self.clientRootHandlers.on_packet, | ||
on_error = self.clientRootHandlers.on_error, | ||
on_open = self.clientRootHandlers.on_connect, | ||
on_close = self.clientRootHandlers.on_close | ||
) | ||
|
||
# Run the CloudLink client | ||
self.linkStatus = 1 | ||
self.wss.run_forever() | ||
self.log("Cloudlink client exiting...") | ||
|
||
def stop(self): | ||
if self.connected: | ||
self.linkStatus = 3 | ||
self.log("Cloudlink client disconnecting...") | ||
self.wss.close() | ||
|
||
# Client API | ||
|
||
def setUsername(self, username:str): | ||
if self.connected: | ||
msg = {"cmd": "setid", "val": username, "listener": "username_set"} | ||
self.cloudlink.sendPacket(msg) | ||
|
||
def getUserlist(self, listener:str = None): | ||
if self.connected: | ||
msg = {"cmd": "ulist", "val": ""} | ||
if listener: | ||
msg["listener"] = listener | ||
self.cloudlink.sendPacket(msg) | ||
|
||
def linkToRooms(self, rooms:list = ["default"], listener:str = None): | ||
if self.connected: | ||
msg = {"cmd": "link", "val": rooms} | ||
if listener: | ||
msg["listener"] = listener | ||
self.cloudlink.sendPacket(msg) | ||
|
||
def unlinkFromRooms(self, listener:str = None): | ||
if self.connected: | ||
msg = {"cmd": "unlink", "val": ""} | ||
if listener: | ||
msg["listener"] = listener | ||
self.cloudlink.sendPacket(msg) | ||
|
||
def sendDirect(self, message:str, username:str = None, listener:str = None): | ||
if self.connected: | ||
msg = {"cmd": "direct", "val": message} | ||
if listener: | ||
msg["listener"] = listener | ||
if username: | ||
msg["id"] = username | ||
self.cloudlink.sendPacket(msg) | ||
|
||
def sendCustom(self, cmd:str, message:str, username:str = None, listener:str = None): | ||
if self.connected: | ||
msg = {"cmd": cmd, "val": message} | ||
if listener: | ||
msg["listener"] = listener | ||
if username: | ||
msg["id"] = username | ||
self.cloudlink.sendPacket(msg) | ||
|
||
def sendPing(self, dummy_payload:str = "", username:str = None, listener:str = None): | ||
if self.connected: | ||
msg = {"cmd": "ping", "val": dummy_payload} | ||
if listener: | ||
msg["listener"] = listener | ||
if username: | ||
msg["id"] = username | ||
self.cloudlink.sendPacket(msg) | ||
|
||
def sendGlobalMessage(self, message:str, listener:str = None): | ||
if self.connected: | ||
msg = {"cmd": "gmsg", "val": message} | ||
if listener: | ||
msg["listener"] = listener | ||
self.cloudlink.sendPacket(msg) | ||
|
||
def sendPrivateMessage(self, message:str, username:str = "", listener:str = None): | ||
if self.connected: | ||
msg = {"cmd": "pmsg", "val": message, "id": username} | ||
if listener: | ||
msg["listener"] = listener | ||
self.cloudlink.sendPacket(msg) | ||
|
||
def sendGlobalVariable(self, var_name:str, var_value:str, listener:str = None): | ||
if self.connected: | ||
msg = {"cmd": "gvar", "val": var_value, "name": var_name} | ||
if listener: | ||
msg["listener"] = listener | ||
self.cloudlink.sendPacket(msg) | ||
|
||
def sendPrivateVariable(self, var_name:str, var_value:str, username:str = "", listener:str = None): | ||
if self.connected: | ||
msg = {"cmd": "pvar", "val": var_value, "name": var_name, "id": username} | ||
if listener: | ||
msg["listener"] = listener | ||
self.cloudlink.sendPacket(msg) |
Oops, something went wrong.