Welcome to mirror list, hosted at ThFree Co, Russian Federation.

ResponseProvider.py « python « tools - github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: a1e8c50418a43086104f9122b6b84c51f871ca05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
from __future__ import print_function

import jsons
import logging
import os


BIG_FILE_SIZE = 47684


class Payload:
    def __init__(self, message, response_code=200, headers={}):
        self.__response_code = response_code
        self.__message = message
        self.__headers = headers
        
    
    def response_code(self):
        """
        Response code to send to the client.
        """
        return self.__response_code
    
    
    def message(self):
        """
        The message to send to the client.
        """
        return self.__message


    def length(self):
        """
        The length of the response.
        """
        return len(self.message())


    def headers(self):
        """
        The headers to be sent to the client. Please, note, that these do not include
        the Content-Length header, which you need to send separately.
        """
        return self.__headers


    def __repr__(self):
        return "{}: {}: {}".format(self.response_code(), self.length(), self.message())


class ResponseProviderMixin:
    """
A mixin (basically, an interface) that the web-server that we might use relies on. 

In this implementation, the job of the web-server is just to get the request
(the url and the headers), and to send the response as it knows how. It isn't
its job to decide how to respond to what request. It is the job of the 
ResponseProvider.

In your web-server you should initialize the ResponseProvider, and ask it for

response_for_url_and_headers(url, headers)

Which will return a Payload object that the server must send as response.

The server might be notified when a particular request has been received:

got_pinged(self) - someone sent a ping request. The Response provider will
respond with "pong" and call this method of the server. You might want to
increment the count of active users, for ping is the request that new instances
of servers send to check if other servers are currently serving.

kill(self) - someone sent the kill request, which means that that someone
no longer needs this server to serve. You might want to decrement the count of
active users and/or stop the server. 
"""
    
    def dispatch_response(self, payload):
        """
    Define this mehtod to dispatch the response received from the ResponseProvider
    """
        raise NotImplementedError()
    

    def got_pinged(self):
        """
    A ping request has been received. In most scenarios it means that the number of 
    users of this server has increased by 1.
    """
        raise NotImplementedError()
    
        
    def kill(self):
        """
    Someone no longer needs this server. Decrement the number of users and stop
    the server if the number fell to 0.
    """
        raise NotImplementedError()


class ResponseProvider:
    def __init__(self, delegate):
        self.headers = list()
        self.delegate = delegate
        self.byterange = None
        self.is_chunked = False
        self.response_code = 200
   
    
    def pong(self):
        self.delegate.got_pinged()
        return Payload("pong")


    def my_id(self):
        return Payload(str(os.getpid()))


    def strip_query(self, url):
        query_start = url.find("?")
        if (query_start > 0):
            return url[:query_start]
        return url


    def response_for_url_and_headers(self, url, headers):
        self.headers = headers
        self.chunk_requested()
        url = self.strip_query(url)
        try:
            return {
                "/unit_tests/1.txt": self.test1,
                "/unit_tests/notexisting_unittest": self.test_404,
                "/unit_tests/permanent": self.test_301,
                "/unit_tests/47kb.file": self.test_47_kb,
                # Following two URIs are used to test downloading failures on different platforms.
                "/unit_tests/mac/1234/Uruguay.mwm": self.test_404,
                "/unit_tests/linux/1234/Uruguay.mwm": self.test_404,
                "/ping": self.pong,
                "/kill": self.kill,
                "/id": self.my_id,
                "/partners/time": self.partners_time,
                "/partners/price": self.partners_price,
                "/booking/min_price": self.partners_minprice,
                "/booking/min_price.getHotelAvailability": self.partners_minprice,
                "/booking/min_price/hotelAvailability": self.partners_hotel_availability,
                "/partners/taxi_info": self.partners_yandex_taxi_info,
                "/partners/get-offers-in-bbox/": self.partners_rent_nearby,
                "/partners/CalculateByCoords": self.partners_calculate_by_coords,
            }[url]()
        except:
            return self.test_404()


    def chunk_requested(self):
        if "range" in self.headers:
            self.is_chunked = True
            self.response_code = 206
            meaningful_string = self.headers["range"][6:]
            first, last = meaningful_string.split("-")
            self.byterange = (int(first), int(last))


    def trim_message(self, message):
        if not self.is_chunked:
            return message
        return message[self.byterange[0]: self.byterange[1] + 1]


    def test1(self):
        init_message = "Test1"
        message = self.trim_message(init_message)
        size = len(init_message)
        self.check_byterange(size)
        headers = self.chunked_response_header(size)
        
        return Payload(message, self.response_code, headers)


    def test_404(self):
        return Payload("", response_code=404)


    def test_301(self):
        return Payload("", 301, {"Location" : "google.com"})
    

    def check_byterange(self, size):
        if self.byterange is None:
            self.byterange = (0, size)

    def chunked_response_header(self, size):
        return {
            "Content-Range" : "bytes {start}-{end}/{out_of}".format(start=self.byterange[0],
            end=self.byterange[1], out_of=size)
        }
        
    
    def test_47_kb(self):
        self.check_byterange(BIG_FILE_SIZE)
        headers = self.chunked_response_header(BIG_FILE_SIZE)
        message = self.trim_message(self.message_for_47kb_file())
            
        return Payload(message, self.response_code, headers)

    
    def message_for_47kb_file(self):
        message = []
        for i in range(0, BIG_FILE_SIZE + 1):
            message.append(chr(i / 256))
            message.append(chr(i % 256))

        return "".join(message)


    # Partners_api_tests
    def partners_time(self):
        return Payload(jsons.PARTNERS_TIME)


    def partners_price(self):
        return Payload(jsons.PARTNERS_PRICE)


    def partners_minprice(self):
        return Payload(jsons.PARTNERS_MINPRICE)

    def partners_hotel_availability(self):
        return Payload(jsons.HOTEL_AVAILABILITY)

    def partners_yandex_taxi_info(self):
        return Payload(jsons.PARTNERS_TAXI_INFO)

    def partners_rent_nearby(self):
        return Payload(jsons.PARTNERS_RENT_NEARBY)

    def partners_calculate_by_coords(self):
        return Payload(jsons.PARTNERS_CALCULATE_BY_COORDS)

    def kill(self):
        logging.debug("Kill called in ResponseProvider")
        self.delegate.kill()
        return Payload("Bye...")