Show More
@@ -25,15 +25,10 b' Provides the implementation of various c' | |||
|
25 | 25 | |
|
26 | 26 | import copy |
|
27 | 27 | import logging |
|
28 | import threading | |
|
29 | import urlparse | |
|
30 | 28 | import uuid |
|
31 | 29 | import weakref |
|
32 | from urllib2 import URLError | |
|
33 | 30 | |
|
34 | import msgpack | |
|
35 | 31 | import Pyro4 |
|
36 | import requests | |
|
37 | 32 | from pyramid.threadlocal import get_current_request |
|
38 | 33 | from Pyro4.errors import CommunicationError, ConnectionClosedError, DaemonError |
|
39 | 34 | |
@@ -43,137 +38,6 b' from rhodecode.lib.vcs.conf import setti' | |||
|
43 | 38 | log = logging.getLogger(__name__) |
|
44 | 39 | |
|
45 | 40 | |
|
46 | # TODO: mikhail: Keep it in sync with vcsserver's | |
|
47 | # HTTPApplication.ALLOWED_EXCEPTIONS | |
|
48 | EXCEPTIONS_MAP = { | |
|
49 | 'KeyError': KeyError, | |
|
50 | 'URLError': URLError, | |
|
51 | } | |
|
52 | ||
|
53 | ||
|
54 | class HTTPRepoMaker(object): | |
|
55 | def __init__(self, server_and_port, backend_endpoint): | |
|
56 | self.url = urlparse.urljoin( | |
|
57 | 'http://%s' % server_and_port, backend_endpoint) | |
|
58 | ||
|
59 | def __call__(self, path, config, with_wire=None): | |
|
60 | log.debug('HTTPRepoMaker call on %s', path) | |
|
61 | return HTTPRemoteRepo(path, config, self.url, with_wire=with_wire) | |
|
62 | ||
|
63 | def __getattr__(self, name): | |
|
64 | def f(*args, **kwargs): | |
|
65 | return self._call(name, *args, **kwargs) | |
|
66 | return f | |
|
67 | ||
|
68 | @exceptions.map_vcs_exceptions | |
|
69 | def _call(self, name, *args, **kwargs): | |
|
70 | payload = { | |
|
71 | 'id': str(uuid.uuid4()), | |
|
72 | 'method': name, | |
|
73 | 'params': {'args': args, 'kwargs': kwargs} | |
|
74 | } | |
|
75 | return _remote_call(self.url, payload, EXCEPTIONS_MAP) | |
|
76 | ||
|
77 | ||
|
78 | class VcsHttpProxy(object): | |
|
79 | ||
|
80 | CHUNK_SIZE = 16384 | |
|
81 | ||
|
82 | def __init__(self, server_and_port, backend_endpoint): | |
|
83 | adapter = requests.adapters.HTTPAdapter(max_retries=5) | |
|
84 | self.base_url = urlparse.urljoin( | |
|
85 | 'http://%s' % server_and_port, backend_endpoint) | |
|
86 | self.session = requests.Session() | |
|
87 | self.session.mount('http://', adapter) | |
|
88 | ||
|
89 | def handle(self, environment, input_data, *args, **kwargs): | |
|
90 | data = { | |
|
91 | 'environment': environment, | |
|
92 | 'input_data': input_data, | |
|
93 | 'args': args, | |
|
94 | 'kwargs': kwargs | |
|
95 | } | |
|
96 | result = self.session.post( | |
|
97 | self.base_url, msgpack.packb(data), stream=True) | |
|
98 | return self._get_result(result) | |
|
99 | ||
|
100 | def _deserialize_and_raise(self, error): | |
|
101 | exception = Exception(error['message']) | |
|
102 | try: | |
|
103 | exception._vcs_kind = error['_vcs_kind'] | |
|
104 | except KeyError: | |
|
105 | pass | |
|
106 | raise exception | |
|
107 | ||
|
108 | def _iterate(self, result): | |
|
109 | unpacker = msgpack.Unpacker() | |
|
110 | for line in result.iter_content(chunk_size=self.CHUNK_SIZE): | |
|
111 | unpacker.feed(line) | |
|
112 | for chunk in unpacker: | |
|
113 | yield chunk | |
|
114 | ||
|
115 | def _get_result(self, result): | |
|
116 | iterator = self._iterate(result) | |
|
117 | error = iterator.next() | |
|
118 | if error: | |
|
119 | self._deserialize_and_raise(error) | |
|
120 | ||
|
121 | status = iterator.next() | |
|
122 | headers = iterator.next() | |
|
123 | ||
|
124 | return iterator, status, headers | |
|
125 | ||
|
126 | ||
|
127 | class HTTPRemoteRepo(object): | |
|
128 | def __init__(self, path, config, url, with_wire=None): | |
|
129 | self.url = url | |
|
130 | self._wire = { | |
|
131 | "path": path, | |
|
132 | "config": config, | |
|
133 | "context": str(uuid.uuid4()), | |
|
134 | } | |
|
135 | if with_wire: | |
|
136 | self._wire.update(with_wire) | |
|
137 | ||
|
138 | def __getattr__(self, name): | |
|
139 | def f(*args, **kwargs): | |
|
140 | return self._call(name, *args, **kwargs) | |
|
141 | return f | |
|
142 | ||
|
143 | @exceptions.map_vcs_exceptions | |
|
144 | def _call(self, name, *args, **kwargs): | |
|
145 | log.debug('Calling %s@%s', self.url, name) | |
|
146 | # TODO: oliver: This is currently necessary pre-call since the | |
|
147 | # config object is being changed for hooking scenarios | |
|
148 | wire = copy.deepcopy(self._wire) | |
|
149 | wire["config"] = wire["config"].serialize() | |
|
150 | payload = { | |
|
151 | 'id': str(uuid.uuid4()), | |
|
152 | 'method': name, | |
|
153 | 'params': {'wire': wire, 'args': args, 'kwargs': kwargs} | |
|
154 | } | |
|
155 | return _remote_call(self.url, payload, EXCEPTIONS_MAP) | |
|
156 | ||
|
157 | def __getitem__(self, key): | |
|
158 | return self.revision(key) | |
|
159 | ||
|
160 | ||
|
161 | def _remote_call(url, payload, exceptions_map): | |
|
162 | response = requests.post(url, data=msgpack.packb(payload)) | |
|
163 | response = msgpack.unpackb(response.content) | |
|
164 | error = response.get('error') | |
|
165 | if error: | |
|
166 | type_ = error.get('type', 'Exception') | |
|
167 | exc = exceptions_map.get(type_, Exception) | |
|
168 | exc = exc(error.get('message')) | |
|
169 | try: | |
|
170 | exc._vcs_kind = error['_vcs_kind'] | |
|
171 | except KeyError: | |
|
172 | pass | |
|
173 | raise exc | |
|
174 | return response.get('result') | |
|
175 | ||
|
176 | ||
|
177 | 41 | class RepoMaker(object): |
|
178 | 42 | |
|
179 | 43 | def __init__(self, proxy_factory): |
General Comments 0
You need to be logged in to leave comments.
Login now