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
28 #conic is used for connection handling
31 from eveapi import eveapi
34 import file_settings as settings
35 from constants import LOGPATH, MAXBYTES, LOGCOUNT
37 #ugly hack to check maemo version. any better way?
38 if hasattr(hildon, "StackableWindow"):
39 from ui.fremantle import gui
41 from ui.diablo import gui
44 """ The controller class for mEvemon. The intent is to help
45 abstract the EVE API and settings code from the UI code.
48 self.program = hildon.Program()
49 self.connect_to_network()
50 self.settings = settings.Settings()
51 self.cached_api = eveapi.EVEAPIConnection( cacheHandler = \
52 apicache.cache_handler(debug=False))
53 self.gui = gui.mEveMonUI(self)
59 def quit(self, *args):
62 def get_auth(self, uid):
63 """ Returns an authentication object to be used for eveapi calls
64 that require authentication.
66 api_key = self.settings.get_api_key(uid)
69 auth = self.cached_api.auth(userID=uid, apiKey=api_key)
71 self.gui.report_error(str(e))
72 logging.getLogger('mevemon').exception("Failed to get character name")
77 def get_char_sheet(self, uid, char_id):
78 """ Returns an object containing information about the character specified
79 by the provided character ID.
82 sheet = self.get_auth(uid).character(char_id).CharacterSheet()
84 self.gui.report_error(str(e))
85 logging.getLogger('mevemon').exception("Failed to get character name")
90 def charid2uid(self, char_id):
91 """ Takes a character ID and returns the user ID of the account containing
94 Returns None if the character isn't found in any of the registered accounts.
97 acct_dict = self.settings.get_accounts()
99 for uid, api_key in acct_dict.items():
100 auth = self.cached_api.auth(userID=uid, apiKey=api_key)
102 api_char_list = auth.account.Characters()
103 characters = api_char_list.characters
107 for character in characters:
108 if character.characterID == char_id:
112 def char_id2name(self, char_id):
113 """ Takes a character ID and returns the character name associated with
115 The EVE API accepts a comma-separated list of IDs, but for now we
116 will just handle a single ID.
119 chars = self.cached_api.eve.CharacterName(ids=char_id).characters
120 name = chars[0].characterName
122 self.gui.report_error(str(e))
123 logging.getLogger('mevemon').exception("Failed to get character name")
128 def char_name2id(self, name):
129 """ Takes the name of an EVE character and returns the characterID.
131 The EVE api accepts a comma separated list of names, but for now
132 we will just handle single names/
135 chars = self.cached_api.eve.CharacterID(names=name).characters
136 char_id = chars[0].characterID
137 char_name = chars[0].name
139 self.gui.report_error(str(e))
140 logging.getLogger('mevemon').exception("Failed to get ID")
145 def get_chars_from_acct(self, uid):
146 """ Returns a list of characters associated with the provided user ID.
148 auth = self.get_auth(uid)
153 api_char_list = auth.account.Characters()
154 char_list = [char.name for char in api_char_list.characters]
156 self.gui.report_error(str(e))
157 logging.getLogger('mevemon').exception("Failed to get character list")
162 def get_characters(self):
163 """ Returns a list of (character_name, image_path, uid) tuples from all the
164 accounts that are registered to mEveMon.
166 If there is an authentication issue, then instead of adding a valid
167 pair to the list, it appends an 'error message'
171 err_img = "/usr/share/mevemon/imgs/error.jpg"
172 err_txt = "Problem fetching info for account"
174 placeholder_chars = (err_txt, err_img, None)
176 acct_dict = self.settings.get_accounts()
178 return [placeholder_chars]
180 for uid in acct_dict.keys():
181 char_names = self.get_chars_from_acct(uid)
184 ui_char_list.append((err_txt + "\t(UID: %s)" % uid, err_img, None))
186 # append each char we get to the list we'll return to the
188 for char_name in char_names:
189 ui_char_list.append((char_name, self.get_portrait(char_name, 64) , uid) )
193 def get_portrait(self, char_name, size):
194 """ Returns the file path of the retrieved portrait
196 char_id = self.char_name2id(char_name)
198 return fetchimg.portrait_filename(char_id, size)
200 def get_skill_tree(self):
201 """ Returns an object from eveapi containing skill tree info
204 tree = self.cached_api.eve.SkillTree()
206 self.gui.report_error(str(e))
207 logging.getLogger('mevemon').exception("Failed to get skill-in-training:")
212 def get_skill_in_training(self, uid, char_id):
213 """ Returns an object from eveapi containing information about the
214 current skill in training
217 skill = self.get_auth(uid).character(char_id).SkillInTraining()
219 self.gui.report_error(str(e))
220 logging.getLogger('mevemon').exception("Failed to get skill-in-training:")
225 def connection_cb(self, connection, event, mgc):
226 """ I'm not sure why we need this, but connection.connect() won't work
227 without it, even empty.
232 def connect_to_network(self):
233 """ This will connect to the default network if avaliable, or pop up the
234 connection dialog to select a connection.
235 Running this when we start the program ensures we are connected to a
238 connection = conic.Connection()
240 connection.connect("connection-event", self.connection_cb, 0xAA55)
241 assert(connection.request_connection(conic.CONNECT_FLAG_NONE))
244 def get_sp(self, uid, char_id):
245 """ Adds up the SP for all known skills, then calculates the SP gained
246 from an in-training skill.
250 sheet = self.get_char_sheet(uid, char_id)
251 for skill in sheet.skills:
252 actual_sp += skill.skillpoints
254 live_sp = actual_sp + self.get_training_sp(uid, char_id)
258 def get_spps(self, uid, char_id):
259 """ Calculate and returns the skill points per hour for the given character.
261 skill = self.get_skill_in_training(uid, char_id)
263 if not skill.skillInTraining:
266 total_sp = skill.trainingDestinationSP - skill.trainingStartSP
267 total_time = skill.trainingEndTime - skill.trainingStartTime
269 spps = float(total_sp) / total_time
271 return (spps, skill.trainingStartTime)
273 def get_training_sp(self, uid, char_id):
274 """ returns the additional SP that the in-training skill has acquired
276 spps_tuple = self.get_spps(uid, char_id)
280 spps, start_time = spps_tuple
281 eve_time = time.time() #evetime is utc, right?
282 time_diff = eve_time - start_time
284 return (spps * time_diff)
287 def excepthook(ex_type, value, tb):
288 """ a replacement for the default exception handler that logs errors"""
289 logging.getLogger("mevemon").error('Uncaught exception:',
290 exc_info=(ex_type, value, tb))
293 """ sets up the logging """
295 logger = logging.getLogger("mevemon")
296 logger.setLevel(logging.DEBUG)
298 fileHandler = logging.handlers.RotatingFileHandler(LOGPATH,
300 backupCount=LOGCOUNT)
301 file_fmt = logging.Formatter('%(asctime)s %(name)-10s %(levelname)-5s %(message)s')
302 console_fmt = logging.Formatter('%(name)-10s %(levelname)-5s %(message)s')
303 fileHandler.setFormatter(file_fmt)
304 logger.addHandler(fileHandler)
306 #create console handler
307 console = logging.StreamHandler()
308 console.setLevel(logging.DEBUG)
309 console.setFormatter(console_fmt)
310 logger.addHandler(console)
311 logger.debug("Logging successfully set-up.")
314 if __name__ == "__main__":
316 sys.excepthook = excepthook
320 except KeyboardInterrupt: