server.py 4.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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 functools import partial
  16. class OpenADRServer:
  17. _MAP = {'on_created_event': EventService,
  18. 'on_request_event': EventService,
  19. 'on_register_report': ReportService,
  20. 'on_create_report': ReportService,
  21. 'on_created_report': ReportService,
  22. 'on_request_report': ReportService,
  23. 'on_update_report': ReportService,
  24. 'on_poll': PollService,
  25. 'on_query_registration': RegistrationService,
  26. 'on_create_party_registration': RegistrationService,
  27. 'on_cancel_party_registration': RegistrationService}
  28. def __init__(self, vtn_id, cert=None, key=None, passphrase=None, fingerprint_lookup=None):
  29. """
  30. Create a new OpenADR VTN (Server).
  31. :param vtn_id string: An identifier string for this VTN. This is how you identify yourself to the VENs that talk to you.
  32. :param cert string: Path to the PEM-formatted certificate file that is used to sign outgoing messages
  33. :param key string: Path to the PEM-formatted private key file that is used to sign outgoing messages
  34. :param passphrase string: The passphrase used to decrypt the private key file
  35. :param fingerprint_lookup callable: A callable that receives a ven_id and should return the registered fingerprint for that VEN.
  36. You should receive these fingerprints outside of OpenADR and configure them manually.
  37. """
  38. self.app = web.Application()
  39. self.services = {'event_service': EventService(vtn_id),
  40. 'report_service': ReportService(vtn_id),
  41. 'poll_service': PollService(vtn_id),
  42. 'opt_service': OptService(vtn_id),
  43. 'registration_service': RegistrationService(vtn_id)}
  44. self.app.add_routes([web.post(f"/OpenADR2/Simple/2.0b/{s.__service_name__}", s.handler) for s in self.services.values()])
  45. # Configure message signing
  46. if cert and key:
  47. with open(cert, "rb") as file:
  48. cert = file.read()
  49. with open(key, "rb") as file:
  50. key = file.read()
  51. VTNService._create_message = partial(create_message, cert=cert, key=key, passphrase=passphrase)
  52. VTNService._parse_message = partial(parse_message, fingerprint_lookup=fingerprint_lookup)
  53. self.__setattr__ = self.add_handler
  54. def run(self):
  55. """
  56. Starts the asyncio-loop and runs the server in it. This function is
  57. blocking. For other ways to run the server in a more flexible context,
  58. please refer to the `aiohttp documentation
  59. <https://docs.aiohttp.org/en/stable/web_advanced.html#aiohttp-web-app-runners>`_.
  60. """
  61. web.run_app(self.app)
  62. def add_handler(self, name, func):
  63. """
  64. Add a handler to the OpenADRServer.
  65. :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.
  66. :param func coroutine: A coroutine that handles this event. It receives the message, and should return the contents of a response.
  67. """
  68. print("Called add_handler", name, func)
  69. if name in self._MAP:
  70. setattr(self._MAP[name], name, staticmethod(func))
  71. else:
  72. raise NameError(f"Unknown handler {name}. Correct handler names are: {self._MAP.keys()}")