Skip to content

Commit

Permalink
0.1.8.3
Browse files Browse the repository at this point in the history
* 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
Show file tree
Hide file tree
Showing 18 changed files with 1,065 additions and 313 deletions.
109 changes: 109 additions & 0 deletions client-example.py
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/")
2 changes: 1 addition & 1 deletion cloudlink/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .cloudlink import Cloudlink
from .cloudlink import *
1 change: 1 addition & 0 deletions cloudlink/client/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .client import *
168 changes: 168 additions & 0 deletions cloudlink/client/client.py
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)
Loading

0 comments on commit ce61b59

Please sign in to comment.