3 # mEveMon - A character monitor for EVE Online
4 # Copyright (c) 2010 Ryan and Danny Campbell, and the mEveMon Team
6 # mEveMon is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # mEveMon is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 import logging.handlers
29 #conic is used for connection handling
32 from eveapi import eveapi
35 import file_settings as settings
36 from constants import LOGPATH, MAXBYTES, LOGCOUNT, CONFIG_DIR, IMG_CACHE_PATH
37 from constants import APICACHE_PATH
38 from constants import REQUIRED_ACCESS_MASK
40 #ugly hack to check maemo version. any better way?
41 if hasattr(hildon, "StackableWindow"):
42 from ui.fremantle import gui
44 from ui.diablo import gui
47 """ The controller class for mEvemon. The intent is to help
48 abstract the EVE API and settings code from the UI code.
51 self.program = hildon.Program()
52 self.connect_to_network()
53 self.settings = settings.Settings()
54 self.cached_api = eveapi.EVEAPIConnection( cacheHandler = \
55 apicache.cache_handler(debug=False))
56 self.gui = gui.mEveMonUI(self)
62 def quit(self, *args):
65 def get_auth(self, key_id):
66 """ Returns an authentication object to be used for eveapi calls
67 that require authentication.
69 ver_code = self.settings.get_ver_code(key_id)
72 auth = self.cached_api.auth(keyID=key_id, vCode=ver_code)
74 self.gui.report_error(str(e))
75 logging.getLogger('mevemon').exception("Failed to get character name")
80 def get_char_sheet(self, key_id, char_id):
81 """ Returns an object containing information about the character specified
82 by the provided character ID.
85 sheet = self.get_auth(key_id).character(char_id).CharacterSheet()
87 self.gui.report_error(str(e))
88 logging.getLogger('mevemon').exception("Failed to get character name")
93 def charid2key_id(self, char_id):
94 """ Takes a character ID and returns the user ID of the account containing
97 Returns None if the character isn't found in any of the registered accounts.
100 acct_dict = self.settings.get_accounts()
102 for key_id, ver_code in acct_dict.items():
103 auth = self.cached_api.auth(keyID=key_id, vCode=ver_code)
105 api_char_list = auth.account.Characters()
106 characters = api_char_list.characters
110 for character in characters:
111 if character.characterID == char_id:
115 def char_id2name(self, char_id):
116 """ Takes a character ID and returns the character name associated with
118 The EVE API accepts a comma-separated list of IDs, but for now we
119 will just handle a single ID.
122 chars = self.cached_api.eve.CharacterName(ids=char_id).characters
123 name = chars[0].characterName
125 self.gui.report_error(str(e))
126 logging.getLogger('mevemon').exception("Failed to get character name")
131 def char_name2id(self, name):
132 """ Takes the name of an EVE character and returns the characterID.
134 The EVE api accepts a comma separated list of names, but for now
135 we will just handle single names/
138 chars = self.cached_api.eve.CharacterID(names=name).characters
139 char_id = chars[0].characterID
140 char_name = chars[0].name
142 self.gui.report_error(str(e))
143 logging.getLogger('mevemon').exception("Failed to get ID")
148 def get_chars_from_acct(self, key_id):
149 """ Returns a list of characters associated with the provided user ID.
151 auth = self.get_auth(key_id)
156 api_char_list = auth.account.Characters()
157 char_name_list = [char.name for char in api_char_list.characters]
158 char_id_list = [char.characterID for char in api_char_list.characters]
160 self.gui.report_error(str(e))
161 logging.getLogger('mevemon').exception("Failed to get character list")
164 return char_name_list, char_id_list
166 def get_characters(self):
167 """ Returns a list of (character_name, image_path, key_id) tuples from all the
168 accounts that are registered to mEveMon.
170 If there is an authentication issue, then instead of adding a valid
171 pair to the list, it appends an 'error message'
175 err_img = "/usr/share/mevemon/imgs/error.jpg"
176 err_txt = "Problem fetching info for account (or no accounts added)"
177 bad_key = "Incorrect key access. Your access mask should be %s." % REQUIRED_ACCESS_MASK
179 placeholder_chars = (err_txt, err_img, None)
181 acct_dict = self.settings.get_accounts()
183 return [placeholder_chars]
185 for key_id, ver_code in acct_dict.items():
187 char_names, char_ids = self.get_chars_from_acct(key_id)
190 ui_char_list.append((err_txt + "\t(KEY_ID: %s)" % key_id, err_img, None))
194 # since there are char names, let's check the key
195 # access and if it's bad we'll generate a key URL for
197 for char_name, char_id in zip(char_names, char_ids):
198 if self.get_access_mask(key_id, ver_code) != REQUIRED_ACCESS_MASK:
199 key_url = self.generate_access_mask_url(char_id)
200 ui_char_list.append((bad_key, err_img, None))
202 # append each char we get to the list we'll
203 # return to the UI --danny
204 ui_char_list.append((char_name, self.get_portrait(char_name, 64), key_id))
208 def get_portrait(self, char_name, size):
209 """ Returns the file path of the retrieved portrait
211 char_id = self.char_name2id(char_name)
213 return fetchimg.portrait_filename(char_id, size)
215 def get_skill_tree(self):
216 """ Returns an object from eveapi containing skill tree info
219 tree = self.cached_api.eve.SkillTree()
221 self.gui.report_error(str(e))
222 logging.getLogger('mevemon').exception("Failed to get skill-in-training:")
227 def get_skill_in_training(self, key_id, char_id):
228 """ Returns an object from eveapi containing information about the
229 current skill in training
232 # should this be accessing the cached object? (confused) --danny
233 skill = self.get_auth(key_id).character(char_id).SkillInTraining()
235 self.gui.report_error(str(e))
236 logging.getLogger('mevemon').exception("Failed to get skill-in-training:")
241 def connection_cb(self, connection, event, mgc):
242 """ I'm not sure why we need this, but connection.connect() won't work
243 without it, even empty.
248 def connect_to_network(self):
249 """ This will connect to the default network if avaliable, or pop up the
250 connection dialog to select a connection.
251 Running this when we start the program ensures we are connected to a
254 connection = conic.Connection()
256 connection.connect("connection-event", self.connection_cb, 0xAA55)
257 assert(connection.request_connection(conic.CONNECT_FLAG_NONE))
260 def get_sp(self, key_id, char_id):
261 """ Adds up the SP for all known skills, then calculates the SP gained
262 from an in-training skill.
266 sheet = self.get_char_sheet(key_id, char_id)
267 for skill in sheet.skills:
268 actual_sp += skill.skillpoints
270 live_sp = actual_sp + self.get_training_sp(key_id, char_id)
274 def get_spps(self, key_id, char_id):
275 """ Calculate and returns the skill points per hour for the given character.
277 skill = self.get_skill_in_training(key_id, char_id)
279 if not skill.skillInTraining:
282 total_sp = skill.trainingDestinationSP - skill.trainingStartSP
283 total_time = skill.trainingEndTime - skill.trainingStartTime
285 spps = float(total_sp) / total_time
287 return (spps, skill.trainingStartTime)
289 def get_training_sp(self, key_id, char_id):
290 """ returns the additional SP that the in-training skill has acquired
292 spps_tuple = self.get_spps(key_id, char_id)
296 spps, start_time = spps_tuple
297 eve_time = time.time() #evetime is utc, right?
298 time_diff = eve_time - start_time
300 return (spps * time_diff)
302 def clear_cache(self):
303 """ Clears all cached data (images and eveapi cache) """
305 util.clean_dir(IMG_CACHE_PATH)
306 util.clean_dir(APICACHE_PATH)
308 logging.getLogger('mevemon').exception("Failed to clear cache")
310 def get_access_mask(self, key_id, ver_code):
313 Returns the access mask that determines what data we have
314 access to on the account.
318 return self.cached_api.account.APIKeyInfo(keyID=key_id, vCode=ver_code).key.accessMask
320 def generate_access_mask_url(self, char_id):
323 Generates a URL to send the user to the page that will help
324 them create an access key with exactly the access mevemon
328 return "https://supporttest.eveonline.com/api/Key/CreatePredefined/%s/%s/false" % (REQUIRED_ACCESS_MASK, char_id)
330 def excepthook(ex_type, value, tb):
331 """ a replacement for the default exception handler that logs errors"""
332 logging.getLogger("mevemon").error('Uncaught exception:',
333 exc_info=(ex_type, value, tb))
336 """ sets up the logging """
337 if not os.path.exists(CONFIG_DIR):
338 os.makedirs(CONFIG_DIR)
340 logger = logging.getLogger("mevemon")
341 logger.setLevel(logging.DEBUG)
343 fileHandler = logging.handlers.RotatingFileHandler(LOGPATH,
345 backupCount=LOGCOUNT)
346 file_fmt = logging.Formatter('%(asctime)s %(name)-10s %(levelname)-5s %(message)s')
347 console_fmt = logging.Formatter('%(name)-10s %(levelname)-5s %(message)s')
348 fileHandler.setFormatter(file_fmt)
349 logger.addHandler(fileHandler)
351 #create console handler
352 console = logging.StreamHandler()
353 console.setLevel(logging.DEBUG)
354 console.setFormatter(console_fmt)
355 logger.addHandler(console)
356 logger.debug("Logging successfully set-up.")
359 if __name__ == "__main__":
361 sys.excepthook = excepthook
365 except KeyboardInterrupt: