예제 #1
0
	def registerEvents(self):
		if not self._printerListener:
			self._printerListener = PrinterListener(self)
			printerManager().registerCallback(self._printerListener)
예제 #2
0
class AstroprintBoxRouterClient(WebSocketClient):
	def __init__(self, hostname, router):
		self._router = router
		self._printerListener = None
		self._lastReceived = 0
		self._subscribers = 0
		self._silentReconnect = False
		self._cameraManager = cameraManager()
		self._profileManager = printerProfileManager()
		self._logger = logging.getLogger(__name__)
		self._lineCheck = None
		self._error = False
		self._condition = threading.Condition()
		super(AstroprintBoxRouterClient, self).__init__(hostname)

	def send(self, data):
		with self._condition:
			if not self.terminated:
				try:
					super(AstroprintBoxRouterClient, self).send(data)

				except socket.error as e:
					self._logger.error('Error raised during send: %s' % e)

					self._error = True

					#Something happened to the link. Let's try to reset it
					self.close()

	def ponged(self, pong):
		if str(pong) == LINE_CHECK_STRING:
			self.outstandingPings -= 1

	def lineCheck(self, timeout=30):
		while not self.terminated:
			sleep(timeout)
			if self.terminated:
				break

			if self.outstandingPings > 0:
				self._logger.error('The line seems to be down')
				self._router.close()
				self._router._doRetry()
				break
			
			if time() - self._lastReceived > timeout:
				try:
					self.send(PingControlMessage(data=LINE_CHECK_STRING))
					self.outstandingPings += 1

				except socket.error:
					self._logger.error("Line Check failed to send")

					#retry connection
					self._router.close()
					self._router._doRetry()

		self._lineCheckThread = None

	def terminate(self):
		#This is code to fix an apparent error in ws4py
		try:
			super(AstroprintBoxRouterClient, self).terminate()
		except AttributeError as e:
			if self.stream is None:
				self.environ = None
			else:
				raise e

	def opened(self):
		self.outstandingPings = 0
		self._lineCheckThread = threading.Thread(target=self.lineCheck)
		self._lineCheckThread.daemon = True
		self._error = False
		self._lineCheckThread.start()

	def closed(self, code, reason=None):
		#only retry if the connection was terminated by the remote or a link check failure (silentReconnect)
		if self._error or (self.server_terminated and self._router.connected):
			self._router.close()
			self._router._doRetry()

	def received_message(self, m):
		self._lastReceived = time()
		msg = json.loads(str(m))
		printer = printerManager()

		if msg['type'] == 'auth':
			self._router.processAuthenticate(msg['data'] if 'data' in msg else None)

		elif msg['type'] == 'set_temp':
			if printer.isOperational():
				payload = msg['payload']
				printer.setTemperature(payload['target'] or 0.0, payload['value'] or 0.0)

		elif msg['type'] == 'update_subscribers':
			self._subscribers += int(msg['data'])

			if not self._printerListener and self._subscribers > 0:
				self.registerEvents()
			elif self._printerListener and self._subscribers <= 0:
				self._subscribers = 0
				self.unregisterEvents()

		elif msg['type'] == 'request':
			try:
				reqId = msg['reqId']
				request = msg['data']['type']
				data = msg['data']['payload']

				if request == 'initial_state':
					response = {
						'printing': printer.isPrinting(),
						'operational': printer.isOperational(),
						'paused': printer.isPaused(),
						'camera': printer.isCameraConnected(),
						'printCapture': self._cameraManager.timelapseInfo,
						'profile': self._profileManager.data
					}
				elif request == 'job_info':
					response = printer._stateMonitor._jobData

				elif request == 'printerCommand':
					command = data['command']
					options = data['options']

					response = {'success': True}
					if command == 'pause' or command == 'resume':
						printer.togglePausePrint();

					elif command == 'cancel':
						printer.cancelPrint();

					elif command == 'photo':
						response['image_data'] = base64.b64encode(self._cameraManager.get_pic())

					else:
						response = {
							'error': True,
							'message': 'Printer command [%s] is not supported' % command
						}

				elif request == 'printCapture':
					freq = data['freq']
					if freq:
						if self._cameraManager.timelapseInfo:
							if self._cameraManager.update_timelapse(freq):
								response = {'success': True}
							else:
								response = {
									'error': True,
									'message': 'Error updating the print capture'
								}
								
						else:
							if self._cameraManager.start_timelapse(freq):
								response = {'success': True}
							else:
								response = {
									'error': True,
									'message': 'Error creating the print capture'
								}

					else:
						response = {
							'error': True,
							'message': 'Frequency required'
						}

				elif request == 'signoff':
					from astroprint.cloud import astroprintCloud

					self._logger.info('Remote signoff requested.')
					threading.Timer(1, astroprintCloud().remove_logged_user).start()

					response = {'success': True}				

				else:
					response = {
						'error': True,
						'message': 'This Box does not recognize the request type [%s]' % request
					}

				self.send(json.dumps({
					'type': 'req_response',
					'reqId': reqId,
					'data': response
				}))

			except Exception as e:
				message = 'Error sending [%s] response: %s' % (request, e) 
				self._logger.error( message )	
				self.send(json.dumps({
					'type': 'req_response',
					'reqId': reqId,
					'data': {'error': True, 'message':message }
				}))

	def registerEvents(self):
		if not self._printerListener:
			self._printerListener = PrinterListener(self)
			printerManager().registerCallback(self._printerListener)

	def unregisterEvents(self):
		if self._printerListener:
			printerManager().unregisterCallback(self._printerListener)
			self._printerListener.cleanup()
			self._printerListener = None
예제 #3
0
 def registerEvents(self):
     if not self._printerListener:
         self._printerListener = PrinterListener(self)
         printerManager().registerCallback(self._printerListener)
예제 #4
0
class AstroprintBoxRouterClient(WebSocketClient):
    def __init__(self, hostname, router):
        self._printerListener = None
        self._lastReceived = 0
        self._lineCheck = None
        self._error = False

        self._weakRefRouter = weakref.ref(router)
        self._logger = logging.getLogger(__name__)
        self._condition = threading.Condition()
        self._messageHandler = BoxRouterMessageHandler(self._weakRefRouter,
                                                       self)
        super(AstroprintBoxRouterClient, self).__init__(hostname)

    def __del__(self):
        self.unregisterEvents()

    def send(self, data):
        with self._condition:
            if not self.terminated:
                try:
                    super(AstroprintBoxRouterClient, self).send(data)

                except socket.error as e:
                    self._logger.error('Error raised during send: %s' % e)

                    self._error = True

                    #Something happened to the link. Let's try to reset it
                    self.close()

    def ponged(self, pong):
        if str(pong) == LINE_CHECK_STRING:
            self.outstandingPings -= 1

    def lineCheck(self, timeout=30):
        while not self.terminated:
            sleep(timeout)
            if self.terminated:
                break

            if self.outstandingPings > 0:
                self._logger.error('The line seems to be down')

                router = self._weakRefRouter()
                router.close()
                router._doRetry()
                break

            if time() - self._lastReceived > timeout:
                try:
                    self.send(PingControlMessage(data=LINE_CHECK_STRING))
                    self.outstandingPings += 1

                except socket.error:
                    self._logger.error("Line Check failed to send")

                    #retry connection
                    router = self._weakRefRouter()
                    router.close()
                    router._doRetry()

        self._lineCheckThread = None

    def terminate(self):
        #This is code to fix an apparent error in ws4py
        try:
            self._th = None  #If this is not freed, the socket can't be freed because of circular references
            super(AstroprintBoxRouterClient, self).terminate()

        except AttributeError as e:
            if self.stream is None:
                self.environ = None
            else:
                raise e

    def opened(self):
        self.outstandingPings = 0
        self._lineCheckThread = threading.Thread(target=self.lineCheck)
        self._lineCheckThread.daemon = True
        self._error = False
        self._lineCheckThread.start()

    def closed(self, code, reason=None):
        #only retry if the connection was terminated by the remote or a link check failure (silentReconnect)
        router = self._weakRefRouter()

        if self._error or (self.server_terminated and router
                           and router.connected):
            router.close()
            router._doRetry()

    def received_message(self, m):
        self._lastReceived = time()
        msg = json.loads(str(m))

        method = getattr(self._messageHandler, msg['type'], None)
        if method:
            response = method(msg)
            if response is not None:
                self.send(json.dumps(response))

        else:
            self._logger.warn('Unknown message type [%s] received' %
                              msg['type'])

    def registerEvents(self):
        if not self._printerListener:
            self._printerListener = PrinterListener(self)
            printerManager().registerCallback(self._printerListener)

    def unregisterEvents(self):
        if self._printerListener:
            printerManager().unregisterCallback(self._printerListener)
            self._printerListener.cleanup()
            self._printerListener = None
