Ejemplo n.º 1
0
		def process_done():
			data = p.stdout.read()
			if data:
				log('Data from completion callback: %s' % repr(data))
				return True
			log('Callback for job completion done; return: %s' % repr(p.wait()))
			return False
Ejemplo n.º 2
0
def debug(priority, message):
    if priority <= config['loglimit']:
        log(message, depth=1)
    if logfile:
        logfile.write('{}: ({}) {}\n'.format(
            time.strftime('%c', time.gmtime()), priority, message))
        logfile.flush()
Ejemplo n.º 3
0
		def process_done():
			data = p.stdout.read()
			if data:
				log('Data from completion callback: %s' % repr(data))
				return True
			log('Callback for job completion done; return: %s' % repr(p.wait()))
			return False
Ejemplo n.º 4
0
	def _call(self, name, a, ka): # {{{
		wake = (yield)
		#log('other: %s %s %s' % (name, repr(a), repr(ka)))
		if 'machine' in ka:
			machine = ka.pop('machine')
		else:
			machine = None
		if machine not in machines:
			if len(machines) == 1:
				machine = tuple(machines.keys())[0]
			else:
				options = [m for m in machines if machines[m].port is not None]
				if len(options) == 1:
					machine = options[0]
				else:
					log('No active machine')
					return ('error', 'No active machine')
		if name.endswith('_POST'):
			log('refusing to call function only meant for POST')
			return ('error', 'Invalid function name')
		def reply(success, ret):
			if success:
				wake(ret)
			else:
				log('machine errors')
				wake(('error', ret))
				#disable(machine, 'machine replied with error to wake up')
		machines[machine].call(name, (self.socket.data['role'],) + tuple(a), ka, reply)
		return (yield)
Ejemplo n.º 5
0
 def boot_printer_error():
     log('error during printer detection on port %s.' % port)
     websocketd.remove_timeout(timeout_handle[0])
     printer.close()
     ports[port] = None
     broadcast(None, 'port_state', port, 0)
     return False
Ejemplo n.º 6
0
def print_done(port, completed, reason):  # {{{
    broadcast(None, 'printing', port.port, False)
    if config['done']:
        cmd = config['done']
        cmd = cmd.replace('[[STATE]]',
                          'completed' if completed else 'aborted').replace(
                              '[[REASON]]', reason)
        log('running %s' % cmd)
        p = subprocess.Popen(cmd,
                             stdout=subprocess.PIPE,
                             shell=True,
                             close_fds=True)

        def process_done():
            data = p.stdout.read()
            if data:
                log('Data from completion callback: %s' % repr(data))
                return True
            log('Callback for print completion done; return: %s' %
                repr(p.wait()))
            return False

        def process_error():
            log('Print completion process returned error.')
            return False

        websocketd.add_read(p.stdout, process_done, process_error)
Ejemplo n.º 7
0
		def boot_machine_error():
			log('error during machine detection on port %s.' % port)
			websocketd.remove_timeout(timeout_handle[0])
			machine.close()
			ports[port] = None
			broadcast(None, 'port_state', port, 0)
			return False
Ejemplo n.º 8
0
def disable(role, port): # {{{
	if port not in ports:
		log('not disabling nonexistent port %s' % port)
		return
	p = ports[port]
	if p is None:
		log('not disabling inactive port %s' % port)
		return
	if not isinstance(p, Port):
		# Detecting or similar; cancel operation.
		p()
		return
	if p.detecting:
		p.die()
		return
	# Forget the printer.  First tell the printer to die
	p.die()
	ports[port] = None
	if p:
		def done(success, ret):
			websocketd.remove_read(p.input_handle)
			try:
				p.process.kill()
			except OSError:
				pass
			try:
				p.process.communicate()
			except:
				pass
			p.process = None
		p.call('die', (role, 'disabled by user',), {}, done)
	if p not in (None, False):
		broadcast(None, 'del_printer', port)
	broadcast(None, 'port_state', port, 0)
Ejemplo n.º 9
0
	def post(self, connection):
		# Add to queue (POST).
		if 'file' not in connection.post[1] or 'port' not in connection.post[0] or 'action' not in connection.post[0]:
			self.reply(connection, 400)
			return False
		port = connection.post[0]['port'][0]
		action = connection.post[0]['action'][0]
		if port not in ports or not ports[port]:
			log('port not found: %s' % port)
			self.reply(connection, 404)
			return False
		post = connection.post[1].pop('file')
		def cb(success, ret):
			self.reply(connection, 200 if success else 400, '' if ret is None else ret.encode('utf8'), 'text/plain;charset=utf8')
			os.unlink(post[0]);
			connection.socket.close()
		if action == 'queue_add':
			ports[port].call('queue_add_file', [connection.data['role'], post[0], post[1]], {}, cb)
		elif action == 'audio_add':
			ports[port].call('audio_add_file', [connection.data['role'], post[0], post[1]], {}, cb)
		elif action == 'import':
			ports[port].call('import_file', [connection.data['role'], post[0], post[1]], {}, cb)
		else:
			os.unlink(post[0]);
			self.reply(connection, 400)
			return False
		return True
Ejemplo n.º 10
0
    def _call(self, name, a, ka):  # {{{
        wake = (yield)
        #log('other: %s %s %s' % (name, repr(a), repr(ka)))
        if 'machine' in ka:
            machine = ka.pop('machine')
        else:
            machine = None
        if machine not in machines:
            if len(machines) == 1:
                machine = tuple(machines.keys())[0]
            else:
                options = [m for m in machines if machines[m].port is not None]
                if len(options) == 1:
                    machine = options[0]
                else:
                    log('No active machine')
                    return ('error', 'No active machine')
        if name.endswith('_POST'):
            log('refusing to call function only meant for POST')
            return ('error', 'Invalid function name')

        def reply(success, ret):
            if success:
                wake(ret)
            else:
                log('machine errors')
                wake(('error', ret))
                #disable(machine, 'machine replied with error to wake up')

        machines[machine].call(name, (self.socket.data['role'], ) + tuple(a),
                               ka, reply)
        return (yield)
Ejemplo n.º 11
0
	def upload(self, port, board): # {{{
		wake = (yield)
		assert self.socket.data['role'] in ('benjamin', 'admin')
		assert port in ports
		if ports[port]:
			disable(ports[port], 'disabled for upload')
		def cancel():
			# Waking the generator kills the process.
			wake('Aborted')
		ports[port] = cancel
		command = self._get_command(board, port)
		data = ['']
		log('Flashing firmware: ' + ' '.join(command))
		broadcast(None, 'port_state', port, 3)
		process = subprocess.Popen(command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, close_fds = True)
		def output():
			d = ''
			try:
				d = process.stdout.read().decode('utf-8')
			except:
				data[0] += '\nError writing %s firmware: ' % board + traceback.format_exc()
				log(repr(data[0]))
				wake(data[0])
				return False
			if d != '':
				#broadcast(None, 'message', port, '\n'.join(data[0].split('\n')[-4:]))
				data[0] += d
				return True
			wake(data[0])
			return False
		def error():
			data[0] += '\nError writing %s firmware: ' % board
			log(repr(data[0]))
			wake(data[0])
			return False
		fl = fcntl.fcntl(process.stdout.fileno(), fcntl.F_GETFL)
		fcntl.fcntl(process.stdout.fileno(), fcntl.F_SETFL, fl | os.O_NONBLOCK)
		websocketd.add_read(process.stdout, output, error)
		broadcast(None, 'uploading', port, 'uploading firmware for %s' % board)
		#broadcast(None, 'message', port, '')
		d = (yield)
		try:
			process.kill()	# In case it wasn't dead yet.
		except:
			pass
		try:
			process.communicate()	# Clean up.
		except:
			pass
		broadcast(None, 'uploading', port, None)
		#broadcast(None, 'message', port, '')
		broadcast(None, 'port_state', port, 0)
		ports[port] = None
		if autodetect:
			websocketd.call(None, detect, port)
		if d:
			return 'firmware upload for %s: ' % board + d
		else:
			return 'firmware for %s successfully uploaded' % board
Ejemplo n.º 12
0
	def upload(self, port, board): # {{{
		wake = (yield)
		assert self.socket.data['role'] in ('benjamin', 'admin')
		assert port in ports
		if ports[port]:
			disable(ports[port], 'disabled for upload')
		def cancel():
			# Waking the generator kills the process.
			wake('Aborted')
		ports[port] = cancel
		command = self._get_command(board, port)
		data = ['']
		log('Flashing firmware: ' + ' '.join(command))
		broadcast(None, 'port_state', port, 3)
		process = subprocess.Popen(command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, close_fds = True)
		def output():
			d = ''
			try:
				d = process.stdout.read().decode('utf-8')
			except:
				data[0] += '\nError writing %s firmware: ' % board + traceback.format_exc()
				log(repr(data[0]))
				wake(data[0])
				return False
			if d != '':
				#broadcast(None, 'message', port, '\n'.join(data[0].split('\n')[-4:]))
				data[0] += d
				return True
			wake(data[0])
			return False
		def error():
			data[0] += '\nError writing %s firmware: ' % board
			log(repr(data[0]))
			wake(data[0])
			return False
		fl = fcntl.fcntl(process.stdout.fileno(), fcntl.F_GETFL)
		fcntl.fcntl(process.stdout.fileno(), fcntl.F_SETFL, fl | os.O_NONBLOCK)
		websocketd.add_read(process.stdout, output, error)
		broadcast(None, 'uploading', port, 'uploading firmware for %s' % board)
		#broadcast(None, 'message', port, '')
		d = (yield)
		try:
			process.kill()	# In case it wasn't dead yet.
		except:
			pass
		try:
			process.communicate()	# Clean up.
		except:
			pass
		broadcast(None, 'uploading', port, None)
		#broadcast(None, 'message', port, '')
		broadcast(None, 'port_state', port, 0)
		ports[port] = None
		if autodetect:
			websocketd.call(None, detect, port)
		if d:
			return 'firmware upload for %s: ' % board + d
		else:
			return 'firmware for %s successfully uploaded' % board
Ejemplo n.º 13
0
 def finish():
     log('finish detect %s' % repr(uuid))
     ports[port] = uuid
     machines[uuid] = new_machine
     log('connecting new machine %s to port %s' % (uuid, port))
     new_machine.call('connect',
                      ['admin', port, [chr(x) for x in run_id]],
                      {}, lambda success, ret: None)
