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
39 #ugly hack to check maemo version. any better way?
40 if hasattr(hildon, "StackableWindow"):
41 from ui.fremantle import gui
43 from ui.diablo import gui
46 """ The controller class for mEvemon. The intent is to help
47 abstract the EVE API and settings code from the UI code.
50 self.program = hildon.Program()
51 self.connect_to_network()
52 self.settings = settings.Settings()
53 self.cached_api = eveapi.EVEAPIConnection( cacheHandler = \
54 apicache.cache_handler(debug=False))
55 self.gui = gui.mEveMonUI(self)
61 def quit(self, *args):
64 def get_auth(self, uid):
65 """ Returns an authentication object to be used for eveapi calls
66 that require authentication.
68 api_key = self.settings.get_api_key(uid)
71 auth = self.cached_api.auth(userID=uid, apiKey=api_key)
73 self.gui.report_error(str(e))
74 logging.getLogger('mevemon').exception("Failed to get character name")
79 def get_char_sheet(self, uid, char_id):
80 """ Returns an object containing information about the character specified
81 by the provided character ID.
84 sheet = self.get_auth(uid).character(char_id).CharacterSheet()
86 self.gui.report_error(str(e))
87 logging.getLogger('mevemon').exception("Failed to get character name")
92 def charid2uid(self, char_id):
93 """ Takes a character ID and returns the user ID of the account containing
96 Returns None if the character isn't found in any of the registered accounts.
99 acct_dict = self.settings.get_accounts()
101 for uid, api_key in acct_dict.items():
102 auth = self.cached_api.auth(userID=uid, apiKey=api_key)
104 api_char_list = auth.account.Characters()
105 characters = api_char_list.characters
109 for character in characters:
110 if character.characterID == char_id:
114 def char_id2name(self, char_id):
115 """ Takes a character ID and returns the character name associated with
117 The EVE API accepts a comma-separated list of IDs, but for now we
118 will just handle a single ID.
121 chars = self.cached_api.eve.CharacterName(ids=char_id).characters
122 name = chars[0].characterName
124 self.gui.report_error(str(e))
125 logging.getLogger('mevemon').exception("Failed to get character name")
130 def char_name2id(self, name):
131 """ Takes the name of an EVE character and returns the characterID.
133 The EVE api accepts a comma separated list of names, but for now
134 we will just handle single names/
137 chars = self.cached_api.eve.CharacterID(names=name).characters
138 char_id = chars[0].characterID
139 char_name = chars[0].name
141 self.gui.report_error(str(e))
142 logging.getLogger('mevemon').exception("Failed to get ID")
147 def get_chars_from_acct(self, uid):
148 """ Returns a list of characters associated with the provided user ID.
150 auth = self.get_auth(uid)
155 api_char_list = auth.account.Characters()
156 char_list = [char.name for char in api_char_list.characters]
158 self.gui.report_error(str(e))
159 logging.getLogger('mevemon').exception("Failed to get character list")
164 def get_characters(self):
165 """ Returns a list of (character_name, image_path, uid) tuples from all the
166 accounts that are registered to mEveMon.
168 If there is an authentication issue, then instead of adding a valid
169 pair to the list, it appends an 'error message'
173 err_img = "/usr/share/mevemon/imgs/error.jpg"
174 err_txt = "Problem fetching info for account (or no accounts added)"
176 placeholder_chars = (err_txt, err_img, None)
178 acct_dict = self.settings.get_accounts()
180 return [placeholder_chars]
182 for uid in acct_dict.keys():
183 char_names = self.get_chars_from_acct(uid)
186 ui_char_list.append((err_txt + "\t(UID: %s)" % uid, err_img, None))
188 # append each char we get to the list we'll return to the
190 for char_name in char_names:
191 ui_char_list.append((char_name, self.get_portrait(char_name, 64) , uid) )
195 def get_portrait(self, char_name, size):
196 """ Returns the file path of the retrieved portrait
198 char_id = self.char_name2id(char_name)
200 return fetchimg.portrait_filename(char_id, size)
202 def get_skill_tree(self):
203 """ Returns an object from eveapi containing skill tree info
206 tree = self.cached_api.eve.SkillTree()
208 self.gui.report_error(str(e))
209 logging.getLogger('mevemon').exception("Failed to get skill-in-training:")
214 def get_skill_in_training(self, uid, char_id):
215 """ Returns an object from eveapi containing information about the
216 current skill in training
219 skill = self.get_auth(uid).character(char_id).SkillInTraining()
221 self.gui.report_error(str(e))
222 logging.getLogger('mevemon').exception("Failed to get skill-in-training:")
227 def connection_cb(self, connection, event, mgc):
228 """ I'm not sure why we need this, but connection.connect() won't work
229 without it, even empty.
234 def connect_to_network(self):
235 """ This will connect to the default network if avaliable, or pop up the
236 connection dialog to select a connection.
237 Running this when we start the program ensures we are connected to a
240 connection = conic.Connection()
242 connection.connect("connection-event", self.connection_cb, 0xAA55)
243 assert(connection.request_connection(conic.CONNECT_FLAG_NONE))
246 def get_sp(self, uid, char_id):
247 """ Adds up the SP for all known skills, then calculates the SP gained
248 from an in-training skill.
252 sheet = self.get_char_sheet(uid, char_id)
253 for skill in sheet.skills:
254 actual_sp += skill.skillpoints
256 live_sp = actual_sp + self.get_training_sp(uid, char_id)
260 def get_spps(self, uid, char_id):
261 """ Calculate and returns the skill points per hour for the given character.
263 skill = self.get_skill_in_training(uid, char_id)
265 if not skill.skillInTraining:
268 total_sp = skill.trainingDestinationSP - skill.trainingStartSP
269 total_time = skill.trainingEndTime - skill.trainingStartTime
271 spps = float(total_sp) / total_time
273 return (spps, skill.trainingStartTime)
275 def get_training_sp(self, uid, char_id):
276 """ returns the additional SP that the in-training skill has acquired
278 spps_tuple = self.get_spps(uid, char_id)
282 spps, start_time = spps_tuple
283 eve_time = time.time() #evetime is utc, right?
284 time_diff = eve_time - start_time
286 return (spps * time_diff)
288 def clear_cache(self):
289 """ Clears all cached data (images and eveapi cache) """
291 shutil.rmtree(IMG_CACHE_PATH)
292 shutil.rmtree(APICACHE_PATH)
294 logging.getLogger('mevemon').exception("Failed to clear cache")
296 def excepthook(ex_type, value, tb):
297 """ a replacement for the default exception handler that logs errors"""
298 logging.getLogger("mevemon").error('Uncaught exception:',
299 exc_info=(ex_type, value, tb))
302 """ sets up the logging """
303 if not os.path.exists(CONFIG_DIR):
304 os.makedirs(CONFIG_DIR)
306 logger = logging.getLogger("mevemon")
307 logger.setLevel(logging.DEBUG)
309 fileHandler = logging.handlers.RotatingFileHandler(LOGPATH,
311 backupCount=LOGCOUNT)
312 file_fmt = logging.Formatter('%(asctime)s %(name)-10s %(levelname)-5s %(message)s')
313 console_fmt = logging.Formatter('%(name)-10s %(levelname)-5s %(message)s')
314 fileHandler.setFormatter(file_fmt)
315 logger.addHandler(fileHandler)
317 #create console handler
318 console = logging.StreamHandler()
319 console.setLevel(logging.DEBUG)
320 console.setFormatter(console_fmt)
321 logger.addHandler(console)
322 logger.debug("Logging successfully set-up.")
325 if __name__ == "__main__":
327 sys.excepthook = excepthook
331 except KeyboardInterrupt: