Failed Conditions
Pull Request — master (#1990)
by Mischa
01:34
created

coalib.output.dbus.DbusServer   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 162
Duplicated Lines 0 %
Metric Value
dl 0
loc 162
rs 10
wmc 20

11 Methods

Rating   Name   Duplication   Size   Complexity  
A DbusServer.DisposeDocument() 0 21 2
B DbusServer.__init__() 0 24 1
A DbusServer.get_or_create_document() 0 17 2
A DbusServer.get_or_create_app() 0 12 2
A DbusServer.create_app() 0 9 1
A DbusServer._on_name_lost() 0 5 2
A DbusServer.create_document() 0 14 1
A DbusServer.CreateDocument() 0 16 1
A DbusServer.dispose_app() 0 14 4
A DbusServer.dispose_document() 0 14 3
A DbusServer._next_app_id() 0 3 1
1
import os
2
3
import dbus.service  # Ignore PyImportSortBear
4
5
from coalib.output.dbus.DbusApp import DbusApp
6
7
8
class DbusServer(dbus.service.Object):
9
    interface = "org.coala_analyzer.v1"
10
11
    def __init__(self, bus, path, on_disconnected=None):
12
        """
13
        Creates a new DbusServer class which handles the dynamic creation and
14
        disposal of dbus object-paths for documents and also handles
15
        information about DbusApplication.
16
17
        :param bus:             The dbus bus to which to connect this object
18
                                path to.
19
        :param path:            The path in the dbus bus using which apps can
20
                                communicate.
21
        :param on_disconnected: This function will be called when the
22
                                DbusServer has no more applications connected
23
                                to it.
24
        """
25
        dbus.service.Object.__init__(self, bus, path)
26
27
        self.apps = {}
28
        self.__next_app_id = 0
29
        self.on_disconnected = on_disconnected
30
31
        bus.add_signal_receiver(self._on_name_lost,
32
                                signal_name='NameOwnerChanged',
33
                                dbus_interface=None,
34
                                path=None)
35
36
    @dbus.service.method(interface,
37
                         in_signature="s",
38
                         out_signature="o",
39
                         sender_keyword="sender")
40
    def CreateDocument(self, path, sender=None):
41
        """
42
        Creates a DbusDocument if it doesn't exist.
43
44
        :param path:   The path to the document.
45
        :param sender: The client who created the dbus request - this is used
46
                       as the DbusApp's name.
47
        :return:       a DbusDocument object.
48
        """
49
        app = self.get_or_create_app(sender)
50
        doc = self.get_or_create_document(app, path)
51
        return doc._object_path
52
53
    @dbus.service.method(interface,
54
                         in_signature="s",
55
                         out_signature="",
56
                         sender_keyword="sender")
57
    def DisposeDocument(self, path, sender=None):
58
        """
59
        Disposes a DbusDocument if it exists. Fails silently if it does not
60
        exist.
61
62
        :param path:   The path to the document.
63
        :param sender: The client who created the dbus request - this is used
64
                       as the DbusApp's name to search for the document in.
65
        """
66
        path = os.path.normpath(path)
67
68
        try:
69
            app = self.apps[sender]
70
        except KeyError:
71
            return
72
73
        self.dispose_document(app, path)
74
75
    def _on_name_lost(self, name, oldowner, newowner):
76
        if newowner != '':
77
            return
78
79
        self.dispose_app(oldowner)
80
81
    def _next_app_id(self):
82
        self.__next_app_id += 1
83
        return self.__next_app_id
84
85
    def create_app(self, appname):
86
        """
87
        Create a new dbus app with the given appname.
88
89
        :param appname: The name of the app to be created.
90
        :return:        a DbusApp object.
91
        """
92
        self.apps[appname] = DbusApp(self._next_app_id(), appname)
93
        return self.apps[appname]
94
95
    def get_or_create_app(self, appname):
96
        """
97
        Get the dbus app with the given appname. If there does not exist any
98
        app with the given name, a new app is created and returned.
99
100
        :param appname: The name of the app to be created.
101
        :return:        A DbusApp object.
102
        """
103
        try:
104
            return self.apps[appname]
105
        except KeyError:
106
            return self.create_app(appname)
107
108
    def dispose_app(self, appname):
109
        """
110
        Dispose of the app with the given name. It fails silently if the app
111
        does not exist. If there are no more apps connected to the server, it
112
        calls the on_disconnected callback.
113
114
        :param appname: The name of the app to dispose of.
115
        """
116
        try:
117
            self.apps.pop(appname)
118
            if len(self.apps) == 0 and self.on_disconnected:
119
                self.on_disconnected()
120
        except KeyError:
121
            pass
122
123
    def create_document(self, app, path):
124
        """
125
        Create a new dbus document.
126
127
        :param app:  The DbusApp the document is related to.
128
        :param path: The path to the document to be created.
129
        :return:     a DbusDocument object.
130
        """
131
        doc = app.create_document(path)
132
        objpath = (self._object_path + "/" + str(app.app_id) +
133
                   "/documents/" + str(doc.doc_id))
134
        doc.add_to_connection(self._connection, objpath)
135
136
        return doc
137
138
    def get_or_create_document(self, app, path):
139
        """
140
        Get the dbus document with the given path. If there does not exist any
141
        document under the DbusApp with the given path, a new document is
142
        created and returned.
143
144
        :param app:  The DbusApp the document is under.
145
        :param path: The path to the document to be created.
146
        :return:     A DbusApp object.
147
        """
148
        path = os.path.abspath(os.path.expanduser(path))
149
        try:
150
            doc = app.docs[path]
151
        except KeyError:
152
            doc = self.create_document(app, path)
153
154
        return doc
155
156
    def dispose_document(self, app, path):
157
        """
158
        Dispose of the document with the given path. It fails silently if the
159
        document does not exist. If there are no more documents in the app,
160
        the app is disposed.
161
162
        :param app:  The DbusApp the document is under.
163
        :param path: The path to the document.
164
        """
165
        doc = app.dispose_document(path)
166
        if doc != None:
167
            doc.remove_from_connection()
168
            if len(app.docs) == 0:
169
                self.dispose_app(app.name)
170