Ejemplo n.º 14
0
def remove_port(port): # {{{
	log('removing port %s' % port)
	if port not in ports:
		return
	if ports[port]:
		ports[port].make_orphan()
	del ports[port]
	broadcast(None, 'del_port', port)
Ejemplo n.º 15
0
def remove_port(port): # {{{
	log('removing port %s' % port)
	if port not in ports:
		return
	if ports[port]:
		disable(ports[port], 'port is removed')
	del ports[port]
	broadcast(None, 'del_port', port)
Ejemplo n.º 16
0
def remove_port(port):  # {{{
    log('removing port %s' % port)
    if port not in ports:
        return
    if ports[port]:
        ports[port].make_orphan()
    del ports[port]
    broadcast(None, 'del_port', port)
Ejemplo n.º 17
0
 def finish(success, uuid):
     assert success
     ports[port] = uuid
     printers[uuid] = new_printer
     log('connecting new printer %s to port %s' % (uuid, port))
     new_printer.call('connect',
                      ['admin', port, [chr(x) for x in run_id]],
                      {}, lambda success, ret: None)
Ejemplo n.º 18
0
def remove_port(port):  # {{{
    log('removing port %s' % port)
    if port not in ports:
        return
    if ports[port]:
        machines[ports[port]].disconnect()
    del ports[port]
    broadcast(None, 'del_port', port)
Ejemplo n.º 19
0
def remove_port(port):  # {{{
    log('removing port %s' % port)
    if port not in ports:
        return
    if ports[port]:
        disable(ports[port], 'port is removed')
    del ports[port]
    broadcast(None, 'del_port', port)
Ejemplo n.º 20
0
 def remove_port(cls, port):  # {{{
     log('removing port %s' % port)
     if port not in ports:
         return
     if ports[port]:
         # Close serial port, in case it still exists.
         cls._disable('admin', port)
     del ports[port]
     cls._broadcast(None, 'del_port', port)
Ejemplo n.º 21
0
	def detect(cls, port): # {{{
		resumeinfo = [(yield), None]
		log('detecting printer on %s' % port)
		if port not in ports or ports[port] != None:
			log('port is not in detectable state')
			return
		ports[port] = False
		c = websocketd.call(resumeinfo, detect, port)
		while c(): c.args = (yield websocketd.WAIT)
Ejemplo n.º 22
0
	def remove_port(cls, port): # {{{
		log('removing port %s' % port)
		if port not in ports:
			return
		if ports[port]:
			# Close serial port, in case it still exists.
			cls._disable('admin', port)
		del ports[port]
		cls._broadcast(None, 'del_port', port)
Ejemplo n.º 23
0
	def die(self, reason = 'at request'): # {{{
		log('{} died {}.'.format(self.name, reason))
		self.process.kill()
		try:
			self.process.communicate()
		except:
			pass
		for t in range(3):
			for w in self.waiters[t]:
				self.waiters[t][w](False, 'Printer {} died {}'.format(self.name, reason))
Ejemplo n.º 24
0
	def make_orphan(self): # {{{
		if ports[self.port]:
			self.call('disconnect', ['admin'], {}, lambda cd, arg: None)
		# If there already is an orphan with the same uuid, kill the old orphan.
		for o in [x for x in orphans if orphans[x].uuid == self.uuid]:
			# This for loop always runs 0 or 1 times, never more.
			log('killing duplicate orphan')
			orphans[o].call('die', ('admin', 'replaced by connection with same uuid',), {}, lambda success, ret: None)
			del orphans[o]
		orphans[self.run_id] = self
		broadcast(None, 'del_printer', self.port)
Ejemplo n.º 25
0
    def post(self, connection):
        # Add to queue (POST).
        if 'file' not in connection.post[1] or 'machine' not in connection.post[
                0] or 'action' not in connection.post[0]:
            log('invalid post: {}'.format(connection.post))
            self.reply(connection, 400)
            return False
        machine = connection.post[0]['machine'][0]
        action = connection.post[0]['action'][0]
        if machine not in machines or not isinstance(machines[machine],
                                                     Machine):
            log('machine not found: %s' % machine)
            self.reply(connection, 404)
            return False
        # Count files, so we know when the connection should be closed.
        # Use a list to make it accessible from the callback.
        num = [len(connection.post[1]['file'])]
        for post in connection.post[1].pop('file'):

            def cb(success, ret, filename):
                self.reply(connection, 200 if success else 400,
                           b'' if ret is None else ret.encode('utf-8'),
                           'text/plain;charset=utf-8')
                os.unlink(filename)
                num[0] -= 1
                if num[0] == 0:
                    connection.socket.close()

            def cbwrap(filename):
                '''This function makes sure that filename gets its own scope and is not changed by the for loop.'''
                return lambda success, ret: cb(success, ret, filename)

            if action == 'queue_add':
                machines[machine].call(
                    'queue_add_POST',
                    [connection.data['role'], post[0], post[1]], {},
                    cbwrap(post[0]))
            elif action == 'probe_add':
                machines[machine].call(
                    'probe_add_POST',
                    [connection.data['role'], post[0], post[1]], {},
                    cbwrap(post[0]))
            elif action == 'audio_add':
                machines[machine].call(
                    'audio_add_POST',
                    [connection.data['role'], post[0], post[1]], {},
                    cbwrap(post[0]))
            elif action == 'import':
                machines[machine].call(
                    'import_POST', [connection.data['role'], post[0], post[1]],
                    {}, cbwrap(post[0]))
            else:
                cb(false, 'invalid POST action', post[0])
        return True
