server.py 4.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. # SPDX-License-Identifier: Apache-2.0
  2. # Copyright 2020 Contributors to OpenLEADR
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. # http://www.apache.org/licenses/LICENSE-2.0
  7. # Unless required by applicable law or agreed to in writing, software
  8. # distributed under the License is distributed on an "AS IS" BASIS,
  9. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. # See the License for the specific language governing permissions and
  11. # limitations under the License.
  12. from aiohttp import web
  13. from openleadr.service import EventService, PollService, RegistrationService, ReportService, OptService, VTNService
  14. from openleadr.messaging import create_message, parse_message
  15. from openleadr.utils import certificate_fingerprint
  16. from functools import partial
  17. class OpenADRServer:
  18. _MAP = {'on_created_event': EventService,
  19. 'on_request_event': EventService,
  20. 'on_register_report': ReportService,
  21. 'on_create_report': ReportService,
  22. 'on_created_report': ReportService,
  23. 'on_request_report': ReportService,
  24. 'on_update_report': ReportService,
  25. 'on_poll': PollService,
  26. 'on_query_registration': RegistrationService,
  27. 'on_create_party_registration': RegistrationService,
  28. 'on_cancel_party_registration': RegistrationService}
  29. def __init__(self, vtn_id, cert=None, key=None, passphrase=None, fingerprint_lookup=None):
  30. """
  31. Create a new OpenADR VTN (Server).
  32. :param vtn_id string: An identifier string for this VTN. This is how you identify yourself to the VENs that talk to you.
  33. :param cert string: Path to the PEM-formatted certificate file that is used to sign outgoing messages
  34. :param key string: Path to the PEM-formatted private key file that is used to sign outgoing messages
  35. :param passphrase string: The passphrase used to decrypt the private key file
  36. :param fingerprint_lookup callable: A callable that receives a ven_id and should return the registered fingerprint for that VEN.
  37. You should receive these fingerprints outside of OpenADR and configure them manually.
  38. """
  39. self.app = web.Application()
  40. self.services = {'event_service': EventService(vtn_id),
  41. 'report_service': ReportService(vtn_id),
  42. 'poll_service': PollService(vtn_id),
  43. 'opt_service': OptService(vtn_id),
  44. 'registration_service': RegistrationService(vtn_id)}
  45. self.app.add_routes([web.post(f"/OpenADR2/Simple/2.0b/{s.__service_name__}", s.handler) for s in self.services.values()])
  46. # Configure message signing
  47. if cert and key:
  48. with open(cert, "rb") as file:
  49. cert = file.read()
  50. with open(key, "rb") as file:
  51. key = file.read()
  52. print("*" * 80)
  53. print("Your VTN Certificate Fingerprint is", certificate_fingerprint(cert))
  54. print("Please deliver this fingerprint to the VTN you are connecting to.")
  55. print("You do not need to keep this a secret.")
  56. print("*" * 80)
  57. VTNService._create_message = partial(create_message, cert=cert, key=key, passphrase=passphrase)
  58. VTNService._parse_message = partial(parse_message, fingerprint_lookup=fingerprint_lookup)
  59. self.__setattr__ = self.add_handler
  60. def run(self):
  61. """
  62. Starts the asyncio-loop and runs the server in it. This function is
  63. blocking. For other ways to run the server in a more flexible context,
  64. please refer to the `aiohttp documentation
  65. <https://docs.aiohttp.org/en/stable/web_advanced.html#aiohttp-web-app-runners>`_.
  66. """
  67. web.run_app(self.app)
  68. def add_handler(self, name, func):
  69. """
  70. Add a handler to the OpenADRServer.
  71. :param name string: The name for this handler. Should be one of: on_created_event, on_request_event, on_register_report, on_create_report, on_created_report, on_request_report, on_update_report, on_poll, on_query_registration, on_create_party_registration, on_cancel_party_registration.
  72. :param func coroutine: A coroutine that handles this event. It receives the message, and should return the contents of a response.
  73. """
  74. print("Called add_handler", name, func)
  75. if name in self._MAP:
  76. setattr(self._MAP[name], name, staticmethod(func))
  77. else:
  78. raise NameError(f"Unknown handler {name}. Correct handler names are: {self._MAP.keys()}")