def handle_move(event, destinations, db_path, cli_config, logger): """Handler for evt.EVT_C_MOVE. Parameters ---------- event : pynetdicom.events.Event The C-MOVE request :class:`~pynetdicom.events.Event`. destinations : dict A :class:`dict` containing know move destinations as ``{b'AE_TITLE: (addr, port)}`` db_path : str The database path to use with create_engine(). cli_config : dict A :class:`dict` containing configuration settings passed via CLI. logger : logging.Logger The application's logger. Yields ------ (str, int) or (None, None) The (IP address, port) of the *Move Destination* (if known). int The number of sub-operations required to complete the request. int or pydicom.dataset.Dataset, pydicom.dataset.Dataset or None The C-MOVE response's *Status* and if the *Status* is pending then the dataset to be sent, otherwise ``None``. """ requestor = event.assoc.requestor timestamp = event.timestamp.strftime("%Y-%m-%d %H:%M:%S") addr, port = requestor.address, requestor.port logger.info(f"Received C-MOVE request from {addr}:{port} at {timestamp} " f"with move destination {event.move_destination}") # Unknown `Move Destination` try: addr, port = destinations[event.move_destination] except KeyError: logger.info('No matching move destination in the configuration') yield None, None return model = event.request.AffectedSOPClassUID engine = create_engine(db_path) with engine.connect() as conn: Session = sessionmaker(bind=engine) session = Session() # Search database using Identifier as the query try: matches = search(model, event.identifier, session) except InvalidIdentifier as exc: session.rollback() logger.error('Invalid C-MOVE Identifier received') logger.error(str(exc)) yield 0xA900, None return except Exception as exc: session.rollback() logger.error('Exception occurred while querying database') logger.exception(exc) yield 0xC520, None return finally: session.close() # Yield `Move Destination` IP and port, plus required contexts # We should be able to reduce the number of contexts by using the # implicit context conversion between: # implicit VR <-> explicit VR <-> deflated transfer syntaxes contexts = list(set([ii.context for ii in matches])) yield addr, port, {'contexts': contexts[:128]} # Yield number of sub-operations yield len(matches) # Yield results for match in matches: if event.is_cancelled: yield 0xFE00, None return try: ds = dcmread(match.filename) except Exception as exc: logger.error(f"Error reading file: {fpath}") logger.exception(exc) yield 0xC521, None yield 0xFF00, ds
def handle_find(event, db_path, cli_config, logger): """Handler for evt.EVT_C_FIND. Parameters ---------- event : pynetdicom.events.Event The C-FIND request :class:`~pynetdicom.events.Event`. db_path : str The database path to use with create_engine(). cli_config : dict A :class:`dict` containing configuration settings passed via CLI. logger : logging.Logger The application's logger. Yields ------ int or pydicom.dataset.Dataset, pydicom.dataset.Dataset or None The C-FIND response's *Status* and if the *Status* is pending then the dataset to be sent, otherwise ``None``. """ requestor = event.assoc.requestor timestamp = event.timestamp.strftime("%Y-%m-%d %H:%M:%S") addr, port = requestor.address, requestor.port logger.info(f"Received C-FIND request from {addr}:{port} at {timestamp}") model = event.request.AffectedSOPClassUID engine = create_engine(db_path) with engine.connect() as conn: Session = sessionmaker(bind=engine) session = Session() # Search database using Identifier as the query try: matches = search(model, event.identifier, session) except InvalidIdentifier as exc: session.rollback() logger.error('Invalid C-FIND Identifier received') logger.error(str(exc)) yield 0xA900, None return except Exception as exc: session.rollback() logger.error('Exception occurred while querying database') logger.exception(exc) yield 0xC320, None return finally: session.close() # Yield results for match in matches: if event.is_cancelled: yield 0xFE00, None return try: response = match.as_identifier(event.identifier, model) response.RetrieveAETitle = event.assoc.ae.ae_title except Exception as exc: logger.error("Error creating response Identifier") logger.exception(exc) yield 0xC322, None yield 0xFF00, response
def handle_get(event, db_path, cli_config, logger): """Handler for evt.EVT_C_GET. Parameters ---------- event : pynetdicom.events.Event The C-GET request :class:`~pynetdicom.events.Event`. db_path : str The database path to use with create_engine(). cli_config : dict A :class:`dict` containing configuration settings passed via CLI. logger : logging.Logger The application's logger. Yields ------ int The number of sub-operations required to complete the request. int or pydicom.dataset.Dataset, pydicom.dataset.Dataset or None The C-GET response's *Status* and if the *Status* is pending then the dataset to be sent, otherwise ``None``. """ requestor = event.assoc.requestor timestamp = event.timestamp.strftime("%Y-%m-%d %H:%M:%S") addr, port = requestor.address, requestor.port logger.info(f"Received C-GET request from {addr}:{port} at {timestamp}") model = event.request.AffectedSOPClassUID engine = create_engine(db_path) with engine.connect() as conn: Session = sessionmaker(bind=engine) session = Session() # Search database using Identifier as the query try: matches = search(model, event.identifier, session) except InvalidIdentifier as exc: session.rollback() logger.error("Invalid C-GET Identifier received") logger.error(str(exc)) yield 0xA900, None return except Exception as exc: session.rollback() logger.error("Exception occurred while querying database") logger.exception(exc) yield 0xC420, None return finally: session.close() # Yield number of sub-operations yield len(matches) # Yield results for match in matches: if event.is_cancelled: yield 0xFE00, None return try: ds = dcmread(match.filename) except Exception as exc: logger.error(f"Error reading file: {match.filename}") logger.exception(exc) yield 0xC421, None yield 0xFF00, ds