예제 #5
0
class AstroprintBoxRouterClient(WebSocketClient):
	def __init__(self, hostname, router):
		self._printerListener = None
		self._lastReceived = 0
		self._lineCheck = None
		self._error = False

		self._weakRefRouter = weakref.ref(router)
		self._logger = logging.getLogger(__name__)
		self._condition = threading.Condition()
		self._messageHandler = BoxRouterMessageHandler(self._weakRefRouter, self)
		super(AstroprintBoxRouterClient, self).__init__(hostname)

	def __del__(self):
		self.unregisterEvents()

	def send(self, data):
		with self._condition:
			if not self.terminated:
				try:
					super(AstroprintBoxRouterClient, self).send(data)

				except socket.error as e:
					self._logger.error('Error raised during send: %s' % e)

					self._error = True

					#Something happened to the link. Let's try to reset it
					self.close()

	def ponged(self, pong):
		if str(pong) == LINE_CHECK_STRING:
			self.outstandingPings -= 1

	def lineCheck(self, timeout=30):
		while not self.terminated:
			sleep(timeout)
			if self.terminated:
				break

			if self.outstandingPings > 0:
				self._logger.error('The line seems to be down')

				router = self._weakRefRouter()
				router.close()
				router._doRetry()
				break

			if time() - self._lastReceived > timeout:
				try:
					self.send(PingControlMessage(data=LINE_CHECK_STRING))
					self.outstandingPings += 1

				except socket.error:
					self._logger.error("Line Check failed to send")

					#retry connection
					router = self._weakRefRouter()
					router.close()
					router._doRetry()

		self._lineCheckThread = None

	def terminate(self):
		#This is code to fix an apparent error in ws4py
		try:
			self._th = None #If this is not freed, the socket can't be freed because of circular references
			super(AstroprintBoxRouterClient, self).terminate()
			
		except AttributeError as e:
			if self.stream is None:
				self.environ = None
			else:
				raise e

	def opened(self):
		self.outstandingPings = 0
		self._lineCheckThread = threading.Thread(target=self.lineCheck)
		self._lineCheckThread.daemon = True
		self._error = False
		self._lineCheckThread.start()

	def closed(self, code, reason=None):
		#only retry if the connection was terminated by the remote or a link check failure (silentReconnect)
		router = self._weakRefRouter()

		if self._error or (self.server_terminated and router and router.connected):
			router.close()
			router._doRetry()

	def received_message(self, m):
		self._lastReceived = time()
		msg = json.loads(str(m))
		
		method  = getattr(self._messageHandler, msg['type'], None)
		if method:
			response = method(msg)
			if response is not None:
				self.send(json.dumps(response))

		else:
			self._logger.warn('Unknown message type [%s] received' % msg['type'])

	def registerEvents(self):
		if not self._printerListener:
			self._printerListener = PrinterListener(self)
			printerManager().registerCallback(self._printerListener)

	def unregisterEvents(self):
		if self._printerListener:
			printerManager().unregisterCallback(self._printerListener)
			self._printerListener.cleanup()
			self._printerListener = None
