Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jbflow/feature/tcp socket #119

Open
wants to merge 25 commits into
base: websockets
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d9d5b47
utility scripts for copying remote script and reading lives logs
jbflow May 21, 2024
9c01912
added threaded TCP websocket class Socket
jbflow May 21, 2024
aa37b1a
incorporate socket logic into main file with queue for messages
jbflow May 21, 2024
e95149b
add react websocket hook and dependencies
jbflow May 21, 2024
03a55fc
message parsing
jbflow May 21, 2024
dee9906
remove chunking from send method
jbflow May 28, 2024
fbea3c4
revert AbletonJS to midi-script
jbflow May 28, 2024
dc9571e
added seperate UDP/TCP socket
jbflow May 28, 2024
2b1577a
add socket disconnect logic
jbflow May 28, 2024
72f4687
refactored to base class for UDP/TCP approach
jbflow May 28, 2024
fd81481
create socket interface
jbflow May 29, 2024
0e7c0b1
set socket flag to UDP to revert functionality
jbflow May 29, 2024
dd88e6b
removed not needed scripts
jbflow May 29, 2024
8570d84
removed react hook and dependencies - can add later as examples
jbflow May 29, 2024
d1f465b
handle shutdown logic
jbflow May 29, 2024
68f1fe8
tcp socket shutdown
jbflow May 29, 2024
e67f9da
remove c_instance from tcp and make attrs private
jbflow May 29, 2024
c207f44
change vars in socket send method
jbflow May 29, 2024
338a7ca
tcp socket in port range 39031 - 39038
jbflow May 29, 2024
fec8822
moved socket classes to own dir
jbflow Jun 26, 2024
92b537c
implement websocket message handler from interface
jbflow Jun 26, 2024
0bc69ea
implemented handshake handler class
jbflow Jun 26, 2024
0372444
update tcp socket class
jbflow Jun 26, 2024
abc0003
implement TCP socket handlers into main class
jbflow Jun 26, 2024
afae9c6
reformat files
jbflow Jun 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 25 additions & 50 deletions midi-script/AbletonJS.py → midi-script/AbletonJSBase.py
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
from __future__ import absolute_import
import time


from .version import version
from .Config import DEBUG, FAST_POLLING
from .Config import DEBUG
from .Logging import logger
from .Socket import Socket

from .Interface import Interface
from .Application import Application
from .ApplicationView import ApplicationView
Expand All @@ -29,16 +26,12 @@
import Live


class AbletonJS(ControlSurface):
class AbletonJSBase(ControlSurface):
def __init__(self, c_instance):
super(AbletonJS, self).__init__(c_instance)
logger.info("Starting AbletonJS " + version + "...")

super(AbletonJSBase, self).__init__(c_instance)
logger.info(f"Starting AbletonJS {version}...")
self._socket = None
self.tracked_midi = set()

Socket.set_message(self.show_message)
self.socket = Socket(self.command_handler)

self.handlers = {
"application": Application(c_instance, self.socket, self.application()),
"application-view": ApplicationView(c_instance, self.socket, self.application()),
Expand All @@ -58,33 +51,16 @@ def __init__(self, c_instance):
"clip_slot": ClipSlot(c_instance, self.socket),
"clip": Clip(c_instance, self.socket),
}

@property
def socket(self):
return self._socket

self._last_tick = time.time() * 1000
self.tick()

if FAST_POLLING:
self.recv_loop = Live.Base.Timer(
callback=self.socket.process, interval=10, repeat=True)

self.recv_loop.start()

def tick(self):
tick_time = time.time() * 1000

if tick_time - self._last_tick > 200:
logger.warning("UDP tick is lagging, delta: " +
str(round(tick_time - self._last_tick)) + "ms")

self._last_tick = tick_time
self.socket.process()

process_time = time.time() * 1000

if process_time - tick_time > 100:
logger.warning("UDP processing is taking long, delta: " +
str(round(tick_time - process_time)) + "ms")

self.schedule_message(1, self.tick)
@socket.setter
def socket(self, value):
self._socket = value
for handler in self.handlers.values():
handler.socket = value

def build_midi_map(self, midi_map_handle):
script_handle = self._c_instance.handle()
Expand All @@ -99,15 +75,7 @@ def build_midi_map(self, midi_map_handle):
def receive_midi(self, midi_bytes):
self.handlers["midi"].send_midi(midi_bytes)

def disconnect(self):
logger.info("Disconnecting")
if FAST_POLLING:
self.recv_loop.stop()
self.socket.send("disconnect")
self.socket.shutdown()
Interface.listeners.clear()
super(AbletonJS, self).disconnect()


def command_handler(self, payload):
namespace = payload["ns"]

Expand All @@ -119,5 +87,12 @@ def command_handler(self, payload):
handler = self.handlers[namespace]
handler.handle(payload)
else:
self.socket.send("error", "No handler for namespace " +
str(namespace), payload["uuid"])
self.socket.send(f"error - No handler for namespace: {namespace}, Payload UUID: {payload['uuid']}")

def disconnect(self):
logger.info("Disconnecting")
self.socket.send("disconnect")
self.socket.shutdown()
Interface.listeners.clear()
super(AbletonJSBase, self).disconnect()

41 changes: 41 additions & 0 deletions midi-script/AbletonJSTCP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from __future__ import absolute_import
import queue
from .version import version
from .Logging import logger
from .Socket.TCPSocket import Socket, WebsocketMessageHandler, WebsocketHandshakeHandler
from .AbletonJSBase import AbletonJSBase
import Live


class AbletonJSTCP(AbletonJSBase):
def __init__(self, c_instance):
super(AbletonJSTCP, self).__init__(c_instance)
self.message_queue = queue.Queue()
self.socket_handshake_handler = WebsocketHandshakeHandler()
self.socket_message_handler = WebsocketHandshakeHandler()
self.socket = Socket(self.socket_callback, self.socket_handshake_handler, self.socket_websocket_handler)
self.socket.start()
self.check_queue = Live.Base.Timer(callback=self.process_queue, interval=20, repeat=True)
self.check_queue.start()


def socket_callback(self, payload):
self.message_queue.put(payload)

def process_queue(self):
if not self.message_queue.empty():
try:
payload = self.message_queue.get()
logger.debug(f"Payload: {payload}")
self.command_handler(payload)
except Exception as e:
logger.error(f'Error processing queue: {e}')


def disconnect(self):
self.check_queue.stop()
self.message_queue.clear()
self.message_queue = None
super(AbletonJSTCP, self).disconnect()


48 changes: 48 additions & 0 deletions midi-script/AbletonJSUDP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from __future__ import absolute_import
import time
from .Config import FAST_POLLING
from .Logging import logger
from .Socket.UDPSocket import Socket
from .Interface import Interface

from .AbletonJSBase import AbletonJSBase
import Live


class AbletonJSUDP(AbletonJSBase):
def __init__(self, c_instance):
super(AbletonJSUDP, self).__init__(c_instance)
Socket.set_message(self.show_message)
self.socket = Socket(self.command_handler)
self._last_tick = time.time() * 1000
self.tick()
if FAST_POLLING:
self.recv_loop = Live.Base.Timer(
callback=self.socket.process, interval=10, repeat=True)

self.recv_loop.start()

def tick(self):
tick_time = time.time() * 1000

if tick_time - self._last_tick > 200:
logger.warning("UDP tick is lagging, delta: " +
str(round(tick_time - self._last_tick)) + "ms")

self._last_tick = tick_time
self.socket.process()

process_time = time.time() * 1000

if process_time - tick_time > 100:
logger.warning("UDP processing is taking long, delta: " +
str(round(tick_time - process_time)) + "ms")
self.schedule_message(1, self.tick)



def disconnect(self):
if FAST_POLLING:
self.recv_loop.stop()
super(AbletonJSUDP, self).disconnect()

2 changes: 2 additions & 0 deletions midi-script/Internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ def get_version(self, ns):
def set_client_port(self, nsid, port):
self.socket.set_client_port(port)
return True


24 changes: 24 additions & 0 deletions midi-script/Socket/Interfaces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class MessageHandlerInterface:
def receive_message(self, connection):
raise NotImplementedError("receive_message method must be implemented by MassageHandler subclasses")

def send_message(self, connection, message):
raise NotImplementedError("send_message method must be implemented by MessageHandler subclasses")

class HandshakeHandlerInterface:
def parse_headers(self, request):
raise NotImplementedError("parse_headers method must be implemented by HandshakeHandler subclasses")

def generate_accept_key(self, websocket_key):
raise NotImplementedError("generate_accept_key method should be implemented by HandshakeHandler subclasses")

def perform_handshake(self, connection):
raise NotImplementedError("perform_handshake method must be implemented by HandshakeHandler subclasses")

class SocketInterface:
def send(self, name, obj=None, uuid=None):
raise NotImplementedError("send method must be implemented by socket subclasses")

def shutdown(self):
raise NotImplementedError("shutdown method must be implemented by socket subclasses")

Loading