1
2 """
3
4 @author: Fabio Erculiani <lxnay@sabayonlinux.org>
5 @contact: lxnay@sabayonlinux.org
6 @copyright: Fabio Erculiani
7 @license: GPL-2
8
9 B{Entropy Client Services Base Interface}.
10
11 """
12 import time
13 from entropy.const import const_isstring, etpUi
14 from entropy.exceptions import *
15 from entropy.i18n import _
16 from entropy.misc import TimeScheduled
17 from entropy.i18n import _
18
20
21 ssl_connection = True
22 - def __init__(self, OutputInterface, MethodsInterface = None,
23 ClientCommandsInterface = None, quiet = True, show_progress = False,
24 do_cache_connection = False, do_cache_session = False,
25 socket_timeout = 120.0):
26
27 if not hasattr(OutputInterface, 'updateProgress'):
28 mytxt = _("OutputInterface does not have an updateProgress method")
29 raise IncorrectParameter("IncorrectParameter: %s, (! %s !)" % (
30 OutputInterface, mytxt,))
31 elif not hasattr(OutputInterface.updateProgress, '__call__'):
32 mytxt = _("OutputInterface does not have an updateProgress method")
33 raise IncorrectParameter("IncorrectParameter: %s, (! %s !)" % (
34 OutputInterface, mytxt,))
35
36 from entropy.client.services.system.commands import Client as ClientCommands
37 if not issubclass(ClientCommandsInterface, ClientCommands):
38 mytxt = _("A valid entropy.client.services.system.commands.Client class/subclass is needed")
39 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,))
40
41 from entropy.client.services.system.methods import BaseMixin
42 if not issubclass(MethodsInterface, BaseMixin):
43 mytxt = _("A valid entropy.client.services.system.methods.BaseMixin class/subclass is needed")
44 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,))
45
46 self.ClientCommandsInterface = ClientCommandsInterface
47 import socket, struct
48 import entropy.tools as entropyTools
49 self.socket, self.struct, self.entropyTools = socket, struct, entropyTools
50 from datetime import datetime
51 self.datetime = datetime
52 import threading
53 self.threading = threading
54 self.Output = OutputInterface
55 self.hostname = None
56 self.hostport = None
57 self.username = None
58 self.password = None
59 if quiet and etpUi['debug']:
60 quiet = False
61 self.quiet = quiet
62 self.socket_timeout = socket_timeout
63 self.do_cache_connection = do_cache_connection
64 self.show_progress = show_progress
65 self.ClientCommandsInterface = ClientCommandsInterface
66 self.Methods = MethodsInterface(self)
67 self.session_cache = {}
68 self.SessionCacheLock = self.threading.Lock()
69 self.connection_cache = {}
70 self.CacheLock = self.threading.Lock()
71 self.shutdown = False
72 self.connection_killer = None
73
74
75
76
77
78
79 self.do_cache_session = do_cache_session
80 if self.do_cache_connection:
81 self.connection_killer = TimeScheduled(2,
82 self.connection_killer_handler)
83 self.connection_killer.start()
84
86 if hasattr(self, 'shutdown'):
87 self.shutdown = True
88 if hasattr(self, 'connection_killer'):
89 if self.connection_killer != None:
90 self.connection_killer.kill()
91
93 if not const_isstring(self.hostname):
94 raise IncorrectParameter("IncorrectParameter: hostname: %s. %s" % (
95 _('not a string'), _('Please use setup_connection() properly'),))
96 if not const_isstring(self.username):
97 raise IncorrectParameter("IncorrectParameter: username: %s. %s" % (
98 _('not a string'), _('Please use setup_connection() properly'),))
99 if not const_isstring(self.password):
100 raise IncorrectParameter("IncorrectParameter: password: %s. %s" % (
101 _('not a string'), _('Please use setup_connection() properly'),))
102 if not isinstance(self.hostport, int):
103 raise IncorrectParameter("IncorrectParameter: port: %s. %s" % (
104 _('not an int'), _('Please use setup_connection() properly'),))
105 if not isinstance(self.ssl_connection, bool):
106 raise IncorrectParameter("IncorrectParameter: ssl_connection: %s. %s" % (
107 _('not a bool'), _('Please use setup_connection() properly'),))
108
110 if self.do_cache_session:
111 with self.SessionCacheLock:
112 return self.session_cache.get(cmd_tuple)
113
115 if self.do_cache_session:
116 with self.SessionCacheLock:
117 self.session_cache[cmd_tuple] = session_id
118
120 if self.do_cache_session:
121 with self.SessionCacheLock:
122 del self.session_cache[cmd_tuple]
123
125 return hash((self.hostname, self.hostport, self.username, self.password, self.ssl_connection,))
126
128 if self.do_cache_connection:
129 key = self.get_connection_cache_key()
130 srv = self.connection_cache.get(key)
131
132
133
134
135 return srv
136
138 if self.do_cache_connection:
139 key = self.get_connection_cache_key()
140 self.connection_cache[key] = {
141 'conn': srv,
142 'ts': self.get_ts(),
143 }
144
146 if self.do_cache_connection:
147 key = self.get_connection_cache_key()
148 if key not in self.connection_cache:
149 return
150 self.connection_cache[key]['ts'] = self.get_ts()
151
153 if self.do_cache_connection:
154 self.CacheLock.acquire()
155 try:
156 keys = list(self.connection_cache.keys())
157 for key in keys:
158 data = self.connection_cache.pop(key)
159 data['conn'].disconnect()
160 finally:
161 self.CacheLock.release()
162
164
165 if not self.do_cache_connection:
166 return
167 if self.shutdown:
168 return
169 if not self.connection_cache:
170 return
171
172 keys = list(self.connection_cache.keys())
173 for key in keys:
174 curr_ts = self.get_ts()
175 ts = self.connection_cache[key]['ts']
176 delta = curr_ts - ts
177 if delta.seconds < 60:
178 continue
179 self.CacheLock.acquire()
180 try:
181 data = self.connection_cache.pop(key)
182 finally:
183 self.CacheLock.release()
184 srv = data['conn']
185 srv.disconnect()
186
188 return self.datetime.fromtimestamp(time.time())
189
191 self.hostname = hostname
192 self.hostport = port
193 self.username = username
194 self.password = password
195 self.ssl_connection = ssl
196 self._validate_credentials()
197
199 self._validate_credentials()
200 args = [self.Output, self.ClientCommandsInterface]
201 kwargs = {
202 'ssl': self.ssl_connection,
203 'quiet': self.quiet,
204 'show_progress': self.show_progress
205 }
206 if timeout is None:
207 kwargs['socket_timeout'] = self.socket_timeout
208 else:
209 kwargs['socket_timeout'] = timeout
210 from entropy.services.ugc.interfaces import Client
211 srv = Client(*args,**kwargs)
212 srv.connect(self.hostname, self.hostport)
213 return srv
214
221
222 - def logout(self, srv, session_id):
223 self._validate_credentials()
224 return srv.CmdInterface.service_logout(self.username, session_id)
225
226 - def login(self, srv, session_id):
227 self._validate_credentials()
228 return srv.CmdInterface.service_login(self.username, self.password, session_id)
229
230
231 - def do_cmd(self, login_required, func, args, kwargs):
232
233 with self.CacheLock:
234
235 srv = self.get_connection_cache()
236 if srv == None:
237 srv = self.get_service_connection(timeout = self.socket_timeout)
238 if srv != None:
239 self.cache_connection(srv)
240 else:
241 srv = srv['conn']
242
243 if srv == None:
244 return False, 'no connection'
245
246 cmd_tuple = (login_required, func,)
247 new_session = False
248 session = self.get_session_cache(cmd_tuple)
249 if session == None:
250 new_session = True
251 session = srv.open_session()
252 if session == None:
253 return False, 'no session'
254 else:
255 if not srv.is_session_alive(session):
256 new_session = True
257 session = srv.open_session()
258 if session == None:
259 return False, 'no session'
260 self.set_session_cache(cmd_tuple, session)
261
262 self.update_connection_ts()
263 args.insert(0, session)
264
265 if login_required and new_session:
266 logged, error = self.login(srv, session)
267 if not logged:
268 srv.close_session(session)
269 self.remove_session_cache(cmd_tuple)
270 if not self.do_cache_connection:
271 srv.disconnect()
272 return False, error
273
274 cmd_func = getattr(srv.CmdInterface, func)
275 rslt = cmd_func(*args, **kwargs)
276 if not self.do_cache_session:
277 if login_required:
278 self.logout(srv, session)
279 srv.close_session(session)
280 if not self.do_cache_connection:
281 srv.disconnect()
282 return rslt
283
286