예제 #6
0
class AstroprintBoxRouterClient(WebSocketClient):
    def __init__(self, hostname, router):
        self._weakRefRouter = weakref.ref(router)
        self._printerListener = None
        self._lastReceived = 0
        self._subscribers = 0
        self._silentReconnect = False
        self._profileManager = printerProfileManager()
        self._logger = logging.getLogger(__name__)
        self._lineCheck = None
        self._error = False
        self._condition = threading.Condition()
        super(AstroprintBoxRouterClient, self).__init__(hostname)

    def __del__(self):
        self.unregisterEvents()

    def send(self, data):
        with self._condition:
            if not self.terminated:
                try:
                    super(AstroprintBoxRouterClient, self).send(data)

                except socket.error as e:
                    self._logger.error('Error raised during send: %s' % e)

                    self._error = True

                    #Something happened to the link. Let's try to reset it
                    self.close()

    def ponged(self, pong):
        if str(pong) == LINE_CHECK_STRING:
            self.outstandingPings -= 1

    def lineCheck(self, timeout=30):
        while not self.terminated:
            sleep(timeout)
            if self.terminated:
                break

            if self.outstandingPings > 0:
                self._logger.error('The line seems to be down')

                router = self._weakRefRouter()
                router.close()
                router._doRetry()
                break

            if time() - self._lastReceived > timeout:
                try:
                    self.send(PingControlMessage(data=LINE_CHECK_STRING))
                    self.outstandingPings += 1

                except socket.error:
                    self._logger.error("Line Check failed to send")

                    #retry connection
                    router = self._weakRefRouter()
                    router.close()
                    router._doRetry()

        self._lineCheckThread = None

    def terminate(self):
        #This is code to fix an apparent error in ws4py
        try:
            self._th = None  #If this is not freed, the socket can't be freed because of circular references
            super(AstroprintBoxRouterClient, self).terminate()

        except AttributeError as e:
            if self.stream is None:
                self.environ = None
            else:
                raise e

    def opened(self):
        self.outstandingPings = 0
        self._lineCheckThread = threading.Thread(target=self.lineCheck)
        self._lineCheckThread.daemon = True
        self._error = False
        self._lineCheckThread.start()

    def closed(self, code, reason=None):
        #only retry if the connection was terminated by the remote or a link check failure (silentReconnect)
        router = self._weakRefRouter()

        if self._error or (self.server_terminated and router
                           and router.connected):
            router.close()
            router._doRetry()

    def received_message(self, m):
        self._lastReceived = time()
        msg = json.loads(str(m))
        printer = printerManager()

        if msg['type'] == 'auth':
            router = self._weakRefRouter()
            router and router.processAuthenticate(msg['data'] if 'data' in
                                                  msg else None)

        elif msg['type'] == 'set_temp':
            if printer.isOperational():
                payload = msg['payload']
                printer.setTemperature(payload['target'] or 0.0,
                                       payload['value'] or 0.0)

        elif msg['type'] == 'update_subscribers':
            self._subscribers += int(msg['data'])

            if not self._printerListener and self._subscribers > 0:
                self.registerEvents()
            elif self._printerListener and self._subscribers <= 0:
                self._subscribers = 0
                self.unregisterEvents()

        elif msg['type'] == 'request':
            try:
                reqId = msg['reqId']
                request = msg['data']['type']
                data = msg['data']['payload']

                if request == 'initial_state':
                    response = {
                        'printing': printer.isPrinting(),
                        'operational': printer.isOperational(),
                        'paused': printer.isPaused(),
                        'camera': printer.isCameraConnected(),
                        'printCapture': cameraManager().timelapseInfo,
                        'profile': self._profileManager.data,
                        'remotePrint': True
                    }
                elif request == 'job_info':
                    response = printer._stateMonitor._jobData

                elif request == 'printerCommand':
                    command = data['command']
                    options = data['options']

                    response = {'success': True}
                    if command == 'pause' or command == 'resume':
                        printer.togglePausePrint()

                    elif command == 'cancel':
                        printer.cancelPrint()

                    elif command == 'photo':
                        response['image_data'] = base64.b64encode(
                            cameraManager().get_pic())

                    else:
                        response = {
                            'error':
                            True,
                            'message':
                            'Printer command [%s] is not supported' % command
                        }

                elif request == 'printCapture':
                    freq = data['freq']
                    if freq:
                        cm = cameraManager()

                        if cm.timelapseInfo:
                            if cm.update_timelapse(freq):
                                response = {'success': True}
                            else:
                                response = {
                                    'error': True,
                                    'message':
                                    'Error updating the print capture'
                                }

                        else:
                            if cm.start_timelapse(freq):
                                response = {'success': True}
                            else:
                                response = {
                                    'error': True,
                                    'message':
                                    'Error creating the print capture'
                                }

                    else:
                        response = {
                            'error': True,
                            'message': 'Frequency required'
                        }

                elif request == 'signoff':
                    from astroprint.cloud import astroprintCloud

                    self._logger.info('Remote signoff requested.')
                    threading.Timer(
                        1,
                        astroprintCloud().remove_logged_user).start()

                    response = {'success': True}

                elif request == 'print_file':
                    from astroprint.cloud import astroprintCloud
                    from astroprint.printfiles import FileDestinations

                    print_file_id = data['printFileId']

                    em = eventManager()

                    def progressCb(progress):
                        em.fire(
                            Events.CLOUD_DOWNLOAD, {
                                "type": "progress",
                                "id": print_file_id,
                                "progress": progress
                            })

                    def successCb(destFile, fileInfo):
                        if fileInfo is not True:
                            if printer.fileManager.saveCloudPrintFile(
                                    destFile, fileInfo,
                                    FileDestinations.LOCAL):
                                em.fire(
                                    Events.CLOUD_DOWNLOAD, {
                                        "type":
                                        "success",
                                        "id":
                                        print_file_id,
                                        "filename":
                                        printer.fileManager._getBasicFilename(
                                            destFile),
                                        "info":
                                        fileInfo["info"]
                                    })

                            else:
                                errorCb(destFile, "Couldn't save the file")
                                return

                        abosluteFilename = printer.fileManager.getAbsolutePath(
                            destFile)
                        if printer.selectFile(abosluteFilename, False, True):
                            self._printerListener._sendUpdate(
                                'print_file_download', {
                                    'id': print_file_id,
                                    'progress': 100,
                                    'selected': True
                                })

                        else:
                            self._printerListener._sendUpdate(
                                'print_file_download', {
                                    'id': print_file_id,
                                    'progress': 100,
                                    'error': True,
                                    'message': 'Unable to start printing',
                                    'selected': False
                                })

                    def errorCb(destFile, error):
                        if error == 'cancelled':
                            em.fire(Events.CLOUD_DOWNLOAD, {
                                "type": "cancelled",
                                "id": print_file_id
                            })
                        else:
                            em.fire(
                                Events.CLOUD_DOWNLOAD, {
                                    "type": "error",
                                    "id": print_file_id,
                                    "reason": error
                                })

                        if destFile and os.path.exists(destFile):
                            os.remove(destFile)

                    if astroprintCloud().download_print_file(
                            print_file_id, progressCb, successCb, errorCb):
                        response = {'success': True}
                    else:
                        response = {
                            'error': True,
                            'message': 'Unable to start download process'
                        }

                elif request == 'cancel_download':
                    from astroprint.printfiles.downloadmanager import downloadManager

                    print_file_id = data['printFileId']

                    if downloadManager().cancelDownload(print_file_id):
                        response = {'success': True}
                    else:
                        response = {
                            'error': True,
                            'message': 'Unable to cancel download'
                        }

                else:
                    response = {
                        'error':
                        True,
                        'message':
                        'This Box does not recognize the request type [%s]' %
                        request
                    }

                self.send(
                    json.dumps({
                        'type': 'req_response',
                        'reqId': reqId,
                        'data': response
                    }))

            except Exception as e:
                message = 'Error sending [%s] response: %s' % (request, e)
                self._logger.error(message)
                self.send(
                    json.dumps({
                        'type': 'req_response',
                        'reqId': reqId,
                        'data': {
                            'error': True,
                            'message': message
                        }
                    }))

    def registerEvents(self):
        if not self._printerListener:
            self._printerListener = PrinterListener(self)
            printerManager().registerCallback(self._printerListener)

    def unregisterEvents(self):
        if self._printerListener:
            printerManager().unregisterCallback(self._printerListener)
            self._printerListener.cleanup()
            self._printerListener = None
