source: admin/Sources/Clients/ogagent/src/OGAgentUser.py @ 36fe078

918-git-images-111dconfigfileconfigure-oglivegit-imageslgromero-new-oglivemainmaint-cronmount-efivarfsmultivmmultivm-ogboot-installerogClonningEngineogboot-installer-jenkinsoglive-ipv6test-python-scriptsticket-301ticket-50ticket-50-oldticket-577ticket-585ticket-611ticket-612ticket-693ticket-700ubu24tplunification2use-local-agent-oglivevarios-instalacionwebconsole3
Last change on this file since 36fe078 was c3e7c06, checked in by ramon <ramongomez@…>, 9 years ago

#718: Integrar código fuente de agente OGAgent en rama de desarrollo.

git-svn-id: https://opengnsys.es/svn/branches/version1.1@4865 a21b9725-9963-47de-94b9-378ad31fedc9

  • Property mode set to 100644
File size: 11.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Copyright (c) 2014 Virtual Cable S.L.
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without modification,
8# are permitted provided that the following conditions are met:
9#
10#    * Redistributions of source code must retain the above copyright notice,
11#      this list of conditions and the following disclaimer.
12#    * Redistributions in binary form must reproduce the above copyright notice,
13#      this list of conditions and the following disclaimer in the documentation
14#      and/or other materials provided with the distribution.
15#    * Neither the name of Virtual Cable S.L. nor the names of its contributors
16#      may be used to endorse or promote products derived from this software
17#      without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29'''
30@author: Adolfo Gómez, dkmaster at dkmon dot com
31'''
32from __future__ import unicode_literals
33
34import sys
35from PyQt4 import QtGui
36from PyQt4 import QtCore
37
38import time
39import signal
40import json
41import six
42
43from opengnsys import ipc
44from opengnsys import utils
45from opengnsys.log import logger
46from opengnsys.service import IPC_PORT
47from opengnsys import operations
48from about_dialog_ui import Ui_OGAAboutDialog
49from message_dialog_ui import Ui_OGAMessageDialog
50from opengnsys.scriptThread import ScriptExecutorThread
51from opengnsys import VERSION
52from opengnsys.config import readConfig
53from opengnsys.loader import loadModules
54
55trayIcon = None
56
57
58def sigTerm(sigNo, stackFrame):
59    if trayIcon:
60        trayIcon.quit()
61
62
63# About dialog
64class OGAAboutDialog(QtGui.QDialog):
65    def __init__(self, parent=None):
66        QtGui.QDialog.__init__(self, parent)
67        self.ui = Ui_OGAAboutDialog()
68        self.ui.setupUi(self)
69        self.ui.VersionLabel.setText("Version " + VERSION)
70
71    def closeDialog(self):
72        self.hide()
73
74
75class OGAMessageDialog(QtGui.QDialog):
76    def __init__(self, parent=None):
77        QtGui.QDialog.__init__(self, parent)
78        self.ui = Ui_OGAMessageDialog()
79        self.ui.setupUi(self)
80
81    def message(self, message):
82        self.ui.message.setText(message)
83        self.show()
84
85    def closeDialog(self):
86        self.hide()
87
88
89class MessagesProcessor(QtCore.QThread):
90
91    logoff = QtCore.pyqtSignal(name='logoff')
92    message = QtCore.pyqtSignal(tuple, name='message')
93    script = QtCore.pyqtSignal(QtCore.QString, name='script')
94    exit = QtCore.pyqtSignal(name='exit')
95
96    def __init__(self, port):
97        super(self.__class__, self).__init__()
98        # Retries connection for a while
99        for _ in range(10):
100            try:
101                self.ipc = ipc.ClientIPC(port)
102                self.ipc.start()
103                break
104            except Exception:
105                logger.debug('IPC Server is not reachable')
106                self.ipc = None
107                time.sleep(2)
108
109        self.running = False
110
111    def stop(self):
112        self.running = False
113        if self.ipc:
114            self.ipc.stop()
115
116    def isAlive(self):
117        return self.ipc is not None
118
119    def sendLogin(self, userName):
120        if self.ipc:
121            self.ipc.sendLogin(userName)
122
123    def sendLogout(self, userName):
124        if self.ipc:
125            self.ipc.sendLogout(userName)
126
127    def run(self):
128        if self.ipc is None:
129            return
130        self.running = True
131
132        # Wait a bit so we ensure IPC thread is running...
133        time.sleep(2)
134
135        while self.running and self.ipc.running:
136            try:
137                msg = self.ipc.getMessage()
138                if msg is None:
139                    break
140                msgId, data = msg
141                logger.debug('Got Message on User Space: {}:{}'.format(msgId, data))
142                if msgId == ipc.MSG_MESSAGE:
143                    module, message, data = data.split('\0')
144                    self.message.emit((module, message, data))
145                elif msgId == ipc.MSG_LOGOFF:
146                    self.logoff.emit()
147                elif msgId == ipc.MSG_SCRIPT:
148                    self.script.emit(QtCore.QString.fromUtf8(data))
149            except Exception as e:
150                try:
151                    logger.error('Got error on IPC thread {}'.format(utils.exceptionToMessage(e)))
152                except:
153                    logger.error('Got error on IPC thread (an unicode error??)')
154
155        if self.ipc.running is False and self.running is True:
156            logger.warn('Lost connection with Service, closing program')
157
158        self.exit.emit()
159
160
161class OGASystemTray(QtGui.QSystemTrayIcon):
162    def __init__(self, app_, parent=None):
163        self.app = app_
164
165        self.config = readConfig(client=True)
166
167        # Get opengnsys section as dict       
168        cfg = dict(self.config.items('opengnsys'))
169   
170        # Set up log level
171        logger.setLevel(cfg.get('log', 'INFO'))
172       
173        self.ipcport = int(cfg.get('ipc_port', IPC_PORT))
174       
175        # style = app.style()
176        # icon = QtGui.QIcon(style.standardPixmap(QtGui.QStyle.SP_ComputerIcon))
177        icon = QtGui.QIcon(':/images/img/oga.png')
178
179        QtGui.QSystemTrayIcon.__init__(self, icon, parent)
180        self.menu = QtGui.QMenu(parent)
181        exitAction = self.menu.addAction("About")
182        exitAction.triggered.connect(self.about)
183        self.setContextMenu(self.menu)
184        self.ipc = MessagesProcessor(self.ipcport)
185       
186        if self.ipc.isAlive() is False:
187            raise Exception('No connection to service, exiting.')
188       
189        self.timer = QtCore.QTimer()
190        self.timer.timeout.connect(self.timerFnc)
191
192
193        self.stopped = False
194
195        self.ipc.message.connect(self.message)
196        self.ipc.exit.connect(self.quit)
197        self.ipc.script.connect(self.executeScript)
198        self.ipc.logoff.connect(self.logoff)
199
200        self.aboutDlg = OGAAboutDialog()
201        self.msgDlg = OGAMessageDialog()
202
203        self.timer.start(1000)  # Launch idle checking every 1 seconds
204
205        self.ipc.start()
206       
207    def initialize(self):
208        # Load modules and activate them
209        # Also, sends "login" event to service
210        self.modules = loadModules(self, client=True)
211        logger.debug('Modules: {}'.format(list(v.name for v in self.modules)))
212       
213        # Send init to all modules
214        validMods = []
215        for mod in self.modules:
216            try:
217                logger.debug('Activating module {}'.format(mod.name))
218                mod.activate()
219                validMods.append(mod)
220            except Exception as e:
221                logger.exception()
222                logger.error("Activation of {} failed: {}".format(mod.name, utils.exceptionToMessage(e)))
223       
224        self.modules[:] = validMods  # copy instead of assignment
225
226        # If this is running, it's because he have logged in, inform service of this fact
227        self.ipc.sendLogin(operations.getCurrentUser())
228
229    def deinitialize(self):
230        for mod in reversed(self.modules):  # Deinitialize reversed of initialization
231            try:
232                logger.debug('Deactivating module {}'.format(mod.name))
233                mod.deactivate()
234            except Exception as e:
235                logger.exception()
236                logger.error("Deactivation of {} failed: {}".format(mod.name, utils.exceptionToMessage(e)))
237
238    def timerFnc(self):
239        pass
240
241    def message(self, msg):
242        '''
243        Processes the message sent asynchronously, msg is an QString
244        '''
245        try:
246            logger.debug('msg: {}, {}'.format(type(msg), msg))
247            module, message, data = msg
248        except Exception as e:
249            logger.error('Got exception {} processing message {}'.format(e, msg))
250            return
251
252        for v in self.modules:
253            if v.name == module:  # Case Sensitive!!!!
254                try:
255                    logger.debug('Notifying message {} to module {} with json data {}'.format(message, v.name, data))
256                    v.processMessage(message, json.loads(data))
257                    return
258                except Exception as e:
259                    logger.error('Got exception {} processing generic message on {}'.format(e, v.name))
260                   
261        logger.error('Module {} not found, messsage {} not sent'.format(module, message))
262
263    def executeScript(self, script):
264        logger.debug('Executing script')
265        script = six.text_type(script.toUtf8()).decode('base64')
266        th = ScriptExecutorThread(script)
267        th.start()
268
269    def logoff(self):
270        logger.debug('Logoff invoked')
271        operations.logoff()  # Invoke log off
272
273    def about(self):
274        self.aboutDlg.exec_()
275
276    def quit(self):
277        logger.debug('Quit invoked')
278        if self.stopped is False:
279            self.stopped = True
280            try:
281                self.deinitialize()
282            except Exception:
283                logger.exception()
284                logger.error('Got exception deinitializing modules')
285               
286            try:
287                # If we close Client, send Logoff to Broker
288                self.ipc.sendLogout(operations.getCurrentUser())
289                self.timer.stop()
290                self.ipc.stop()
291            except Exception:
292                # May we have lost connection with server, simply exit in that case
293                pass
294
295        try:
296            # operations.logoff()  # Uncomment this after testing to logoff user
297            pass
298        except Exception:
299            pass
300
301        self.app.quit()
302
303if __name__ == '__main__':
304    app = QtGui.QApplication(sys.argv)
305
306    if not QtGui.QSystemTrayIcon.isSystemTrayAvailable():
307        # QtGui.QMessageBox.critical(None, "Systray", "I couldn't detect any system tray on this system.")
308        sys.exit(1)
309
310    # This is important so our app won't close on messages windows (alerts, etc...)
311    QtGui.QApplication.setQuitOnLastWindowClosed(False)
312
313    try:
314        trayIcon = OGASystemTray(app)
315    except Exception as e:
316        logger.exception()
317        logger.error('OGA Service is not running, or it can\'t contact with OGA Server. User Tools stopped: {}'.format(utils.exceptionToMessage(e)))
318        sys.exit(1)
319
320    try:
321        trayIcon.initialize()  # Initialize modules, etc..
322    except Exception as e:
323        logger.exception()
324        logger.error('Exception initializing OpenGnsys User Agent {}'.format(utils.exceptionToMessage(e)))
325        trayIcon.quit()
326        sys.exit(1)
327
328    trayIcon.show()
329
330    # Catch kill and logout user :)
331    signal.signal(signal.SIGTERM, sigTerm)
332
333    res = app.exec_()
334
335    logger.debug('Exiting')
336    trayIcon.quit()
337
338    sys.exit(res)
Note: See TracBrowser for help on using the repository browser.