Ejemplo n.º 26
0
    def upload(self, port, board):  # {{{
        assert self.socket.data['role'] in ('benjamin', 'admin')
        assert ports[port] is None
        wake = (yield)
        command = self._get_command(board, port)
        data = ['']
        log('Flashing firmware: ' + ' '.join(command))
        process = subprocess.Popen(command,
                                   stdin=subprocess.PIPE,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.STDOUT,
                                   close_fds=True)

        def output(fd, cond):
            d = ''
            try:
                d = process.stdout.read().decode('utf-8')
            except:
                data[
                    0] += '\nError writing %s firmware: ' % board + traceback.format_exc(
                    )
                log(repr(data[0]))
                wake(data[0])
                return False
            if d != '':
                self._broadcast(None, 'message', port,
                                '\n'.join(data[0].split('\n')[-4:]))
                data[0] += d
                return True
            wake(data[0])
            return False

        fl = fcntl.fcntl(process.stdout.fileno(), fcntl.F_GETFL)
        fcntl.fcntl(process.stdout.fileno(), fcntl.F_SETFL, fl | os.O_NONBLOCK)
        GLib.io_add_watch(process.stdout,
                          GLib.IO_IN | GLib.IO_PRI | GLib.IO_HUP, output)
        self._broadcast(None, 'blocked', port,
                        'uploading firmware for %s' % board)
        self._broadcast(None, 'message', port, '')
        d = (yield)
        try:
            process.kill()  # In case it wasn't dead yet.
        except OSError:
            pass
        process.communicate()  # Clean up.
        self._broadcast(None, 'blocked', port, None)
        self._broadcast(None, 'message', port, '')
        if autodetect:
            websocketd.call(None, self.detect, port)
        if d:
            return 'firmware upload for %s: ' % board + d
        else:
            return 'firmware for %s successfully uploaded' % board
Ejemplo n.º 27
0
def add_port(port): # {{{
	if port in ports:
		log('already existing port %s cannot be added' % port)
		return
	if not re.match(config['whitelist'], port) or re.match(config['blacklist'], port) or re.match(config['add-blacklist'], port):
		#log('skipping blacklisted or non-whitelisted port %s' % port)
		return
	ports[port] = None
	broadcast(None, 'new_port', port, upload_options(port))
	broadcast(None, 'port_state', port, 0)
	if autodetect:
		websocketd.call(None, detect, port)
Ejemplo n.º 28
0
def add_port(port): # {{{
	if port in ports:
		log('already existing port %s cannot be added' % port)
		return
	if re.match(config['blacklist'], port) or re.match(config['add-blacklist'], port):
		#log('skipping blacklisted port %s' % port)
		return
	ports[port] = None
	broadcast(None, 'new_port', port)
	broadcast(None, 'port_state', port, 0)
	if autodetect:
		detect(port, 'admin')
Ejemplo n.º 29
0
	def add_port(cls, port): # {{{
		wake = (yield)
		if port in ports:
			log('already existing port %s cannot be added' % port)
			return
		if re.match(config['blacklist'], port) or re.match(config['add-blacklist'], port):
			#log('skipping blacklisted port %s' % port)
			return
		ports[port] = None
		cls._broadcast(None, 'new_port', port);
		if autodetect:
			return (yield from cls._generator_call(wake, cls.detect, port))
Ejemplo n.º 30
0
def add_port(port): # {{{
	if port in ports:
		log('already existing port %s cannot be added' % port)
		return
	if not re.match(config['whitelist'], port) or re.match(config['blacklist'], port) or re.match(config['add-blacklist'], port):
		#log('skipping blacklisted or non-whitelisted port %s' % port)
		return
	ports[port] = None
	broadcast(None, 'new_port', port, upload_options(port))
	broadcast(None, 'port_state', port, 0)
	if autodetect:
		websocketd.call(None, detect, port)
Ejemplo n.º 31
0
		def get_vars(success, vars):
			if not success:
				log('failed to get vars')
				return
			# The child has opened the port now; close our handle.
			if detectport is not None:
				log('Driver started; closing server port')
				detectport.close()
			self.uuid = vars['uuid']
			# Copy settings from orphan with the same run_id, then kill the orphan.
			if self.run_id in orphans and orphans[self.run_id].uuid == self.uuid:
				orphans[self.run_id].call('export_settings', ('admin',), {}, get_settings)