예제 #7
0
class AstroprintBoxRouterClient(WebSocketClient):
    def __init__(self, hostname, router):
        #it needs to be imported here because on the main body 'printer' is None
        from octoprint.server import printer

        self._router = router
        self._printer = printer
        self._printerListener = None
        self._lastReceived = 0
        self._subscribers = 0
        self._silentReconnect = False
        self._cameraManager = cameraManager()
        self._profileManager = printerProfileManager()
        self._logger = logging.getLogger(__name__)
        self._lineCheck = None
        super(AstroprintBoxRouterClient, self).__init__(hostname)

    def send(self, data):
        try:
            WebSocketClient.send(self, data)

        except socket.error as e:
            self._logger.error('Error raised during send: %s' % e)

            #Something happened to the link. Let's try to reset it
            self.close()

    def ponged(self, pong):
        if str(pong) == LINE_CHECK_STRING:
            self.outstandingPings -= 1

    def lineCheck(self, timeout=30):
        while not self.terminated:
            sleep(timeout)
            if self.terminated:
                break

            if self.outstandingPings > 0:
                self._logger.error('The line seems to be down')
                self._router.close()
                self._router._doRetry()
                break

            if time() - self._lastReceived > timeout:
                try:
                    self.send(PingControlMessage(data=LINE_CHECK_STRING))
                    self.outstandingPings += 1

                except socket.error:
                    self._logger.error("Line Check failed to send")

                    #retry connection
                    self._router.close()
                    self._router._doRetry()

        self._lineCheckThread = None

    def terminate(self):
        #This is code to fix an apparent error in ws4py
        try:
            super(AstroprintBoxRouterClient, self).terminate()
        except AttributeError as e:
            if self.stream is None:
                self.environ = None
            else:
                raise e

    def opened(self):
        self.outstandingPings = 0
        self._lineCheckThread = threading.Thread(target=self.lineCheck)
        self._lineCheckThread.daemon = True
        self._lineCheckThread.start()

    def closed(self, code, reason=None):
        #only retry if the connection was terminated by the remote or a link check failure (silentReconnect)
        if self.server_terminated and self._router.connected:
            self._router.close()
            self._router._doRetry()

    def received_message(self, m):
        self._lastReceived = time()
        msg = json.loads(str(m))

        if msg['type'] == 'auth':
            self._router.processAuthenticate(msg['data'] if 'data' in
                                             msg else None)

        elif msg['type'] == 'set_temp':
            if self._printer.isOperational():
                payload = msg['payload']
                self._printer.setTemperature(payload['target'] or 0.0,
                                             payload['value'] or 0.0)

        elif msg['type'] == 'update_subscribers':
            self._subscribers += int(msg['data'])

            if not self._printerListener and self._subscribers > 0:
                self.registerEvents()
            elif self._printerListener and self._subscribers <= 0:
                self._subscribers = 0
                self.unregisterEvents()

        elif msg['type'] == 'request':
            try:
                reqId = msg['reqId']
                request = msg['data']['type']
                data = msg['data']['payload']

                if request == 'initial_state':
                    response = {
                        'printing': self._printer.isPrinting(),
                        'operational': self._printer.isOperational(),
                        'paused': self._printer.isPaused(),
                        'camera': self._printer.isCameraConnected(),
                        'printCapture': self._cameraManager.timelapseInfo,
                        'profile': self._profileManager.data
                    }
                elif request == 'job_info':
                    response = self._printer._stateMonitor._jobData

                elif request == 'printerCommand':
                    command = data['command']
                    options = data['options']

                    response = {'success': True}
                    if command == 'pause' or command == 'resume':
                        self._printer.togglePausePrint()

                    elif command == 'cancel':
                        self._printer.cancelPrint()

                    elif command == 'photo':
                        response['image_data'] = base64.b64encode(
                            self._cameraManager.get_pic())

                    else:
                        response = {
                            'error':
                            True,
                            'message':
                            'Printer command [%s] is not supported' % command
                        }

                elif request == 'printCapture':
                    freq = data['freq']
                    if freq:
                        if self._cameraManager.timelapseInfo:
                            if self._cameraManager.update_timelapse(freq):
                                response = {'success': True}
                            else:
                                response = {
                                    'error': True,
                                    'message':
                                    'Error updating the print capture'
                                }

                        else:
                            if self._cameraManager.start_timelapse(freq):
                                response = {'success': True}
                            else:
                                response = {
                                    'error': True,
                                    'message':
                                    'Error creating the print capture'
                                }

                    else:
                        response = {
                            'error': True,
                            'message': 'Frequency required'
                        }

                else:
                    response = {
                        'error':
                        True,
                        'message':
                        'This Box does not recognize the request type [%s]' %
                        request
                    }

                self.send(
                    json.dumps({
                        'type': 'req_response',
                        'reqId': reqId,
                        'data': response
                    }))

            except Exception as e:
                message = 'Error sending [%s] response: %s' % (request, e)
                self._logger.error(message)
                self.send(
                    json.dumps({
                        'type': 'req_response',
                        'reqId': reqId,
                        'data': {
                            'error': True,
                            'message': message
                        }
                    }))

    def registerEvents(self):
        if not self._printerListener:
            self._printerListener = PrinterListener(self)
            self._printer.registerCallback(self._printerListener)

    def unregisterEvents(self):
        if self._printerListener:
            self._printer.unregisterCallback(self._printerListener)
            self._printerListener.cleanup()
            self._printerListener = None
예제 #8
0
class AstroprintBoxRouterClient(WebSocketClient):
	def __init__(self, hostname, router):
		self._weakRefRouter = weakref.ref(router)
		self._printerListener = None
		self._lastReceived = 0
		self._subscribers = 0
		self._silentReconnect = False
		self._profileManager = printerProfileManager()
		self._logger = logging.getLogger(__name__)
		self._lineCheck = None
		self._error = False
		self._condition = threading.Condition()
		super(AstroprintBoxRouterClient, self).__init__(hostname)

	def __del__(self):
		self.unregisterEvents()

	def send(self, data):
		with self._condition:
			if not self.terminated:
				try:
					super(AstroprintBoxRouterClient, self).send(data)

				except socket.error as e:
					self._logger.error('Error raised during send: %s' % e)

					self._error = True

					#Something happened to the link. Let's try to reset it
					self.close()

	def ponged(self, pong):
		if str(pong) == LINE_CHECK_STRING:
			self.outstandingPings -= 1

	def lineCheck(self, timeout=30):
		while not self.terminated:
			sleep(timeout)
			if self.terminated:
				break

			if self.outstandingPings > 0:
				self._logger.error('The line seems to be down')

				router = self._weakRefRouter()
				router.close()
				router._doRetry()
				break

			if time() - self._lastReceived > timeout:
				try:
					self.send(PingControlMessage(data=LINE_CHECK_STRING))
					self.outstandingPings += 1

				except socket.error:
					self._logger.error("Line Check failed to send")

					#retry connection
					router = self._weakRefRouter()
					router.close()
					router._doRetry()

		self._lineCheckThread = None

	def terminate(self):
		#This is code to fix an apparent error in ws4py
		try:
			self._th = None #If this is not freed, the socket can't be freed because of circular references
			super(AstroprintBoxRouterClient, self).terminate()
			
		except AttributeError as e:
			if self.stream is None:
				self.environ = None
			else:
				raise e

	def opened(self):
		self.outstandingPings = 0
		self._lineCheckThread = threading.Thread(target=self.lineCheck)
		self._lineCheckThread.daemon = True
		self._error = False
		self._lineCheckThread.start()

	def closed(self, code, reason=None):
		#only retry if the connection was terminated by the remote or a link check failure (silentReconnect)
		router = self._weakRefRouter()

		if self._error or (self.server_terminated and router and router.connected):
			router.close()
			router._doRetry()

	def received_message(self, m):
		self._lastReceived = time()
		msg = json.loads(str(m))
		printer = printerManager()

		if msg['type'] == 'auth':
			router = self._weakRefRouter()
			router and router.processAuthenticate(msg['data'] if 'data' in msg else None)

		elif msg['type'] == 'set_temp':
			if printer.isOperational():
				payload = msg['payload']
				printer.setTemperature(payload['target'] or 0.0, payload['value'] or 0.0)

		elif msg['type'] == 'update_subscribers':
			self._subscribers += int(msg['data'])

			if not self._printerListener and self._subscribers > 0:
				self.registerEvents()
			elif self._printerListener and self._subscribers <= 0:
				self._subscribers = 0
				self.unregisterEvents()

		elif msg['type'] == 'request':
			try:
				reqId = msg['reqId']
				request = msg['data']['type']
				data = msg['data']['payload']

				if request == 'initial_state':
					response = {
						'printing': printer.isPrinting(),
						'operational': printer.isOperational(),
						'paused': printer.isPaused(),
						'camera': printer.isCameraConnected(),
						'printCapture': cameraManager().timelapseInfo,
						'profile': self._profileManager.data,
						'remotePrint': True
					}
				elif request == 'job_info':
					response = printer._stateMonitor._jobData

				elif request == 'printerCommand':
					command = data['command']
					options = data['options']

					response = {'success': True}
					if command == 'pause' or command == 'resume':
						printer.togglePausePrint();

					elif command == 'cancel':
						printer.cancelPrint();

					elif command == 'photo':
						response['image_data'] = base64.b64encode(cameraManager().get_pic())

					else:
						response = {
							'error': True,
							'message': 'Printer command [%s] is not supported' % command
						}

				elif request == 'printCapture':
					freq = data['freq']
					if freq:
						cm = cameraManager()

						if cm.timelapseInfo:
							if cm.update_timelapse(freq):
								response = {'success': True}
							else:
								response = {
									'error': True,
									'message': 'Error updating the print capture'
								}

						else:
							if cm.start_timelapse(freq):
								response = {'success': True}
							else:
								response = {
									'error': True,
									'message': 'Error creating the print capture'
								}

					else:
						response = {
							'error': True,
							'message': 'Frequency required'
						}

				elif request == 'signoff':
					from astroprint.cloud import astroprintCloud

					self._logger.info('Remote signoff requested.')
					threading.Timer(1, astroprintCloud().remove_logged_user).start()

					response = {'success': True}

				elif request == 'print_file':
					from astroprint.cloud import astroprintCloud
					from astroprint.printfiles import FileDestinations

					print_file_id = data['printFileId']

					em = eventManager()

					def progressCb(progress):
						em.fire(
							Events.CLOUD_DOWNLOAD, {
								"type": "progress",
								"id": print_file_id,
								"progress": progress
							}
						)

					def successCb(destFile, fileInfo):
						if fileInfo is not True:
							if printer.fileManager.saveCloudPrintFile(destFile, fileInfo, FileDestinations.LOCAL):
								em.fire(
									Events.CLOUD_DOWNLOAD, {
										"type": "success",
										"id": print_file_id,
										"filename": printer.fileManager._getBasicFilename(destFile),
										"info": fileInfo["info"]
									}
								)

							else:
								errorCb(destFile, "Couldn't save the file")
								return

						abosluteFilename = printer.fileManager.getAbsolutePath(destFile)
						if printer.selectFile(abosluteFilename, False, True):
							self._printerListener._sendUpdate('print_file_download', {
								'id': print_file_id,
								'progress': 100,
								'selected': True
							})

						else:
							self._printerListener._sendUpdate('print_file_download', {
								'id': print_file_id,
								'progress': 100,
								'error': True,
								'message': 'Unable to start printing',
								'selected': False
							})

					def errorCb(destFile, error):
						if error == 'cancelled':
							em.fire(
									Events.CLOUD_DOWNLOAD,
									{
										"type": "cancelled",
										"id": print_file_id
									}
								)
						else:
							em.fire(
								Events.CLOUD_DOWNLOAD,
								{
									"type": "error",
									"id": print_file_id,
									"reason": error
								}
							)

						if destFile and os.path.exists(destFile):
							os.remove(destFile)

					if astroprintCloud().download_print_file(print_file_id, progressCb, successCb, errorCb):
						response = {'success': True}
					else:
						response = {
							'error': True,
							'message': 'Unable to start download process'
						}

				elif request == 'cancel_download':
					from astroprint.printfiles.downloadmanager import downloadManager

					print_file_id = data['printFileId']

					if downloadManager().cancelDownload(print_file_id):
						response = {'success': True}
					else:
						response = {
							'error': True,
							'message': 'Unable to cancel download'
						}

				else:
					response = {
						'error': True,
						'message': 'This Box does not recognize the request type [%s]' % request
					}

				self.send(json.dumps({
					'type': 'req_response',
					'reqId': reqId,
					'data': response
				}))

			except Exception as e:
				message = 'Error sending [%s] response: %s' % (request, e)
				self._logger.error( message )
				self.send(json.dumps({
					'type': 'req_response',
					'reqId': reqId,
					'data': {'error': True, 'message':message }
				}))

	def registerEvents(self):
		if not self._printerListener:
			self._printerListener = PrinterListener(self)
			printerManager().registerCallback(self._printerListener)

	def unregisterEvents(self):
		if self._printerListener:
			printerManager().unregisterCallback(self._printerListener)
			self._printerListener.cleanup()
			self._printerListener = None
