1import logging 2import os 3import pickle 4import struct 5import sys 6 7import pyinsane2.sane.abstract as pyinsane 8 9 10logger = logging.getLogger("Pyinsane_daemon") 11 12 13device_cache = {} 14scan_sessions = {} 15 16 17def get_devices(local_only): 18 global device_cache 19 20 devices = pyinsane.get_devices(local_only) 21 device_cache = {} 22 for device in devices: 23 device_cache[device.name] = device 24 return devices 25 26 27def get_device(scanner_name): 28 global device_cache 29 if scanner_name in device_cache: 30 return device_cache[scanner_name] 31 scanner = pyinsane.Scanner(scanner_name) 32 device_cache[scanner_name] = scanner 33 return scanner 34 35 36def get_options(scanner_name): 37 return get_device(scanner_name).options 38 39 40def get_option_value(scanner_name, option_name): 41 return get_device(scanner_name).options[option_name].value 42 43 44def set_option_value(scanner_name, option_name, option_value): 45 get_device(scanner_name).options[option_name].value = option_value 46 47 48def make_scan_session(scanner_name, multiple=False): 49 global scan_sessions 50 51 scan_session = get_device(scanner_name).scan(multiple) 52 scan_sessions[scanner_name] = scan_session 53 return scan_session 54 55 56def get_images(scanner_name): 57 global scan_sessions 58 imgs = scan_sessions[scanner_name].images 59 imgs = [(img.mode, img.size, img.tobytes()) for img in imgs] 60 return imgs 61 62 63def scan_read(scanner_name): 64 global scan_sessions 65 return scan_sessions[scanner_name].scan.read() 66 67 68def get_available_lines(scanner_name): 69 global scan_sessions 70 return scan_sessions[scanner_name].scan.available_lines 71 72 73def get_expected_size(scanner_name): 74 global scan_sessions 75 return scan_sessions[scanner_name].scan.expected_size 76 77 78def get_image(scanner_name, start_line, end_line): 79 global scan_sessions 80 img = scan_sessions[scanner_name].scan.get_image(start_line, end_line) 81 return (img.mode, img.size, img.tobytes()) 82 83 84def cancel(scanner_name): 85 global scan_sessions 86 return scan_sessions[scanner_name].scan.cancel() 87 88 89def exit(): 90 pass 91 92 93COMMANDS = { 94 "get_devices": get_devices, 95 "get_options": get_options, 96 "get_option_value": get_option_value, 97 "set_option_value": set_option_value, 98 "scan": make_scan_session, 99 "get_images": get_images, 100 "scan_read": scan_read, 101 "scan_get_available_lines": get_available_lines, 102 "scan_get_expected_size": get_expected_size, 103 "scan_get_image": get_image, 104 "scan_cancel": cancel, 105 "exit": exit, 106} 107 108 109def main_loop(fifo_dir, fifo_filepaths): 110 global COMMANDS 111 112 pyinsane.init() 113 114 length_size = len(struct.pack("i", 0)) 115 fifo_c2s = os.open(fifo_filepaths[0], os.O_RDONLY) 116 fifo_s2c = os.open(fifo_filepaths[1], os.O_WRONLY) 117 118 try: 119 logger.info("Ready") 120 121 while True: 122 length = os.read(fifo_c2s, length_size) 123 if length == b'': 124 break 125 length = struct.unpack("i", length)[0] 126 cmd = os.read(fifo_c2s, length) 127 if cmd == b'': 128 break 129 assert(len(cmd) == length) 130 cmd = pickle.loads(cmd) 131 132 logger.debug("> {}".format(cmd['command'])) 133 f = COMMANDS[cmd['command']] 134 result = {} 135 try: 136 result['out'] = f(*cmd['args'], **cmd['kwargs']) 137 except BaseException as exc: 138 if (not isinstance(exc, EOFError) and 139 not isinstance(exc, StopIteration)): 140 logger.warning("Exception", exc_info=exc) 141 result['exception'] = str(exc.__class__.__name__) 142 result['exception_args'] = exc.args 143 logger.debug("< {}".format(result)) 144 145 result = pickle.dumps(result) 146 length = len(result) 147 length = struct.pack("i", length) 148 os.write(fifo_s2c, length) 149 os.write(fifo_s2c, result) 150 151 if cmd['command'] == 'exit': 152 break 153 finally: 154 os.close(fifo_s2c) 155 os.close(fifo_c2s) 156 157 logger.info("Daemon stopped") 158 159 160if __name__ == "__main__": 161 formatter = logging.Formatter( 162 '%(levelname)-6s %(name)-10s %(message)s' 163 ) 164 log = logging.getLogger() 165 handler = logging.StreamHandler() 166 handler.setFormatter(formatter) 167 log.addHandler(handler) 168 log.setLevel(logging.INFO) 169 170 main_loop(sys.argv[1], sys.argv[2:4]) 171