Ejemplo n.º 32
0
 def printer_input(self):  # {{{
     while self.process is not None:
         data = self.process.stdout.read()
         if data is None:
             #log('%s: no data now' % self.name)
             # No more data.
             return True
         if data == b'':
             # Connection closed.
             log('%s died.' % self.name)
             try:
                 self.process.communicate()  # Clean up the zombie.
             except:
                 pass
             for t in range(3):
                 for w in self.waiters[t]:
                     self.waiters[t][w](False, 'Printer died')
             disable('admin', self.port)
             return False
         self.buffer += data
         #log('printer input:' + repr(data))
         while b'\n'[0] in self.buffer:
             pos = self.buffer.index(b'\n'[0])
             line = self.buffer[:pos]
             self.buffer = self.buffer[pos + 1:]
             data = json.loads(line.decode('utf-8'))
             #log('printer command input:' + repr(data))
             if data[1] == 'broadcast':
                 broadcast(data[2], data[3], self.port, *(data[4:]))
             elif data[1] == 'disconnect':
                 # Don't remember a printer that hasn't sent its name yet.
                 port = self.port
                 ports[self.port] = None
                 broadcast(None, 'port_state', port, 0)
                 self.make_orphan()
                 if autodetect:
                     detect(self.port, 'admin')
             elif data[1] == 'error':
                 if data[0] is None:
                     # Error on command without id.
                     log('error on command without id: %s' % repr(data))
                 else:
                     self.waiters[0].pop(data[0])(False, data[2])
             elif data[1] == 'return':
                 self.waiters[0].pop(data[0])(True, data[2])
             elif data[1] == 'movecb':
                 self.waiters[1].pop(data[0])(True, data[2])
             elif data[1] == 'tempcb':
                 self.waiters[2].pop(data[0])(True, data[2])
             else:
                 raise AssertionError(
                     'invalid reply from printer process: %s' % repr(data))
Ejemplo n.º 33
0
		def get_vars(success, vars, cb = None):
			if not success:
				log('failed to get vars')
				return
			if self.uuid is None:
				log('new uuid:' + repr(vars['uuid']))
				self.uuid = vars['uuid']
			else:
				assert self.uuid == vars['uuid']
			self.detecting = False
			self.call('send_machine', ['admin', None], {}, lambda success, data: broadcast(None, 'port_state', port, 2))
			if cb is not None:
				cb()
Ejemplo n.º 34
0
		def get_vars(success, vars, cb = None):
			if not success:
				log('failed to get vars')
				return
			if self.uuid is None:
				log('new uuid:' + repr(vars['uuid']))
				self.uuid = vars['uuid']
			else:
				assert self.uuid == vars['uuid']
			self.detecting = False
			self.call('send_machine', ['admin', None], {}, lambda success, data: broadcast(None, 'port_state', port, 2))
			if cb is not None:
				cb()
Ejemplo n.º 35
0
 def add_port(cls, port):  # {{{
     wake = (yield)
     if port in ports:
         log('already existing port %s cannot be added' % port)
         return
     if re.match(config['blacklist'], port) or re.match(
             config['add-blacklist'], port):
         #log('skipping blacklisted port %s' % port)
         return
     ports[port] = None
     cls._broadcast(None, 'new_port', port)
     if autodetect:
         return (yield from cls._generator_call(wake, cls.detect, port))
Ejemplo n.º 36
0
	def add_port(cls, port): # {{{
		resumeinfo = [(yield), None]
		if port in ports:
			log('already existing port %s cannot be added' % port)
			return
		if re.match(config['blacklist'], port) or re.match(config['add-blacklist'], port):
			#log('skipping blacklisted port %s' % port)
			return
		ports[port] = None
		cls._broadcast(None, 'new_port', port);
		if autodetect:
			c = websocketd.call(resumeinfo, cls.detect, port)
			while c(): c.args = (yield websocketd.WAIT)
Ejemplo n.º 37
0
		def get_settings(success, settings):
			if not success:
				log('failed to get settings')
				return
			self.call('import_settings', ['admin', settings], {}, lambda success, ret: None)
			GLib.source_remove(orphans[self.run_id].input_handle)
			orphans[self.run_id].call('die', ('admin', 'replaced by new connection',), {}, lambda success, ret: None)
			try:
				orphans[self.run_id].process.kill()
				orphans[self.run_id].process.communicate()
			except OSError:
				pass
			del orphans[self.run_id]
Ejemplo n.º 38
0
def add_port(port):  # {{{
    if port in ports:
        log('already existing port %s cannot be added' % port)
        return
    if re.match(config['blacklist'], port) or re.match(config['add-blacklist'],
                                                       port):
        #log('skipping blacklisted port %s' % port)
        return
    ports[port] = None
    broadcast(None, 'new_port', port)
    broadcast(None, 'port_state', port, 0)
    if autodetect:
        detect(port, 'admin')
Ejemplo n.º 39
0
def disable(uuid, reason):  # {{{
    if uuid not in machines:
        log('not disabling nonexistent machine %s' % uuid)
        return
    p = machines[uuid]
    if p.port not in ports:
        log("not disabling machine which isn't enabled")
        return
    p.call('disconnect', ('admin', reason), {}, lambda success, ret: None)
    port = p.port
    ports[port] = None
    p.port = None
    broadcast(None, 'port_state', port, 0)
Ejemplo n.º 40
0
	def call(self, name, args, kargs, cb): # {{{
		data = json.dumps([self.next_mid, name, args, kargs]) + '\n'
		#log('calling %s on %d' % (repr(data), self.process.stdin.fileno()))
		try:
			self.process.stdin.write(data)
		except:
			log('killing printer handle because of IOError')
			#traceback.print_exc()
			cb(False, None)
			Connection._disable('admin', self.port)
			return
		self.waiters[0][self.next_mid] = cb
		self.next_mid += 1
Ejemplo n.º 41
0
def load(name, group): # {{{
	# Set default user data; can be replaced (or not returned) below.
	ret = default_user(group, name)
	if not os.path.exists(os.path.join(config['data'], 'users', group.lower())):
		debug(0, 'user.load called for nonexistent group {}:{}'.format(name, group))
		return None
	if not os.path.exists(os.path.join(config['data'], 'users', group.lower(), name.lower())):
		if os.path.exists(os.path.join(config['data'], 'users', group.lower(), 'Open')):
			# Create new user.
			save(ret)
		else:
			debug(0, 'user.load called for nonexistent user {}:{}'.format(name, group))
			return None
	if (name.lower(), group.lower()) in users:
		ret = users[(name.lower(), group.lower())]
	for ln in open(os.path.join(config['data'], 'users', group.lower(), name.lower()), errors = 'replace'):
		if ln.strip() == '':
			continue
		try:
			key, value = ln.strip().split('=', 1)
		except ValueError:
			log('Failed to parse line from user config for %s:%s: %s' % (name, group, ln.strip()))
			continue
		if key in unsaved:
			# This key should not have been in the file.
			continue
		if key in ('nosave', 'sandbox'):
			ret[key] = value == 'True'
			continue
		if key.startswith('answer:'):
			try:
				a, c, s, q = key.split(':', 3)
			except:
				log('Failed to parse answer key {}; ignoring'.format(key))
				continue
			if (c, s) not in ret['answers']:
				ret['answers'][(c, s)] = {}
			try:
				ret['answers'][(c, s)][q] = [json.loads(a) for a in value.split(';')]
				assert all('raw' in x for x in ret['answers'][(c, s)][q])
				assert all('style' in x for x in ret['answers'][(c, s)][q])
			except:
				ret['answers'][(c, s)][q] = [{'raw': a, 'style': []} for a in value.split(';')]
			continue
		ret[key] = value.rstrip('\n')
	# Make sure name and group match file location.
	if ret['filename'] != name.lower():
		ret['filename'] = name.lower()
	if ret['group'].casefold() != group.casefold():
		ret['group'] = group
	return ret
Ejemplo n.º 42
0
	def printer_input(self): # {{{
		while self.process is not None:
			data = self.process.stdout.read()
			if data is None:
				#log('%s: no data now' % self.name)
				# No more data.
				return True
			if data == b'':
				# Connection closed.
				log('%s died.' % self.name)
				try:
					self.process.communicate()	# Clean up the zombie.
				except:
					pass
				for t in range(3):
					for w in self.waiters[t]:
						self.waiters[t][w](False, 'Printer died')
				disable('admin', self.port)
				return False
			self.buffer += data
			#log('printer input:' + repr(data))
			while b'\n'[0] in self.buffer:
				pos = self.buffer.index(b'\n'[0])
				line = self.buffer[:pos]
				self.buffer = self.buffer[pos + 1:]
				data = json.loads(line.decode('utf-8'))
				#log('printer command input:' + repr(data))
				if data[1] == 'broadcast':
					broadcast(data[2], data[3], self.port, *(data[4:]))
				elif data[1] == 'disconnect':
					# Don't remember a printer that hasn't sent its name yet.
					port = self.port
					ports[self.port] = None
					broadcast(None, 'port_state', port, 0)
					self.make_orphan()
					if autodetect:
						detect(self.port, 'admin')
				elif data[1] == 'error':
					if data[0] is None:
						# Error on command without id.
						log('error on command without id: %s' % repr(data))
					else:
						self.waiters[0].pop(data[0])(False, data[2])
				elif data[1] == 'return':
					self.waiters[0].pop(data[0])(True, data[2])
				elif data[1] == 'movecb':
					self.waiters[1].pop(data[0])(True, data[2])
				elif data[1] == 'tempcb':
					self.waiters[2].pop(data[0])(True, data[2])
				else:
					raise AssertionError('invalid reply from printer process: %s' % repr(data))
Ejemplo n.º 43
0
		def timeout():
			id[1] += 1
			if id[1] >= 30:
				# Timeout.  Give up.
				GLib.source_remove(watcher)
				printer.close()
				log('Timeout waiting for printer on port %s; giving up.' % port)
				ports[port] = None
				return False
			if not id[2]:
				printer.write(protocol.single['ID'])
			else:
				id[2] = False
			return True
Ejemplo n.º 44
0
def print_done(port, completed, reason): # {{{
	Connection._broadcast(None, 'printing', port.port, False)
	if config['done']:
		cmd = config['done']
		cmd = cmd.replace('[[STATE]]', 'completed' if completed else 'aborted').replace('[[REASON]]', reason)
		log('running %s' % cmd)
		p = subprocess.Popen(cmd, stdout = subprocess.PIPE, shell = True, close_fds = True)
		def process_done(fd, cond):
			data = p.stdout.read()
			if data:
				return True
			log('Flashing done; return: %s' % repr(p.wait()))
			return False
		GLib.io_add_watch(p.stdout.fileno(), GLib.IO_IN, process_done)
Ejemplo n.º 45
0
 def read(self, line):  # {{{
     if line.strip() == '':
         return
     try:
         action, dev = line.split(None, 1)
     except:
         log('invalid command on admin socket: %s' % line)
         return
     if action == 'add':
         add_port(dev.strip())
     elif action == 'remove':
         remove_port(dev.strip())
     else:
         log('invalid action on admin socket: %s' % line)
Ejemplo n.º 46
0
	def read(self, line): # {{{
		if line.strip() == '':
			return
		try:
			action, dev = line.split(None, 1)
		except:
			log('invalid command on admin socket: %s' % line)
			return
		if action == 'add':
			add_port(dev.strip())
		elif action == 'remove':
			remove_port(dev.strip())
		else:
			log('invalid action on admin socket: %s' % line)
