Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# SPDX-License-Identifier: Apache-2.0
3# Copyright 2020 Contributors to OpenLEADR
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
9# http://www.apache.org/licenses/LICENSE-2.0
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
17from openleadr.service import service, handler, VTNService
18from openleadr import objects
19import asyncio
20from dataclasses import asdict
21import logging
22logger = logging.getLogger('openleadr')
24# ╔══════════════════════════════════════════════════════════════════════════╗
25# ║ POLLING SERVICE ║
26# ╚══════════════════════════════════════════════════════════════════════════╝
27#
28# oadrPoll is a service independent polling mechanism used by VENs in a PULL
29# model to request pending service operations from the VTN. The VEN queries
30# the poll endpoint and the VTN re- sponds with the same message that it would
31# have “pushed” had it been a PUSH VEN. If there are multiple messages pending
32# a “push,” the VEN will continue to query the poll endpoint until there are
33# no new messages and the VTN responds with an eiResponse payload.
34#
35# ┌──────────────────────────────────────────────────────────────────────────┐
36# │ The VEN can poll for any messages that we have for them. If we have no │
37# │ (more) messages, we send a generic oadrResponse: │
38# │ ┌────┐ ┌────┐ │
39# │ │VEN │ │VTN │ │
40# │ └─┬──┘ └─┬──┘ │
41# │ │───────────────────────────oadrPoll()───────────────────────────▶│ │
42# │ │ │ │
43# │ │◀ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─oadrResponse() ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│ │
44# │ │ │ │
45# │ │
46# └──────────────────────────────────────────────────────────────────────────┘
47# ┌──────────────────────────────────────────────────────────────────────────┐
48# │ If we have an Event, we expect the following: │
49# │ │
50# │ ┌────┐ ┌────┐ │
51# │ │VEN │ │VTN │ │
52# │ └─┬──┘ └─┬──┘ │
53# │ │───────────────────────────oadrPoll()───────────────────────────▶│ │
54# │ │ │ │
55# │ │◀ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ oadrCreateEvent() ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│ │
56# │ │ │ │
57# │ │───────────────────────oadrCreatedEvent()───────────────────────▶│ │
58# │ │ │ │
59# │ │◀ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─oadrResponse() ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│ │
60# │ │ │ │
61# │ │
62# └──────────────────────────────────────────────────────────────────────────┘
63# ┌──────────────────────────────────────────────────────────────────────────┐
64# │ For Reports: │
65# │ │
66# │ ┌────┐ ┌────┐ │
67# │ │VEN │ │VTN │ │
68# │ └─┬──┘ └─┬──┘ │
69# │ │───────────────────────────oadrPoll()───────────────────────────▶│ │
70# │ │ │ │
71# │ │◀ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─oadrCreateReport() ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│ │
72# │ │ │ │
73# │ │───────────────────────oadrCreatedReport()──────────────────────▶│ │
74# │ │ │ │
75# │ │◀ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─oadrResponse() ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│ │
76# │ │ │ │
77# │ │
78# └──────────────────────────────────────────────────────────────────────────┘
79# ┌──────────────────────────────────────────────────────────────────────────┐
80# │ If re-registration is neccessary: │
81# │ │
82# │ ┌────┐ ┌────┐ │
83# │ │VEN │ │VTN │ │
84# │ └─┬──┘ └─┬──┘ │
85# │ │───────────────────────────oadrPoll()───────────────────────────▶│ │
86# │ │ │ │
87# │ │◀ ─ ─ ─ ─ ─ ─ ─ ─ ─oadrRequestReregistration()─ ─ ─ ─ ─ ─ ─ ─ ─ ─│ │
88# │ │ │ │
89# │ │─────────────────────────oadrResponse()─────────────────────────▶│ │
90# │ │ │ │
91# │ │◀ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ HTTP 200─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│ │
92# │ │ │ │
93# │ │
94# │ │──────────────────oadrCreatePartyRegistration()─────────────────▶│ │
95# │ │ │ │
96# │ │◀ ─ ─ ─ ─ ─ ─ ─ ─ ─oadrRequestReregistration()─ ─ ─ ─ ─ ─ ─ ─ ─ ─│ │
97# │ │ │ │
98# │ │
99# └──────────────────────────────────────────────────────────────────────────┘
102@service('OadrPoll')
103class PollService(VTNService):
105 def __init__(self, vtn_id, polling_method='internal', event_service=None, report_service=None):
106 super().__init__(vtn_id)
107 self.polling_method = polling_method
108 self.events_updated = {}
109 self.report_requests = {}
110 self.event_service = event_service
111 self.report_service = report_service
113 @handler('oadrPoll')
114 async def poll(self, payload):
115 """
116 Handle the request to the oadrPoll service. This either calls a previously registered
117 `on_poll` handler, or it retrieves the next message from the internal queue.
118 """
119 if self.polling_method == 'external':
120 result = self.on_poll(ven_id=payload['ven_id'])
121 elif self.events_updated.get(payload['ven_id']):
122 # Send a oadrDistributeEvent whenever the events were updated
123 result = await self.event_service.request_event({'ven_id': payload['ven_id']})
124 self.events_updated[payload['ven_id']] = False
125 else:
126 return 'oadrResponse', {}
128 if asyncio.iscoroutine(result):
129 result = await result
130 if result is None:
131 return 'oadrResponse', {}
132 if isinstance(result, tuple):
133 return result
134 if isinstance(result, list):
135 return 'oadrDistributeEvent', result
136 if isinstance(result, dict) and 'event_descriptor' in result:
137 return 'oadrDistributeEvent', {'events': [result]}
138 if isinstance(result, objects.Event):
139 return 'oadrDistributeEvent', {'events': [asdict(result)]}
140 logger.warning(f"Could not determine type of message in response to oadrPoll: {result}")
141 return 'oadrResponse', result
143 def on_poll(self, ven_id):
144 """
145 Placeholder for the on_poll handler.
146 """
147 logger.warning("You should implement and register your own on_poll handler that "
148 "returns the next message for the VEN. This handler receives the "
149 "ven_id as its argument, and should return None (if no messages "
150 "are available), an Event or list of Events, a RequestReregistration "
151 " or RequestReport.")
152 return None