Coverage for aiocoap/proxy/client.py: 35%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

48 statements  

1# This file is part of the Python aiocoap library project. 

2# 

3# Copyright (c) 2012-2014 Maciej Wasilak <http://sixpinetrees.blogspot.com/>, 

4# 2013-2014 Christian Amsüss <c.amsuess@energyharvesting.at> 

5# 

6# aiocoap is free software, this file is published under the MIT license as 

7# described in the accompanying LICENSE file. 

8 

9import asyncio 

10 

11from .. import interfaces 

12from ..protocol import ClientObservation 

13 

14from ..util.asyncio import py38args 

15 

16class ProxyForwarder(interfaces.RequestProvider): 

17 """Object that behaves like a Context but only provides the request 

18 function and forwards all messages to a proxy. 

19 

20 This is not a proxy itself, it is just the interface for an external 

21 one.""" 

22 def __init__(self, proxy_address, context): 

23 self.proxy_address = proxy_address 

24 self.context = context 

25 

26 proxy = property(lambda self: self._proxy) 

27 

28 def request(self, message, **kwargs): 

29 assert message.remote is None, "Message already has a configured "\ 

30 "remote, set .opt.uri_{host,port} instead of remote" 

31 assert message.opt.uri_host is not None, "Message does not have a "\ 

32 "destination address" 

33 message.opt.proxy_scheme = 'coap' 

34 return ProxyRequest(self, message, **kwargs) 

35 

36class ProxyRequest(interfaces.Request): 

37 def __init__(self, proxy, app_request, exchange_monitor_factory=lambda x:None): 

38 self.proxy = proxy 

39 self.app_request = app_request 

40 self.response = asyncio.get_running_loop().create_future() 

41 self._exchange_monitor_factory = exchange_monitor_factory 

42 

43 self.observation = ProxyClientObservation(app_request) 

44 

45 asyncio.create_task( 

46 self._launch(), 

47 **py38args(name="Proxying %r" % app_request) 

48 ) 

49 

50 async def _launch(self): 

51 try: 

52 self.app_request.remote = None 

53 self.app_request.unresolved_remote = self.proxy.proxy_address 

54 proxyrequest = self.proxy.context.request(self.app_request, exchange_monitor_factory=self._exchange_monitor_factory) 

55 if proxyrequest.observation is not None: 

56 self.observation._hook_onto(proxyrequest.observation) 

57 else: 

58 self.observation.error(Exception("No proxied observation, this should not have been created in the first place.")) 

59 self.response.set_result(await proxyrequest.response) 

60 except Exception as e: 

61 self.response.set_exception(e) 

62 

63class ProxyClientObservation(ClientObservation): 

64 real_observation = None 

65 _register = None 

66 _unregister = None 

67 

68 def _hook_onto(self, real_observation): 

69 if self.cancelled: 

70 real_observation.cancel() 

71 else: 

72 real_observation.register_callback(self.callback) 

73 real_observation.register_errback(self.error) 

74 

75 def cancel(self): 

76 self.errbacks = None 

77 self.callbacks = None 

78 self.cancelled = True 

79 if self.real_observation is not None: 

80 # delay to _hook_onto, will be cancelled there as cancelled is set to True 

81 self.real_observation.cancel()