Constants, refactoring, listen to feedback, fixed deadlock, revived address input
This commit is contained in:
parent
74a7737d05
commit
3912d9f43f
1 changed files with 63 additions and 28 deletions
|
@ -69,7 +69,7 @@ class Fl0wClient(Client):
|
||||||
if self.fl0w.debug:
|
if self.fl0w.debug:
|
||||||
Logging.info("Connection ready!")
|
Logging.info("Connection ready!")
|
||||||
# Enlist on editor channel
|
# Enlist on editor channel
|
||||||
self.send({"channel" : 1, "name" : get_hostname()}, "subscribe")
|
self.send({"channel" : CHANNEL, "name" : get_hostname()}, "subscribe")
|
||||||
# Subscribe to controller channel
|
# Subscribe to controller channel
|
||||||
self.send({"subscribe" : [2]}, "peers")
|
self.send({"subscribe" : [2]}, "peers")
|
||||||
|
|
||||||
|
@ -124,12 +124,10 @@ class Fl0wClient(Client):
|
||||||
handler, id_, data[id_]["name"]))
|
handler, id_, data[id_]["name"]))
|
||||||
action_menu += Entry("Run program",
|
action_menu += Entry("Run program",
|
||||||
"Run a botball program on the controller",
|
"Run a botball program on the controller",
|
||||||
action=partial(lambda handler, id_: handler.pipe(None, "list_programs", id_),
|
action=partial(handler.pipe, None, "list_programs", id_))
|
||||||
handler, id_))
|
|
||||||
action_menu += Entry("Stop programs",
|
action_menu += Entry("Stop programs",
|
||||||
"Stop all currently running botball programs",
|
"Stop all currently running botball programs",
|
||||||
action=partial(lambda handler, id_: handler.pipe(None, "stop_programs", id_),
|
action=partial(handler.pipe, None, "stop_programs", id_))
|
||||||
handler, id_))
|
|
||||||
utilities_menu += Entry("Set Name",
|
utilities_menu += Entry("Set Name",
|
||||||
"Sets the hostname of the selected controller",
|
"Sets the hostname of the selected controller",
|
||||||
action=partial(lambda handler, id_: Input("New Hostname:",
|
action=partial(lambda handler, id_: Input("New Hostname:",
|
||||||
|
@ -139,22 +137,18 @@ class Fl0wClient(Client):
|
||||||
"hostname", id_)).invoke(handler.fl0w.window), handler, id_))
|
"hostname", id_)).invoke(handler.fl0w.window), handler, id_))
|
||||||
utilities_menu += Entry("Processes",
|
utilities_menu += Entry("Processes",
|
||||||
"Lists processes currently running on controller",
|
"Lists processes currently running on controller",
|
||||||
action=partial(lambda handler, id_: handler.pipe(None, "processes", id_),
|
action=partial(handler.pipe, None, "processes", id_))
|
||||||
handler, id_))
|
|
||||||
utilities_menu += Entry("Identify",
|
utilities_menu += Entry("Identify",
|
||||||
"Plays an identification sound on the controller.",
|
"Plays an identification sound on the controller.",
|
||||||
action=partial(lambda handler, id_: handler.pipe(None, "identify", id_),
|
action=partial(handler.pipe, None, "identify", id_))
|
||||||
handler, id_))
|
|
||||||
action_menu += Entry("Utilities", "Stuff you might need but probably won't",
|
action_menu += Entry("Utilities", "Stuff you might need but probably won't",
|
||||||
sub_menu=utilities_menu)
|
sub_menu=utilities_menu)
|
||||||
power_menu += Entry("Shutdown",
|
power_menu += Entry("Shutdown",
|
||||||
"Shutdown the controller",
|
"Shutdown the controller",
|
||||||
action=partial(lambda handler, id_: handler.pipe(None, "shutdown", id_),
|
action=partial(handler.pipe, None, "shutdown", id_))
|
||||||
handler, id_))
|
|
||||||
power_menu += Entry("Reboot",
|
power_menu += Entry("Reboot",
|
||||||
"Reboot the controller",
|
"Reboot the controller",
|
||||||
action=partial(lambda handler, id_: handler.pipe(None, "reboot", id_),
|
action=partial(handler.pipe, None, "reboot", id_))
|
||||||
handler, id_))
|
|
||||||
action_menu += Entry("Power", "Power related actions", sub_menu=power_menu)
|
action_menu += Entry("Power", "Power related actions", sub_menu=power_menu)
|
||||||
action_menu.back = handler.fl0w.controller_menu
|
action_menu.back = handler.fl0w.controller_menu
|
||||||
handler.fl0w.controller_menu += Entry(data[id_]["name"], id_, sub_menu=action_menu,
|
handler.fl0w.controller_menu += Entry(data[id_]["name"], id_, sub_menu=action_menu,
|
||||||
|
@ -197,11 +191,27 @@ class Fl0wClient(Client):
|
||||||
handler.pipe(program, "run_program", id_)
|
handler.pipe(program, "run_program", id_)
|
||||||
|
|
||||||
|
|
||||||
|
class RunProgram(Pipe):
|
||||||
|
PROGRAM_NOT_FOUND = 1
|
||||||
|
|
||||||
|
def run(self, data, peer, handler):
|
||||||
|
if data == self.__class__.PROGRAM_NOT_FOUND:
|
||||||
|
sublime.error_message("Program not found.")
|
||||||
|
|
||||||
|
|
||||||
|
class StopPrograms(Pipe):
|
||||||
|
NO_PROGRAMS_RUNNING = 1
|
||||||
|
|
||||||
|
def run(self, data, peer, handler):
|
||||||
|
if data == self.__class__.NO_PROGRAMS_RUNNING:
|
||||||
|
sublime.error_message("No programs running.")
|
||||||
|
|
||||||
|
|
||||||
class StdStream(Pipe):
|
class StdStream(Pipe):
|
||||||
def start(self, handler):
|
def start(self, handler):
|
||||||
self.output_panels = {}
|
self.output_panels = {}
|
||||||
|
|
||||||
self.lock = threading.Lock()
|
self.lock = threading.RLock()
|
||||||
self.buffer = {}
|
self.buffer = {}
|
||||||
|
|
||||||
self.handler = None
|
self.handler = None
|
||||||
|
@ -235,17 +245,25 @@ class Fl0wClient(Client):
|
||||||
self.output_panels[peer] = self.create_output_panel(handler.fl0w.window, peer)
|
self.output_panels[peer] = self.create_output_panel(handler.fl0w.window, peer)
|
||||||
self.buffer[peer].append(data)
|
self.buffer[peer].append(data)
|
||||||
self.lock.release()
|
self.lock.release()
|
||||||
"""
|
# Meta info comes in so infrequently that the conditional logic would
|
||||||
|
# slow down the regular output streaming
|
||||||
elif type(data) is dict:
|
elif type(data) is dict:
|
||||||
# Bad solution, should instead be treated seperately
|
|
||||||
# while still being timed correctly.
|
|
||||||
meta_text = ""
|
meta_text = ""
|
||||||
if "exit_code" in data:
|
if "exit_code" in data:
|
||||||
meta_text += "Program finished with exit code: %d\n" % data["exit_code"]
|
meta_text += "Program finished with exit code: %d\n" % data["exit_code"]
|
||||||
self.lock.acquire()
|
self.lock.acquire()
|
||||||
self.buffer.append(meta_text)
|
# try/except is faster than an explicit if as long as the
|
||||||
self.lock.release()
|
# condition is not met
|
||||||
"""
|
# function call is also slower
|
||||||
|
try:
|
||||||
|
self.buffer[peer].append(meta_text)
|
||||||
|
except KeyError:
|
||||||
|
self.buffer[peer] = []
|
||||||
|
self.create_output_panel(handler.fl0w.window, peer)
|
||||||
|
self.output_panels[peer] = self.create_output_panel(handler.fl0w.window, peer)
|
||||||
|
self.buffer[peer].append(meta_text)
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def write_to_panel(self, text, peer):
|
def write_to_panel(self, text, peer):
|
||||||
|
@ -283,6 +301,7 @@ class Fl0wClient(Client):
|
||||||
|
|
||||||
class Fl0w:
|
class Fl0w:
|
||||||
def __init__(self, window, debug=False):
|
def __init__(self, window, debug=False):
|
||||||
|
self.settings = sublime.load_settings("fl0w.sublime-settings")
|
||||||
self.window = window
|
self.window = window
|
||||||
self.folder = window.folders()[0]
|
self.folder = window.folders()[0]
|
||||||
if self.folder != "/":
|
if self.folder != "/":
|
||||||
|
@ -300,7 +319,9 @@ class Fl0w:
|
||||||
|
|
||||||
self.start_menu = Menu()
|
self.start_menu = Menu()
|
||||||
self.start_menu += Entry("Connect", "Connect to a fl0w server",
|
self.start_menu += Entry("Connect", "Connect to a fl0w server",
|
||||||
action=self.invoke_connect)
|
action=partial(Input("Address:Port (auto-connect nyi)",
|
||||||
|
initial_text=self.settings.get("address", "127.0.0.1:3077"),
|
||||||
|
on_done=self.invoke_connect).invoke, self.window))
|
||||||
self.start_menu += Entry("About", "Information about fl0w",
|
self.start_menu += Entry("About", "Information about fl0w",
|
||||||
action=self.invoke_about)
|
action=self.invoke_about)
|
||||||
|
|
||||||
|
@ -385,6 +406,9 @@ class Fl0w:
|
||||||
# Could be simplified because only one view can be active at any time.
|
# Could be simplified because only one view can be active at any time.
|
||||||
# This would definetly lead to some major performace improvements on
|
# This would definetly lead to some major performace improvements on
|
||||||
# view switching and less unnecessary unsubscribes.
|
# view switching and less unnecessary unsubscribes.
|
||||||
|
|
||||||
|
# On the other hand it might be a good idea to leave it in and provide
|
||||||
|
# an option to disable aggressive unsubscribes
|
||||||
@property
|
@property
|
||||||
def combined_subscriptions(self):
|
def combined_subscriptions(self):
|
||||||
return self._combined_subscriptions
|
return self._combined_subscriptions
|
||||||
|
@ -411,9 +435,18 @@ class Fl0w:
|
||||||
|
|
||||||
def unsubscribe(self, sensor_phantom):
|
def unsubscribe(self, sensor_phantom):
|
||||||
if sensor_phantom in self.subscriptions:
|
if sensor_phantom in self.subscriptions:
|
||||||
self.subscriptions_lock.acquire()
|
"""
|
||||||
|
print("Lock will be aquired.")
|
||||||
|
self.subscriptions_lock.acquire()
|
||||||
|
print("Lock was aquired.")
|
||||||
del self.subscriptions[sensor_phantom]
|
del self.subscriptions[sensor_phantom]
|
||||||
|
print("Lock will be released.")
|
||||||
self.subscriptions_lock.release()
|
self.subscriptions_lock.release()
|
||||||
|
print("Lock was released.")
|
||||||
|
"""
|
||||||
|
# Temporary solution, locking caused sublime to freeze
|
||||||
|
# Could cause problems if lots (> 100) views are open.
|
||||||
|
self.subscriptions[sensor_phantom] = {"analog" : [], "digital" : []}
|
||||||
self.make_subscriptions()
|
self.make_subscriptions()
|
||||||
|
|
||||||
|
|
||||||
|
@ -456,26 +489,28 @@ class Fl0w:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def connect(self, connect_details):
|
def connect(self, address):
|
||||||
try:
|
try:
|
||||||
self.ws = Fl0wClient('ws://%s' % connect_details)
|
self.ws = Fl0wClient(address)
|
||||||
self.ws.setup({"info" : Fl0wClient.Info(), "peers" : Fl0wClient.Peers(),
|
self.ws.setup({"info" : Fl0wClient.Info(), "peers" : Fl0wClient.Peers(),
|
||||||
"processes" : Fl0wClient.Processes(),
|
"processes" : Fl0wClient.Processes(),
|
||||||
"list_programs" : Fl0wClient.ListPrograms(), "sensor" : Fl0wClient.Sensor(),
|
"list_programs" : Fl0wClient.ListPrograms(), "sensor" : Fl0wClient.Sensor(),
|
||||||
"std_stream" : Fl0wClient.StdStream()},
|
"std_stream" : Fl0wClient.StdStream(), "run_program" : Fl0wClient.RunProgram(),
|
||||||
|
"stop_programs" : Fl0wClient.StopPrograms()},
|
||||||
self, debug=True)
|
self, debug=True)
|
||||||
self.ws.connect()
|
self.ws.connect()
|
||||||
sublime.set_timeout_async(self.ws.run_forever, 0)
|
sublime.set_timeout_async(self.ws.run_forever, 0)
|
||||||
set_status("Connection opened '%s'" % self.folder, self.window)
|
set_status("Connection opened '%s'" % self.folder, self.window)
|
||||||
self.connected = True
|
self.connected = True
|
||||||
|
self.settings.set("address", address)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
sublime.error_message("Error during connection creation:\n %s" % str(e))
|
sublime.error_message("Error during connection creation:\n %s" % str(e))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def invoke_connect(self):
|
def invoke_connect(self, address):
|
||||||
# Will be removed once autoconnect works
|
# Will be removed once autoconnect works
|
||||||
self.connect("127.0.0.1:3077")
|
self.connect("ws://%s" % address)
|
||||||
|
|
||||||
|
|
||||||
def invoke_disconnect(self):
|
def invoke_disconnect(self):
|
||||||
|
|
Reference in a new issue