Ejemplo n.º 47
0
 def call(self, name, args, kargs, cb):  # {{{
     data = json.dumps([self.next_mid, name, args, kargs]) + '\n'
     #log('calling %s on %d' % (repr(data), self.process.stdin.fileno()))
     try:
         self.process.stdin.write(data.encode('utf-8'))
         self.process.stdin.flush()
     except:
         log('killing printer handle because of IOError')
         #traceback.print_exc()
         cb(False, None)
         Connection._disable('admin', self.port)
         return
     self.waiters[0][self.next_mid] = cb
     self.next_mid += 1
Ejemplo n.º 48
0
 def make_orphan(self):  # {{{
     if ports[self.port]:
         self.call('disconnect', ['admin'], {}, lambda cd, arg: None)
     # If there already is an orphan with the same uuid, kill the old orphan.
     for o in [x for x in orphans if orphans[x].uuid == self.uuid]:
         # This for loop always runs 0 or 1 times, never more.
         log('killing duplicate orphan')
         orphans[o].call('die', (
             'admin',
             'replaced by connection with same uuid',
         ), {}, lambda success, ret: None)
         del orphans[o]
     orphans[self.run_id] = self
     broadcast(None, 'del_printer', self.port)
Ejemplo n.º 49
0
 def get_vars(success, vars):
     if not success:
         log('failed to get vars')
         return
     # The child has opened the port now; close our handle.
     if detectport is not None:
         log('Driver started; closing server port')
         detectport.close()
     self.uuid = vars['uuid']
     # Copy settings from orphan with the same run_id, then kill the orphan.
     if self.run_id in orphans and orphans[
             self.run_id].uuid == self.uuid:
         orphans[self.run_id].call('export_settings', ('admin', ), {},
                                   get_settings)
Ejemplo n.º 50
0
 def die(self, reason='at request'):  # {{{
     log('{} died {}.'.format(self.name, reason))
     try:
         self.process.kill()
     except:
         pass
     try:
         self.process.communicate()
     except:
         pass
     for t in range(3):
         for w in self.waiters[t]:
             self.waiters[t][w](False, 'Printer {} died {}'.format(
                 self.name, reason))
Ejemplo n.º 51
0
		def boot_printer_input():
			id[2] = True
			ids = [protocol.single[code][0] for code in ('ID', 'STARTUP')]
			# CMD:1 ID:8 Checksum:3
			while len(id[0]) < 12:
				try:
					data = printer.read(12 - len(id[0]))
				except OSError:
					continue
				except IOError:
					continue
				id[0] += data
				#log('incomplete id: ' + id[0])
				if len(id[0]) < 12:
					return True
				if id[0][0] not in ids or not protocol.check(id[0]):
					log('skip non-id: %s (%s)' % (''.join('%02x' % x for x in id[0]), repr(id[0])))
					f = len(id[0])
					for start in ids:
						if start in id[0][1:]:
							p = id[0].index(bytes((start,)))
							if p < f:
								f = p
							log('Keeping some')
					if f == 0:
						f = 1
					id[0] = id[0][f:]
					return True
			# We have something to handle; cancel the timeout, but keep the serial port open to avoid a reset. (I don't think this even works, but it doesn't hurt.)
			websocketd.remove_timeout(timeout_handle[0])
			# This printer was running and tried to send an id.  Check the id.
			id[0] = id[0][1:9]
			if id[0] in orphans:
				log('accepting orphan %s on %s' % (''.join('%02x' % x for x in id[0]), port))
				ports[port] = orphans.pop(id[0])
				ports[port].port = port
				def close_port(success, data):
					log('reconnect complete; closing server port')
					printer.close()
				log('reconnecting %s' % port)
				ports[port].call('reconnect', ['admin', port], {}, lambda success, ret: ports[port].call('send_printer', ['admin', None], {}, close_port) if success else close_port)
				broadcast(None, 'port_state', port, 2)
				return False
			run_id = nextid()
			log('accepting unknown printer on port %s (id %s)' % (port, ''.join('%02x' % x for x in run_id)))
			#log('orphans: %s' % repr(tuple(orphans.keys())))
			process = subprocess.Popen((fhs.read_data('driver.py', opened = False), '--cdriver', fhs.read_data('franklin-cdriver', opened = False), '--port', port, '--run-id', run_id, '--allow-system', config['allow-system']) + (('--system',) if fhs.is_system else ()), stdin = subprocess.PIPE, stdout = subprocess.PIPE, close_fds = True)
			ports[port] = Port(port, process, printer, run_id)
			return False
