Hide keyboard shortcuts

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 

2 

3# Copyright 2020 Contributors to OpenLEADR 

4 

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 

8 

9# http://www.apache.org/licenses/LICENSE-2.0 

10 

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. 

16 

17from openleadr.service import service, handler, VTNService 

18from openleadr import objects 

19import asyncio 

20from dataclasses import asdict 

21import logging 

22logger = logging.getLogger('openleadr') 

23 

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# └──────────────────────────────────────────────────────────────────────────┘ 

100 

101 

102@service('OadrPoll') 

103class PollService(VTNService): 

104 

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 

112 

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', {} 

127 

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 

142 

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