def test_oadr_event_targets_and_targets_by_type(): event = objects.Event( event_descriptor=objects.EventDescriptor( event_id=1, modification_number=0, market_context='MarketContext1', event_status=enums.EVENT_STATUS.NEAR), active_period=objects.ActivePeriod(dtstart=datetime.now(), duration=timedelta(minutes=10)), event_signals=[ objects.EventSignal(intervals=[ objects.Interval(dtstart=datetime.now(), duration=timedelta(minutes=5), uid=0, signal_payload=1), objects.Interval(dtstart=datetime.now(), duration=timedelta(minutes=5), uid=1, signal_payload=2) ], targets=[objects.Target(ven_id='1234')], signal_name=enums.SIGNAL_NAME.LOAD_CONTROL, signal_type=enums.SIGNAL_TYPE.LEVEL, signal_id=1, current_value=0) ], targets=[{ 'ven_id': 'ven123' }], targets_by_type={'ven_id': ['ven123']}) msg = create_message('oadrDistributeEvent', events=[event]) validate_xml_schema(ensure_bytes(msg)) message_type, message_payload = parse_message(msg)
async def _perform_request(self, service, message): await self._ensure_client_session() logger.debug(f"Client is sending {message}") url = f"{self.vtn_url}/{service}" try: async with self.client_session.post(url, data=message) as req: content = await req.read() if req.status != HTTPStatus.OK: logger.warning( f"Non-OK status {req.status} when performing a request to {url} " f"with data {message}: {req.status} {content.decode('utf-8')}" ) return None, {} logger.debug(content.decode('utf-8')) except aiohttp.client_exceptions.ClientConnectorError as err: # Could not connect to server logger.error( f"Could not connect to server with URL {self.vtn_url}:") logger.error(f"{err.__class__.__name__}: {str(err)}") return None, {} except Exception as err: logger.error(f"Request error {err.__class__.__name__}:{err}") return None, {} if len(content) == 0: return None try: tree = validate_xml_schema(content) if self.vtn_fingerprint: validate_xml_signature(tree) message_type, message_payload = parse_message(content) except XMLSyntaxError as err: logger.warning( f"Incoming message did not pass XML schema validation: {err}") return None, {} except errors.FingerprintMismatch as err: logger.warning(err) return None, {} except InvalidSignature: logger.warning("Incoming message had invalid signature, ignoring.") return None, {} except Exception as err: logger.error( f"The incoming message could not be parsed or validated: {err}" ) return None, {} if 'response' in message_payload and 'response_code' in message_payload[ 'response']: if message_payload['response']['response_code'] != 200: logger.warning( "We got a non-OK OpenADR response from the server: " f"{message_payload['response']['response_code']}: " f"{message_payload['response']['response_description']}") return message_type, message_payload
def test_message(message_type, data): # file = open('representations.rst', 'a') # print(f".. _{message_type}:", file=file) # print("", file=file) # print(message_type, file=file) # print("="*len(message_type), file=file) # print("", file=file) # print("OpenADR payload:", file=file) # print("", file=file) # print(".. code-block:: xml", file=file) # print(" ", file=file) message = create_message(message_type, **data) # message = re.sub(r"\s\s+","",message) # message = message.replace("\n","") # xml_lines = etree.tostring(etree.fromstring(message.replace('\n', '').encode('utf-8')), pretty_print=True).decode('utf-8').splitlines() # for line in xml_lines: # print(" " + line, file=file) # print("", file=file) # print("OpenLEADR representation:", file=file) # print(" ", file=file) # print(".. code-block:: python3", file=file) # print(" ", file=file) validate_xml_schema(message) parsed = parse_message(message)[1] # dict_lines = pformat(parsed).splitlines() # for line in dict_lines: # print(" " + line, file=file) # print("", file=file) # print("", file=file) if message_type == 'oadrRegisterReport': for report in data['reports']: for rd in report['report_descriptions']: if 'measurement' in rd: rd['measurement'].pop('ns') if message_type == 'oadrDistributeEvent': for event in data['events']: for signal in event['event_signals']: if 'measurement' in signal: signal['measurement'].pop('ns') assert parsed == data
async def handler(self, request): """ Handle all incoming POST requests. """ try: # Check the Content-Type header content_type = request.headers.get('content-type', '') if not content_type.lower().startswith("application/xml"): raise errors.HTTPError(status=HTTPStatus.BAD_REQUEST, description="The Content-Type header must be application/xml; " f"you provided {request.headers.get('content-type', '')}") content = await request.read() hooks.call('before_parse', content) # Validate the message to the XML Schema message_tree = validate_xml_schema(content) # Parse the message to a type and payload dict message_type, message_payload = parse_message(content) if message_type == 'oadrResponse': raise errors.SendEmptyHTTPResponse() if 'vtn_id' in message_payload \ and message_payload['vtn_id'] is not None \ and message_payload['vtn_id'] != self.vtn_id: raise errors.InvalidIdError(f"The supplied vtnID is invalid. It should be '{self.vtn_id}', " f"you supplied {message_payload['vtn_id']}.") # Check if we know this VEN, ask for reregistration otherwise if message_type not in ('oadrCreatePartyRegistration', 'oadrQueryRegistration') \ and 'ven_id' in message_payload and hasattr(self, 'ven_lookup'): result = await utils.await_if_required(self.ven_lookup(ven_id=message_payload['ven_id'])) if result is None or result.get('registration_id', None) is None: raise errors.RequestReregistration(message_payload['ven_id']) # Authenticate the message if request.secure and 'ven_id' in message_payload: if hasattr(self, 'fingerprint_lookup'): await authenticate_message(request, message_tree, message_payload, fingerprint_lookup=self.fingerprint_lookup) elif hasattr(self, 'ven_lookup'): await authenticate_message(request, message_tree, message_payload, ven_lookup=self.ven_lookup) else: logger.error("Could not authenticate this VEN because " "you did not provide a 'ven_lookup' function. Please see " "https://openleadr.org/docs/server.html#signing-messages for info.") # Pass the message off to the handler and get the response type and payload try: # Add the request fingerprint to the message so that the handler can check for it. if request.secure and message_type == 'oadrCreatePartyRegistration': message_payload['fingerprint'] = utils.get_cert_fingerprint_from_request(request) response_type, response_payload = await self.handle_message(message_type, message_payload) except Exception as err: logger.error("An exception occurred during the execution of your " f"{self.__class__.__name__} handler: " f"{err.__class__.__name__}: {err}") raise err if 'response' not in response_payload: response_payload['response'] = {'response_code': 200, 'response_description': 'OK', 'request_id': message_payload.get('request_id')} response_payload['vtn_id'] = self.vtn_id if 'ven_id' not in response_payload: response_payload['ven_id'] = message_payload.get('ven_id') except errors.RequestReregistration as err: response_type = 'oadrRequestReregistration' response_payload = {'ven_id': err.ven_id} msg = self._create_message(response_type, **response_payload) response = web.Response(text=msg, status=HTTPStatus.OK, content_type='application/xml') except errors.SendEmptyHTTPResponse: response = web.Response(text='', status=HTTPStatus.OK, content_type='application/xml') except errors.ProtocolError as err: # In case of an OpenADR error, return a valid OpenADR message response_type, response_payload = self.error_response(message_type, err.response_code, err.response_description) msg = self._create_message(response_type, **response_payload) response = web.Response(text=msg, status=HTTPStatus.OK, content_type='application/xml') except errors.HTTPError as err: # If we throw a http-related error, deal with it here response = web.Response(text=err.response_description, status=err.response_code) except XMLSyntaxError as err: logger.warning(f"XML schema validation of incoming message failed: {err}.") response = web.Response(text=f'XML failed validation: {err}', status=HTTPStatus.BAD_REQUEST) except errors.FingerprintMismatch as err: logger.warning(err) response = web.Response(text=str(err), status=HTTPStatus.FORBIDDEN) except InvalidSignature: logger.warning("Incoming message had invalid signature, ignoring.") response = web.Response(text='Invalid Signature', status=HTTPStatus.FORBIDDEN) except Exception as err: # In case of some other error, return a HTTP 500 logger.error(f"The VTN server encountered an error: {err.__class__.__name__}: {err}") response = web.Response(status=HTTPStatus.INTERNAL_SERVER_ERROR) else: # We've successfully handled this message msg = self._create_message(response_type, **response_payload) response = web.Response(text=msg, status=HTTPStatus.OK, content_type='application/xml') hooks.call('before_respond', response.text) return response
def test_message(msg_type, payload): message = create_message(msg_type, **payload) print(message) tree = validate_xml_schema(ensure_bytes(message))