Ejemplo n.º 52
0
def read_boards():  # {{{
    boards = {}
    for d in fhs.read_data('hardware',
                           packagename='arduino',
                           dir=True,
                           multiple=True):
        for board in os.listdir(d):
            boards_txt = os.path.join(d, board, 'boards' + os.extsep + 'txt')
            if not os.path.exists(boards_txt):
                continue
            with open(boards_txt) as b:
                for line in b:
                    if line.startswith('#') or line.strip() == '':
                        continue
                    parse = re.match('([^.=]+)\.([^=]+)=(.*)$', line.strip())
                    if parse is None:
                        log('Warning: invalid line in %s: %s' %
                            (boards_txt, line.strip()))
                        continue
                    tag, option, value = parse.groups()
                    if tag not in boards:
                        boards[tag] = {}
                    if option in boards[tag]:
                        if boards[tag][option] != value:
                            log('%s: duplicate tag %s.%s with different value (%s != %s); using %s'
                                % (boards_txt, tag, option, value,
                                   boards[tag][option], boards[tag][option]))
                            continue
                    boards[tag][option] = value
    for tag in tuple(boards.keys()):
        if 'name' not in boards[tag]:
            boards[tag]['name'] = tag
        if any(x not in boards[tag]
               for x in ('upload.protocol', 'upload.speed', 'build.mcu',
                         'upload.maximum_size')):
            #log('skipping %s because hardware information is incomplete (%s)' % (boards[tag]['name'], repr(boards[tag])))
            del boards[tag]
            continue
        if int(boards[tag]['upload.maximum_size']) < 30000:
            # Not enough memory; don't complain about skipping this board.
            del boards[tag]
            continue
        if fhs.read_data(os.path.join(
                'firmware', boards[tag]['build.mcu'] + os.extsep + 'hex'),
                         opened=False) is None:
            #log('skipping %s because firmware for %s is not installed' % (boards[tag]['name'], boards[tag]['build.mcu']))
            del boards[tag]
            continue
    return boards
Ejemplo n.º 53
0
	def close(self):
		if self.game.Public.name not in instances:
			# Already closed.
			return
		log("stopped instance '%s'" % self.game.Public.name)
		del instances[self.game.Public.name]
		for c in connections:
			if connections[c].instance != self:
				continue
			leave({'connection': connections[c]})
		self.game.Public._die()
		for p in self.game.players:
			p.Private._die()
		if self is not title_game:
			title_game.game.Public.games.remove(self.game.Public.name)
Ejemplo n.º 54
0
 def timeout():
     id[1] += 1
     if id[1] >= 30:
         # Timeout.  Give up.
         GLib.source_remove(watcher)
         printer.close()
         log('Timeout waiting for printer on port %s; giving up.' %
             port)
         ports[port] = None
         return False
     if not id[2]:
         printer.write(protocol.single['ID'])
     else:
         id[2] = False
     return True
Ejemplo n.º 55
0
		def output():
			d = ''
			try:
				d = process.stdout.read().decode('utf-8')
			except:
				data[0] += '\nError writing %s firmware: ' % board + traceback.format_exc()
				log(repr(data[0]))
				wake(data[0])
				return False
			if d != '':
				#broadcast(None, 'message', port, '\n'.join(data[0].split('\n')[-4:]))
				data[0] += d
				return True
			wake(data[0])
			return False
Ejemplo n.º 56
0
		def timeout():
			id[1] += 1
			if id[1] >= 30:
				# Timeout.  Give up.
				websocketd.remove_read(watcher)
				machine.close()
				log('Timeout waiting for machine on port %s; giving up.' % port)
				ports[port] = None
				broadcast(None, 'port_state', port, 0)
				return
			if not id[2]:
				machine.write(protocol.single['ID'])
			else:
				id[2] = False
			timeout_handle[0] = websocketd.add_timeout(time.time() + .5, timeout)
Ejemplo n.º 57
0
		def output(fd, cond):
			d = ''
			try:
				d = process.stdout.read()
			except:
				data[0] += '\nError writing %s firmware: ' % board + traceback.format_exc()
				log(repr(data[0]))
				resumeinfo[0](data[0])
				return False
			if d != '':
				self._broadcast(None, 'message', port, '\n'.join(data[0].split('\n')[-4:]))
				data[0] += d
				return True
			resumeinfo[0](data[0])
			return False
Ejemplo n.º 58
0
		def output():
			d = ''
			try:
				d = process.stdout.read().decode('utf-8')
			except:
				data[0] += '\nError writing %s firmware: ' % board + traceback.format_exc()
				log(repr(data[0]))
				wake(data[0])
				return False
			if d != '':
				#broadcast(None, 'message', port, '\n'.join(data[0].split('\n')[-4:]))
				data[0] += d
				return True
			wake(data[0])
			return False
Ejemplo n.º 59
0
		def get_vars(success, vars):
			if not success:
				log('failed to get vars')
				return
			# The child has opened the port now; close our handle.
			if detectport is not None:
				log('Driver started; closing server port')
				detectport.close()
			self.uuid = vars['uuid']
			# Copy settings from orphan with the same run_id, then kill the orphan.
			if self.run_id in orphans and orphans[self.run_id].uuid == self.uuid:
				orphans[self.run_id].call('export_settings', ('admin',), {}, get_settings)
			else:
				self.detecting = False
				self.call('send_printer', ['admin', None], {}, lambda success, data: broadcast(None, 'port_state', port, 2))
Ejemplo n.º 60
0
		def timeout():
			id[1] += 1
			if id[1] >= 30:
				# Timeout.  Give up.
				websocketd.remove_read(watcher)
				machine.close()
				log('Timeout waiting for machine on port %s; giving up.' % port)
				ports[port] = None
				broadcast(None, 'port_state', port, 0)
				return
			if not id[2]:
				machine.write(protocol.single['ID'])
			else:
				id[2] = False
			timeout_handle[0] = websocketd.add_timeout(time.time() + .5, timeout)