예제 #9
0
class AstroprintBoxRouterClient(WebSocketClient):
	def __init__(self, hostname, router):
		#it needs to be imported here because on the main body 'printer' is None
		from octoprint.server import printer

		self._router = router
		self._printer = printer
		self._printerListener = None
		self._subscribers = 0
		self._cameraManager = cameraManager()
		self._logger = logging.getLogger(__name__)
		WebSocketClient.__init__(self, hostname)

	def closed(self, code, reason=None):
		#only retry if the connection was terminated by the remote
		retry = self._router.connected

		self._router.close()

		if retry:
			self._router._doRetry()

	def received_message(self, m):
		msg = json.loads(str(m))

		if msg['type'] == 'auth':
			self._router.processAuthenticate(msg['data'] if 'data' in msg else None)

		elif msg['type'] == 'set_temp':
			if self._printer.isOperational():
				payload = msg['payload']
				self._printer.setTemperature(payload['target'] or 0.0, payload['value'] or 0.0)

		elif msg['type'] == 'update_subscribers':
			self._subscribers += int(msg['data'])

			if not self._printerListener and self._subscribers > 0:
				self.registerEvents()
			elif self._printerListener and self._subscribers <= 0:
				self._subscribers = 0
				self.unregisterEvents()

		elif msg['type'] == 'request':
			try:
				reqId = msg['reqId']
				request = msg['data']['type']
				data = msg['data']['payload']

				if request == 'initial_state':
					response = {
						'printing': self._printer.isPrinting(),
						'operational': self._printer.isOperational(),
						'paused': self._printer.isPaused(),
						'camera': self._printer.isCameraConnected(),
						'printCapture': self._cameraManager.timelapseInfo
					}
				elif request == 'job_info':
					response = self._printer._stateMonitor._jobData

				elif request == 'printerCommand':
					command = data['command']
					options = data['options']

					response = {'success': True}
					if command == 'pause' or command == 'resume':
						self._printer.togglePausePrint();

					elif command == 'cancel':
						self._printer.cancelPrint();

					elif command == 'photo':
						response['image_data'] = base64.b64encode(self._cameraManager.get_pic())

					else:
						response = {
							'error': True,
							'message': 'Printer command [%s] is not supported' % command
						}

				elif request == 'printCapture':
					freq = data['freq']
					if freq:
						if self._cameraManager.timelapseInfo:
							if self._cameraManager.update_timelapse(freq):
								response = {'success': True}
							else:
								response = {
									'error': True,
									'message': 'Error updating the print capture'
								}
								
						else:
							if self._cameraManager.start_timelapse(freq):
								response = {'success': True}
							else:
								response = {
									'error': True,
									'message': 'Error creating the print capture'
								}

					else:
						response = {
							'error': True,
							'message': 'Frequency required'
						}						

				else:
					response = {
						'error': True,
						'message': 'This Box does not recognize the request type [%s]' % request
					}

				self.send(json.dumps({
					'type': 'req_response',
					'reqId': reqId,
					'data': response
				}))

			except Exception as e:
				message = 'Error sending [%s] response: %s' % (request, e) 
				self._logger.error( message )	
				self.send(json.dumps({
					'type': 'req_response',
					'reqId': reqId,
					'data': {'error': True, 'message':message }
				}))

	def registerEvents(self):
		if not self._printerListener:
			self._printerListener = PrinterListener(self)
			self._printer.registerCallback(self._printerListener)

	def unregisterEvents(self):
		if self._printerListener:
			self._printer.unregisterCallback(self._printerListener)
			self._printerListener.cleanup()
			self._printerListener = None