Example #1
0
    def __init__(self, exec_path, nodeid, bind_ip, webuiport, comport, masterip=None, masterport=None):
        self.ismaster = True
        self.exec_path = exec_path
        self.nodeid = nodeid
        self.bindip = bind_ip
        self.webuiport = webuiport
        self.comport = comport
        self.masterip = masterip
        self.masterport = masterport
        self.user_appdata_directory = None
        self.started_at = time.time()
        self.last_tick_at = self.started_at
        self.uptime = 0
        self.public_ip = "Not yet known"


        if platform.system() == "Darwin":
            self.user_appdata_directory = os.path.expanduser("~/Library/ServerSync/%s" % (self.nodeid))
        elif platform.system() == "Linux":
            self.user_appdata_directory = os.path.expanduser("~/.config/ServerSync/%s" % (self.nodeid)) # inspired by Google Chrome location
        elif platform.system() == "Windows":
            self.user_appdata_directory = os.path.expanduser("~\\AppData\\Local\\ServerSync\\%s" % (self.nodeid))
        else:
            raise("Platform not supported")

        if masterip is None:
            self.print("Setting up node %s as master\n" % (nodeid))
        else :
            self.ismaster = False
            self.print("Setting up node %s.\n" % (nodeid))
            self.print("  will ask peer list to node at %s:%s\n" % (masterip, masterport))

        self.print("Control panel is on port %s\n" % (webuiport))
        self.print("Listen for other nodes on port %s\n" % (comport))

        # create a directory for the application if not aready exists
        if not os.path.exists(self.user_appdata_directory):
            os.makedirs(self.user_appdata_directory)

        self.updater = Updater()

        #m = multiprocessing.Manager()
        self.q_peerstore_in = multiprocessing.Queue() #m.Queue() #for networked multiprocessing
        self.q_peerstore_out = multiprocessing.Queue()
        self.q_comwebserver_in = multiprocessing.Queue() #m.Queue() #for networked multiprocessing
        self.q_comwebserver_out = multiprocessing.Queue()
        self.q_client_in = multiprocessing.Queue()
        self.q_client_out = multiprocessing.Queue()
        self.q_uiwebserver_in = multiprocessing.Queue()
        self.q_uiwebserver_out = multiprocessing.Queue()
        self.q_logger_in = multiprocessing.Queue()
        self.q_logger_out = multiprocessing.Queue()
        self.q_console_out = multiprocessing.Queue()
        self.peerstore = PeerStore(THREAD_SLEEP_TIME, self.q_peerstore_in, self.q_peerstore_out, "PeerStore", self.user_appdata_directory, self.comport, self.nodeid, self.masterip, self.masterport)
        self.uiwebserver = UIWebServer(THREAD_SLEEP_TIME, self.exec_path, self.bindip, self.q_uiwebserver_in, self.q_uiwebserver_out, self.webuiport, self.nodeid, "UIWebServer")
        self.logger = Logger(THREAD_SLEEP_TIME, self.q_logger_in, self.q_logger_out, self.nodeid, "Logger")
        self.comwebserver = ComWebServer(THREAD_SLEEP_TIME, self.exec_path, self.bindip, self.q_comwebserver_in, self.q_comwebserver_out, self.comport, self.nodeid, "ComWebServer")
        self.client = Client(THREAD_SLEEP_TIME, self.exec_path, self.bindip, self.q_client_in, self.q_client_out, self.nodeid, "Client")
        self.console = Console(self.q_console_out, sys.stdin, sys.stdout, self.nodeid, "Console")


        self.running = False

        self.should_restart = False
Example #2
0
class ServerSync(object):
    def __init__(self, exec_path, nodeid, bind_ip, webuiport, comport, masterip=None, masterport=None):
        self.ismaster = True
        self.exec_path = exec_path
        self.nodeid = nodeid
        self.bindip = bind_ip
        self.webuiport = webuiport
        self.comport = comport
        self.masterip = masterip
        self.masterport = masterport
        self.user_appdata_directory = None
        self.started_at = time.time()
        self.last_tick_at = self.started_at
        self.uptime = 0
        self.public_ip = "Not yet known"


        if platform.system() == "Darwin":
            self.user_appdata_directory = os.path.expanduser("~/Library/ServerSync/%s" % (self.nodeid))
        elif platform.system() == "Linux":
            self.user_appdata_directory = os.path.expanduser("~/.config/ServerSync/%s" % (self.nodeid)) # inspired by Google Chrome location
        elif platform.system() == "Windows":
            self.user_appdata_directory = os.path.expanduser("~\\AppData\\Local\\ServerSync\\%s" % (self.nodeid))
        else:
            raise("Platform not supported")

        if masterip is None:
            self.print("Setting up node %s as master\n" % (nodeid))
        else :
            self.ismaster = False
            self.print("Setting up node %s.\n" % (nodeid))
            self.print("  will ask peer list to node at %s:%s\n" % (masterip, masterport))

        self.print("Control panel is on port %s\n" % (webuiport))
        self.print("Listen for other nodes on port %s\n" % (comport))

        # create a directory for the application if not aready exists
        if not os.path.exists(self.user_appdata_directory):
            os.makedirs(self.user_appdata_directory)

        self.updater = Updater()

        #m = multiprocessing.Manager()
        self.q_peerstore_in = multiprocessing.Queue() #m.Queue() #for networked multiprocessing
        self.q_peerstore_out = multiprocessing.Queue()
        self.q_comwebserver_in = multiprocessing.Queue() #m.Queue() #for networked multiprocessing
        self.q_comwebserver_out = multiprocessing.Queue()
        self.q_client_in = multiprocessing.Queue()
        self.q_client_out = multiprocessing.Queue()
        self.q_uiwebserver_in = multiprocessing.Queue()
        self.q_uiwebserver_out = multiprocessing.Queue()
        self.q_logger_in = multiprocessing.Queue()
        self.q_logger_out = multiprocessing.Queue()
        self.q_console_out = multiprocessing.Queue()
        self.peerstore = PeerStore(THREAD_SLEEP_TIME, self.q_peerstore_in, self.q_peerstore_out, "PeerStore", self.user_appdata_directory, self.comport, self.nodeid, self.masterip, self.masterport)
        self.uiwebserver = UIWebServer(THREAD_SLEEP_TIME, self.exec_path, self.bindip, self.q_uiwebserver_in, self.q_uiwebserver_out, self.webuiport, self.nodeid, "UIWebServer")
        self.logger = Logger(THREAD_SLEEP_TIME, self.q_logger_in, self.q_logger_out, self.nodeid, "Logger")
        self.comwebserver = ComWebServer(THREAD_SLEEP_TIME, self.exec_path, self.bindip, self.q_comwebserver_in, self.q_comwebserver_out, self.comport, self.nodeid, "ComWebServer")
        self.client = Client(THREAD_SLEEP_TIME, self.exec_path, self.bindip, self.q_client_in, self.q_client_out, self.nodeid, "Client")
        self.console = Console(self.q_console_out, sys.stdin, sys.stdout, self.nodeid, "Console")


        self.running = False

        self.should_restart = False

    def start(self):

        # we will fork the subprocesses now so we disable the signal handling for them
        # we will enable it later
        signal.signal(signal.SIGINT, signal.SIG_IGN)


        # start process
        self.comwebserver.start()
        self.uiwebserver.start()
        self.client.start()
        self.logger.start()
        self.peerstore.start()

        # catch CTRL+C
        signal.signal(signal.SIGINT, self.signal_handler)

        # start threads
        self.console.start()


        self.running = True

        self.q_logger_in.put(Message("System", "Logger", "register", ["System"]))

        while(self.running):
            time.sleep(MAIN_SLEEP_TIME)

            m = self.process_queues()

            # each second we send a tick to some of the processes telling them since how manytime we run
            if int(time.time() - self.last_tick_at) >= 1:
                self.last_tick_at = time.time()
                self.uptime = int(time.time() - self.started_at)
                self.q_peerstore_in.put(Message(self.nodeid, "PeerStore", "tick", [self.uptime]))
                self.q_comwebserver_in.put(Message(self.nodeid, "ComWebServer", "tick", [self.uptime]))
                self.q_uiwebserver_in.put(Message(self.nodeid, "UIWebServer", "tick", [self.uptime]))
                self.q_logger_in.put(Message(self.nodeid, "Logger", "tick", [self.uptime]))

            # We send poison pill to threads only if they are not configured to loop based on a sleep time (blocking queues)
            if THREAD_SLEEP_TIME is 0:
                self.poison_pill_queues()



        self.print("Shutdown client and server processes...\n")

        # ask the client and server process to shut down, except if we received a kill signal
        self.print("Wait for gracefull stop\n")
        self.q_client_in.put(Message(self.nodeid, "Client", "kill", []))
        self.q_comwebserver_in.put(Message(self.nodeid, "ComWebServer", "kill", []))
        self.q_uiwebserver_in.put(Message(self.nodeid, "UIWebServer", "kill", []))
        self.q_logger_in.put(Message(self.nodeid, "Logger", "kill", []))
        self.q_peerstore_in.put(Message(self.nodeid, "PeerStore", "kill", []))

        time.sleep(1)


        # read what remains in the queues
        self.process_queues()

        # Wait for the worker to finish
        self.comwebserver.join()
        self.print("ComWebServer joined\n")
        self.uiwebserver.join()
        self.print("UIWebServer joined\n")
        self.logger.join()
        self.print("Logger joined\n")
        self.client.join()
        self.print("Client joined\n")
        self.peerstore.join()
        self.print("PeerStore joined\n")
        self.console.cancel()
        self.print("Console joined\n")

        self.print("Stopped\n")

        return self.should_restart

    def poison_pill_queues(self):
        self.q_comwebserver_in.put(Message(self.nodeid, "ComWebServer", "pill", []))
        self.q_uiwebserver_in.put(Message(self.nodeid, "UIWebServer", "pill", []))
        self.q_logger_in.put(Message(self.nodeid, "Logger", "pill", []))
        self.q_peerstore_in.put(Message(self.nodeid, "PeerStore", "pill", []))

    def process_queues(self):
        q_comwebserver_out_empty = False
        q_client_out_empty = False
        q_uiwebserver_out_empty = False
        q_logger_out_empty = False
        q_peerstore_out_empty = False
        q_console_out_empty = False


        while (not q_comwebserver_out_empty) or (not q_client_out_empty) or (not q_uiwebserver_out_empty) or (not q_logger_out_empty) or (not q_peerstore_out_empty) or (not q_console_out_empty):
            try:
                m = self.q_console_out.get(False)
                self.dispatch_message(m)
            except Exception as e:
                q_console_out_empty = True

            try:
                m = self.q_uiwebserver_out.get(False)
                self.dispatch_message(m)
            except Exception as e:
                q_uiwebserver_out_empty = True

            try:
                m = self.q_logger_out.get(False)
                self.dispatch_message(m)
            except Exception as e:
                q_logger_out_empty = True

            try:
                m = self.q_comwebserver_out.get(False)
                self.dispatch_message(m)
            except Exception as e:
                q_comwebserver_out_empty = True

            try:
                m = self.q_peerstore_out.get(False)
                self.dispatch_message(m)
            except Exception as e:
                q_peerstore_out_empty = True

            try:
                m = self.q_client_out.get(False)
                self.dispatch_message(m)
            except Exception as e:
                q_client_out_empty = True

    def dispatch_message(self, message):
        try:
            #
            # intercept message like exit/quit/restart
            #
            if message.destination == "System":
                if message.command == "halt" or message.command == "stop":
                    self.running = False
                elif message.command == "restart":
                    self.running = False
                    self.should_restart = True
                elif message.command == "PublicIpDiscovered":
                    self.public_ip = message.arguments[0]
                elif message.command == "GetVersion":
                    self.print("\n\nreceived Get Version FROM %s\n\n" % (message.sender_id))
                    m = Message("System", message.sender_id, "GetVersion_ret",
                                [{
                                    "current_version": self.updater.current_version,
                                    "new_version": self.updater.new_version_available
                                }], communication_id=message.communication_id)
                    self.q_uiwebserver_in.put(m)
                elif message.command == "increment":
                    message.destination = "UIWebServer" # useless step ? the message wil not be dispatched anymore, no nee to change its dest
                    self.q_uiwebserver_in.put(message)
                elif message.command == "uptime":
                    m = Message("System", "Logger", "print", ["Running since %s (hh:mm:ss)\n" % (time.strftime('%H:%M:%S', time.gmtime(self.uptime)))])
                    self.q_logger_in.put(m)
                elif message.command == "print":
                    self.print("%s %s %s\n"%(message.sender_id, message.command, message.arguments))
                elif message.command == "exception":
                    self.print("%s Catched exception: %s \n"%(message.sender_id, [message.arguments[0]]))
                elif message.command == "NodeInfo":
                    m = Message("System", message.sender_id, "NodeInfo_ret",
                                [{"ismaster": self.ismaster, "nodeid": self.nodeid,
                                 "webuiport": self.webuiport, "comport": self.comport,
                                 "masterip": self.masterip, "masterport": self.masterport,
                                 "user_appdata_directory": self.user_appdata_directory,
                                 "started_at": self.started_at, "uptime": self.uptime,
                                 "public_ip": self.public_ip,
                                  "version": self.updater.current_version
                                  }], communication_id=message.communication_id)
                    self.q_uiwebserver_in.put(m)

            #
            # we also intercept print comands
            #
            elif message.destination == "Logger":
                if self.running:
                    self.q_logger_in.put(message)
                else:
                    # if no logger running we fallback to the system print
                    self.print("%s %s %s\n"%(message.sender_id, message.command, message.arguments))

            elif message.destination == "PeerStore":
                self.q_peerstore_in.put(message)

            elif message.destination == "UIWebServer":
                self.q_uiwebserver_in.put(message)

            elif message.destination == "ComWebServer":
                self.q_comwebserver_in.put(message)

            elif message.destination == "Client":
                self.q_client_in.put(message)


            #
            # dispatch other messages
            #
            else :
                self.print("Message dispatcher received a msg for the unknown destination '%s'\n" % (message.destination))

        except Exception as e:
            self.print("Exception while dispatching message '%s'\n" % ([e]))

    def print(self, message):
        sys.stdout.write("%s => %s" % (datetime.datetime.utcnow().strftime("%Y %b %d %H:%M:%S %Z "), message))
        sys.stdout.flush()

    def signal_handler(self, sig, frame):
        if sig == signal.SIGINT:
            self.print("Please type 'halt' or 'stop' to close the program or 'restart' to full restart\n")