backend.fcmservice   B
last analyzed

Complexity

Total Complexity 45

Size/Duplication

Total Lines 175
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 126
dl 0
loc 175
rs 8.8
c 0
b 0
f 0
wmc 45

22 Methods

Rating   Name   Duplication   Size   Complexity  
A InfrastructureService.__init__() 0 7 1
A PoolService.get_all_pools() 0 4 1
A Configuration.is_enabled() 0 8 3
A PoolService.findpool() 0 8 5
A Configuration.get() 0 4 2
A BaseService.serialize() 0 10 3
A Configuration.__init__() 0 2 1
A BaseService.createmessageenvelope() 0 3 1
A BaseService.serializemessageenvelope() 0 3 1
A BaseService.getconfigfilename() 0 3 1
A BaseService.__init__() 0 7 1
A BaseService.initmessaging() 0 3 1
A BaseService.deserializemessageenvelope() 0 3 1
A PoolService.getpool() 0 9 3
A PoolService.knownpools() 0 7 3
A Telegram.sendphoto() 0 4 4
A PoolService.update_pool() 0 6 2
A PoolService.save_pool() 0 14 3
A Telegram.__init__() 0 3 1
A Telegram.sendmessage() 0 3 2
A PoolService.add_pool() 0 6 2
A PoolService.putpool() 0 5 3

How to fix   Complexity   

Complexity

Complex classes like backend.fcmservice often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import os
2
import datetime
3
import json
4
from helpers.telegramhelper import sendalert, sendphoto
5
from messaging.schema import MinerSchema, PoolSchema, AvailablePoolSchema, MinerCurrentPoolSchema
6
from messaging.messages import Message, MessageSchema
7
from domain.mining import Miner, Pool, MinerCurrentPool, AvailablePool
8
from domain.rep import PoolRepository
9
import domain.minerpool
10
from backend.fcmcache import CacheKeys
11
import backend.fcmutils as utils
12
13
class ServiceName:
14
    '''names of infrastructure services'''
15
    messagebus = 'rabbit'
16
    cache = 'redis'
17
    database = 'mysql'
18
    email = 'gmail'
19
    telegram = 'telegram'
20
21
class InfrastructureService:
22
    '''configuration for a dependency'''
23
    def __init__(self, name, connection, host, port, user, password):
24
        self.name = name
25
        self.connection = connection
26
        self.host = host
27
        self.port = port
28
        self.user = user
29
        self.password = password
30
31
class BaseService():
32
    '''Every service will share reference to configuration and cache'''
33
    def __init__(self, config, cache):
34
        self.homedirectory = os.path.dirname(__file__)
35
        self.initmessaging()
36
        self.configuration = config
37
        self.cache = cache
38
        #subclass needs to override
39
        self.component = ''
40
41
    def initmessaging(self):
42
        '''start up messaging'''
43
        self._schemamsg = MessageSchema()
44
45
    def getconfigfilename(self, configfilename):
46
        '''get the contents of a config file'''
47
        return os.path.join(self.homedirectory, configfilename)
48
49
    def serialize(self, entity):
50
        '''serialize any entity
51
        only need schema, message class not needed
52
        '''
53
        if isinstance(entity, Miner):
54
            return utils.serialize(entity, MinerSchema())
55
56
        if isinstance(entity, Pool):
57
            return utils.serialize(entity, PoolSchema())
58
        return None
59
60
    def createmessageenvelope(self):
61
        '''create message envelope'''
62
        return Message(timestamp=datetime.datetime.utcnow(), sender=self.component)
63
64
    def serializemessageenvelope(self, msg):
65
        '''serialize message envelope'''
66
        return self._schemamsg.dumps(msg).data
67
68
    def deserializemessageenvelope(self, body):
69
        '''serialize message envelope'''
70
        return self._schemamsg.load(json.loads(utils.safestring(body))).data
71
72
73
class Configuration(object):
74
    def __init__(self, config):
75
        self.__config = config
76
77
    def get(self, key):
78
        if not key in self.__config:
79
            return None
80
        return self.__config[key]
81
82
    def is_enabled(self, key):
83
        lookupkey = '{0}.enabled'.format(key)
84
        if not lookupkey in self.__config:
85
            return False
86
        value = self.__config[lookupkey]
87
        if isinstance(value, str):
88
            return value == 'true' or value == 'True'
89
        return False
90
91
class PoolService(BaseService):
92
    #def __init__(self, configuration, cache):
93
    #    super(PoolService, self).__init__()
94
95
    def get_all_pools(self):
96
        '''configured pools'''
97
        pools = PoolRepository().readpools(self.getconfigfilename('config/pools.conf'))
98
        return pools
99
100
    def findpool(self, minerpool):
101
        '''find a pool in list'''
102
        if minerpool is None:
103
            return None
104
        for pool in self.get_all_pools():
105
            if minerpool.currentpool == pool.url and minerpool.currentworker.startswith(pool.user):
106
                return pool
107
        return None
108
109
    def knownpools(self):
110
        if not self.cache:
111
            return None
112
        dknownpools = self.cache.gethashset(CacheKeys.knownpools)
113
        if dknownpools:
114
            return utils.deserializelist_withschema(AvailablePoolSchema(), list(dknownpools.values()))
115
        return None
116
117
    def getpool(self, miner: Miner):
118
        '''get pool from cache'''
119
        if not self.cache:
120
            return None
121
        valu = self.cache.trygetvaluefromcache(miner.name + '.pool')
122
        if valu is None:
123
            return None
124
        entity = MinerCurrentPool(miner, **utils.deserialize(MinerCurrentPoolSchema(), valu))
125
        return entity
126
127
    def add_pool(self, minerpool: domain.minerpool.MinerPool):
128
        '''see if pool is known or not, then add it'''
129
        knownpool = self.cache.getfromhashset(CacheKeys.knownpools, minerpool.pool.key)
130
        if not knownpool:
131
            val = utils.jsonserialize(AvailablePoolSchema(), minerpool.pool)
132
            self.cache.putinhashset(CacheKeys.knownpools, minerpool.pool.key, val)
133
134
    def putpool(self, pool: Pool):
135
        '''put pool in cache'''
136
        if pool and pool.name:
137
            valu = self.serialize(pool)
138
            self.cache.tryputcache('pool.{0}'.format(pool.name), valu)
139
140
    def update_pool(self, key, pool: AvailablePool):
141
        self.cache.hdel(CacheKeys.knownpools, key)
142
        knownpool = self.cache.getfromhashset(CacheKeys.knownpools, pool.key)
143
        if not knownpool:
144
            val = utils.jsonserialize(AvailablePoolSchema(), pool)
145
            self.cache.putinhashset(CacheKeys.knownpools, pool.key, val)
146
147
    def save_pool(self, pool: Pool):
148
        sch = PoolSchema()
149
        pools = PoolRepository()
150
        pools.add(pool, self.getconfigfilename('config/pools.conf'), sch)
151
152
        #update the known pools
153
        for known in self.knownpools():
154
            if pool.is_same_as(known):
155
                oldkey = known.key
156
                known.named_pool = pool
157
                #this changes the pool key!
158
                known.user = pool.user
159
                #update the known pool (with new key)
160
                self.update_pool(oldkey, known)
161
162
class Telegram(object):
163
    def __init__(self, config, service):
164
        self.configuration = config
165
        self.service = service
166
167
    def sendmessage(self, message):
168
        if self.configuration.is_enabled('telegram'):
169
            sendalert(message, self.service)
170
171
    def sendphoto(self, file_name):
172
        if os.path.isfile(file_name) and os.path.getsize(file_name) > 0:
173
            if self.configuration.is_enabled('telegram'):
174
                sendphoto(file_name, self.service)
175