def build(self): from eos import db self.__extraDrains = [] self.__ehp = None self.__weaponDPS = None self.__minerYield = None self.__weaponVolley = None self.__droneDPS = None self.__droneVolley = None self.__droneYield = None self.__sustainableTank = None self.__effectiveSustainableTank = None self.__effectiveTank = None self.__calculated = False self.__capStable = None self.__capState = None self.__capUsed = None self.__capRecharge = None self.__calculatedTargets = [] self.factorReload = False self.fleet = None self.boostsFits = set() self.gangBoosts = None self.ecmProjectedStr = 1 self.extraAttributes = ModifiedAttributeDict(self) self.extraAttributes.original = self.EXTRA_ATTRIBUTES self.ship = Ship(db.getItem(self.shipID)) if self.shipID is not None else None if self.ship is not None: self.mode = self.ship.checkModeItem(db.getItem(self.modeID) if self.modeID else None) else: self.mode = None
def importXml(cls, text): doc = xml.dom.minidom.parseString(text.encode("utf-8")) fittings = doc.getElementsByTagName("fittings").item(0) fittings = fittings.getElementsByTagName("fitting") fits = [] from eos import db for fitting in fittings: f = Fit() f.name = fitting.getAttribute("name") shipType = fitting.getElementsByTagName("shipType").item(0).getAttribute("value") f.ship = Ship(db.getItem(shipType)) hardwares = fitting.getElementsByTagName("hardware") for hardware in hardwares: try: moduleName = hardware.getAttribute("type") item = db.getItem(moduleName, eager="group.category") if item: if item.category.name == "Drone": d = Drone(item) d.amount = int(hardware.getAttribute("qty")) f.drones.append(d) else: m = Module(item) if m.isValidState(State.ACTIVE): m.state = State.ACTIVE f.modules.append(m) except Exception: continue fits.append(f) return fits
def build(self): from eos import db self.__extraDrains = [] self.__ehp = None self.__weaponDPS = None self.__minerYield = None self.__weaponVolley = None self.__droneDPS = None self.__droneVolley = None self.__droneYield = None self.__sustainableTank = None self.__effectiveSustainableTank = None self.__effectiveTank = None self.__calculated = False self.__capStable = None self.__capState = None self.__capUsed = None self.__capRecharge = None self.__calculatedTargets = [] self.factorReload = False self.fleet = None self.boostsFits = set() self.gangBoosts = None self.ecmProjectedStr = 1 self.extraAttributes = ModifiedAttributeDict(self) self.extraAttributes.original = self.EXTRA_ATTRIBUTES self.ship = Ship(db.getItem( self.shipID)) if self.shipID is not None else None if self.ship is not None: self.mode = self.ship.checkModeItem( db.getItem(self.modeID) if self.modeID else None) else: self.mode = None
def importDna(cls, string): from eos import db info = string.split(":") f = Fit() f.ship = Ship(db.getItem(int(info[0]))) f.name = "{0} - DNA Imported".format(f.ship.item.name) for itemInfo in info[1:]: if itemInfo: itemID, amount = itemInfo.split(";") item = db.getItem(int(itemID), eager="group.category") if item.category.name == "Drone": d = Drone(item) d.amount = int(amount) f.drones.append(d) elif item.category.name == "Charge": for i in xrange(int(amount)): for mod in f.modules: if (mod.isValidCharge(item) and mod.charge == None): mod.charge = item break; else: for i in xrange(int(amount)): try: m = Module(item) f.modules.append(m) except: pass if m.isValidState(State.ACTIVE): m.state = State.ACTIVE return f
def importCrest(cls, info): from eos import db import urllib2 import json try: response = urllib2.urlopen("https://public-crest.eveonline.com/killmails/%s/%s/" % info) except: return kill = (json.loads(response.read()))['victim'] fit = Fit() fit.ship = Ship(db.getItem(kill['shipType']['name'])) fit.name = "CREST: %s's %s" % (kill['character']['name'], kill['shipType']['name']) # sort based on flag to get proper rack position items = sorted(kill['items'], key=lambda k: k['flag']) # We create a relation between module flag and module position on fit at time of append: # this allows us to know which module to apply charges to if need be (see below) flagMap = {} # Charges may show up before or after the module. We process modules first, # storing any charges that are fitted in a dict and noting their flag (module). charges = {} for mod in items: if mod['flag'] == 5: # throw out cargo continue item = db.getItem(mod['itemType']['name'], eager="group.category") if item.category.name == "Drone": d = Drone(item) d.amount = mod['quantityDropped'] if 'quantityDropped' in mod else mod['quantityDestroyed'] fit.drones.append(d) elif item.category.name == "Charge": charges[mod['flag']] = item else: m = Module(item) if m.isValidState(State.ACTIVE): m.state = State.ACTIVE fit.modules.append(m) flagMap[mod['flag']] = fit.modules.index(m) for flag, item in charges.items(): # we do not need to verify valid charge as it comes directly from CCP fit.modules[flagMap[flag]].charge = item return fit
def populateSkillTree(self, data): if data is None: return root = self.root tree = self.fittingsTreeCtrl tree.DeleteChildren(root) sEsi = Esi.getInstance() dict = {} fits = data for fit in fits: if fit['fitting_id'] in sEsi.fittings_deleted: continue ship = getItem(fit['ship_type_id']) if ship is None: pyfalog.debug('Cannot find ship type id: {}'.format(fit['ship_type_id'])) continue if ship.name not in dict: dict[ship.name] = [] dict[ship.name].append(fit) for name, fits in dict.items(): shipID = tree.AppendItem(root, name) for fit in fits: fitId = tree.AppendItem(shipID, fit['name']) tree.SetItemData(fitId, json.dumps(fit)) tree.SortChildren(root)
def requiredSkills(self): if self.__requiredSkills is None: # This import should be here to make sure it's fully initialized from eos import db requiredSkills = OrderedDict() self.__requiredSkills = requiredSkills # Map containing attribute IDs we may need for required skills # { requiredSkillX : requiredSkillXLevel } srqIDMap = {182: 277, 183: 278, 184: 279, 1285: 1286, 1289: 1287, 1290: 1288} combinedAttrIDs = set(srqIDMap.iterkeys()).union(set(srqIDMap.itervalues())) # Map containing result of the request # { attributeID : attributeValue } skillAttrs = {} # Get relevant attribute values from db (required skill IDs and levels) for our item for attrInfo in db.directAttributeRequest((self.ID,), tuple(combinedAttrIDs)): attrID = attrInfo[1] attrVal = attrInfo[2] skillAttrs[attrID] = attrVal # Go through all attributeID pairs for srqIDAtrr, srqLvlAttr in srqIDMap.iteritems(): # Check if we have both in returned result if srqIDAtrr in skillAttrs and srqLvlAttr in skillAttrs: skillID = int(skillAttrs[srqIDAtrr]) skillLvl = skillAttrs[srqLvlAttr] # Fetch item from database and fill map item = db.getItem(skillID) requiredSkills[item] = skillLvl return self.__requiredSkills
def deleteFitting(self, event): sEsi = Esi.getInstance() selection = self.fitView.fitSelection if not selection: return data = json.loads(self.fitTree.fittingsTreeCtrl.GetItemData(selection)) with wx.MessageDialog( self, _t("Do you really want to delete {} ({}) from EVE?").format( (data['name'], getItem(data['ship_type_id']).name)), _t("Confirm Delete"), wx.YES | wx.NO | wx.ICON_QUESTION) as dlg: if dlg.ShowModal() == wx.ID_YES: activeChar = self.getActiveCharacter() if activeChar is None: return try: sEsi.delFitting(activeChar, data['fitting_id']) # repopulate the fitting list self.fitTree.populateSkillTree(self.fittings) self.fitView.update([]) except requests.exceptions.ConnectionError: msg = _t( "Connection error, please check your internet connection" ) pyfalog.error(msg) self.statusbar.SetStatusText(msg)
def importXml(cls, text): doc = xml.dom.minidom.parseString(text.encode("utf-8")) fittings = doc.getElementsByTagName("fittings").item(0) fittings = fittings.getElementsByTagName("fitting") fits = [] from eos import db for fitting in fittings: f = Fit() f.name = fitting.getAttribute("name") # <localized hint="Maelstrom">Maelstrom</localized> shipType = fitting.getElementsByTagName("shipType").item(0).getAttribute("value") try: f.ship = Ship(db.getItem(shipType)) except: continue hardwares = fitting.getElementsByTagName("hardware") for hardware in hardwares: try: moduleName = hardware.getAttribute("type") try: item = db.getItem(moduleName, eager="group.category") except: continue if item: if item.category.name == "Drone": d = Drone(item) d.amount = int(hardware.getAttribute("qty")) f.drones.append(d) else: try: m = Module(item) # When item can't be added to any slot (unknown item or just charge), ignore it except ValueError: continue if m.isValidState(State.ACTIVE): m.state = State.ACTIVE f.modules.append(m) except KeyboardInterrupt: continue fits.append(f) return fits
def importXml(cls, text): doc = xml.dom.minidom.parseString(text.encode("utf-8")) fittings = doc.getElementsByTagName("fittings").item(0) fittings = fittings.getElementsByTagName("fitting") fits = [] from eos import db for fitting in fittings: f = Fit() f.name = fitting.getAttribute("name") # <localized hint="Maelstrom">Maelstrom</localized> shipType = fitting.getElementsByTagName("shipType").item( 0).getAttribute("value") try: f.ship = Ship(db.getItem(shipType)) except: continue hardwares = fitting.getElementsByTagName("hardware") for hardware in hardwares: try: moduleName = hardware.getAttribute("type") try: item = db.getItem(moduleName, eager="group.category") except: continue if item: if item.category.name == "Drone": d = Drone(item) d.amount = int(hardware.getAttribute("qty")) f.drones.append(d) else: try: m = Module(item) # When item can't be added to any slot (unknown item or just charge), ignore it except ValueError: continue if m.isValidState(State.ACTIVE): m.state = State.ACTIVE f.modules.append(m) except KeyboardInterrupt: continue fits.append(f) return fits
def displayFit(self, event): selection = self.fittingsTreeCtrl.GetSelection() fit = json.loads(self.fittingsTreeCtrl.GetPyData(selection)) list = [] for item in fit['items']: try: cargo = Cargo(getItem(item['type']['id'])) cargo.amount = item['quantity'] list.append(cargo) except: pass self.parent.fitView.fitSelection = selection self.parent.fitView.update(list)
def fetchPrices(cls, prices): """Fetch all prices passed to this method""" # Dictionary for our price objects priceMap = {} # Check all provided price objects, and add invalid ones to dictionary for price in prices: if not price.isValid: priceMap[price.typeID] = price if len(priceMap) == 0: return # Set of items which are still to be requested from this service toRequest = set() # Compose list of items we're going to request for typeID in priceMap: # Get item object item = db.getItem(typeID) # We're not going to request items only with market group, as eve-central # doesn't provide any data for items not on the market if item is not None and item.marketGroupID: toRequest.add(typeID) # Do not waste our time if all items are not on the market if len(toRequest) == 0: return sFit = Fit.getInstance() if len(cls.sources.keys()) == 0: pyfalog.warn('No price source can be found') return # attempt to find user's selected price source, otherwise get first one sourceCls = cls.sources.get(sFit.serviceFittingOptions["priceSource"], cls.sources[cls.sources.keys()[0]]) sourceCls(toRequest, cls.systemsList[sFit.serviceFittingOptions["priceSystem"]], priceMap) # if we get to this point, then we've got an error. Set to REREQUEST delay for typeID in priceMap.keys(): priceobj = priceMap[typeID] priceobj.time = time.time() + REREQUEST priceobj.failed = True
def deleteFitting(self, event): sEsi = Esi.getInstance() selection = self.fitView.fitSelection if not selection: return data = json.loads(self.fitTree.fittingsTreeCtrl.GetItemData(selection)) dlg = wx.MessageDialog( self, "Do you really want to delete %s (%s) from EVE?" % (data['name'], getItem(data['ship_type_id']).name), "Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION) if dlg.ShowModal() == wx.ID_YES: try: sEsi.delFitting(self.getActiveCharacter(), data['fitting_id']) except requests.exceptions.ConnectionError: msg = "Connection error, please check your internet connection" pyfalog.error(msg) self.statusbar.SetStatusText(msg)
def deleteFitting(self, event): self.statusbar.SetStatusText("") sEsi = Esi.getInstance() selection = self.fitView.fitSelection if not selection: return data = json.loads(self.fitTree.fittingsTreeCtrl.GetItemData(selection)) with wx.MessageDialog( self, _t("Do you really want to delete {} ({}) from EVE?").format( data['name'], getItem(data['ship_type_id']).name), _t("Confirm Delete"), wx.YES | wx.NO | wx.ICON_QUESTION) as dlg: if dlg.ShowModal() == wx.ID_YES: activeChar = self.getActiveCharacter() if activeChar is None: return try: try: sEsi.delFitting(activeChar, data['fitting_id']) # repopulate the fitting list self.fitTree.populateSkillTree(self.fittings) self.fitView.update([]) except APIException as ex: pyfalog.error(ex) self.statusbar.SetStatusText( "Failed to delete fit: ESI error {} received - {}". format(ex.status_code, ex.response["error"])) try: ESIExceptionHandler(ex) except: # don't need to do anything - we should already have error code in the status pass except requests.exceptions.ConnectionError: msg = _t( "Connection error, please check your internet connection" ) pyfalog.error(msg) self.statusbar.SetStatusText(msg)
def displayFit(self, event): selection = self.fittingsTreeCtrl.GetSelection() data = self.fittingsTreeCtrl.GetItemData(selection) if data is None: event.Skip() return fit = json.loads(data) list = [] for item in fit['items']: try: cargo = Cargo(getItem(item['type_id'])) cargo.amount = item['quantity'] list.append(cargo) except Exception as e: pyfalog.critical("Exception caught in displayFit") pyfalog.critical(e) self.parent.fitView.fitSelection = selection self.parent.fitView.update(list)
def populateSkillTree(self, data): if data is None: return root = self.root tree = self.fittingsTreeCtrl tree.DeleteChildren(root) dict = {} fits = data for fit in fits: ship = getItem(fit['ship_type_id']) if ship.name not in dict: dict[ship.name] = [] dict[ship.name].append(fit) for name, fits in dict.items(): shipID = tree.AppendItem(root, name) for fit in fits: fitId = tree.AppendItem(shipID, fit['name']) tree.SetItemData(fitId, json.dumps(fit)) tree.SortChildren(root)
def importEftCfg(cls, shipname, contents): """Handle import from EFT config store file""" # Check if we have such ship in database, bail if we don't from eos import db try: db.getItem(shipname) except: return # If client didn't take care of encoding file contents into Unicode, # do it using fallback encoding ourselves if isinstance(contents, str): contents = unicode(contents, "cp1252") # List for fits fits = [] # List for starting line numbers for each fit fitIndices = [] # Separate string into lines lines = re.split('[\n\r]+', contents) for line in lines: # Detect fit header if line[:1] == "[" and line[-1:] == "]": # Line index where current fit starts startPos = lines.index(line) fitIndices.append(startPos) for i, startPos in enumerate(fitIndices): # End position is last file line if we're trying to get it for last fit, # or start position of next fit minus 1 endPos = len(lines) if i == len(fitIndices) - 1 else fitIndices[i + 1] # Finally, get lines for current fitting fitLines = lines[startPos:endPos] try: # Create fit object f = Fit() # Strip square brackets and pull out a fit name f.name = fitLines[0][1:-1] # Assign ship to fitting f.ship = Ship(db.getItem(shipname)) for i in range(1, len(fitLines)): line = fitLines[i] # Parse line into some data we will need misc = re.match("(Drones|Implant|Booster)_(Active|Inactive)=(.+)",line) if misc: entityType = misc.group(1) entityState = misc.group(2) entityData = misc.group(3) if entityType == "Drones": droneData = re.match("(.+),([0-9]+)", entityData) # Get drone name and attempt to detect drone number droneName = droneData.group(1) if droneData else entityData droneAmount = int(droneData.group(2)) if droneData else 1 # Bail if we can't get item or it's not from drone category try: droneItem = db.getItem(droneName, eager="group.category") except: continue if droneItem.category.name != "Drone": continue # Add drone to the fitting d = Drone(droneItem) d.amount = droneAmount if entityState == "Active": d.amountActive = droneAmount elif entityState == "Inactive": d.amountActive = 0 f.drones.append(d) elif entityType == "Implant": # Bail if we can't get item or it's not from implant category try: implantItem = db.getItem(entityData, eager="group.category") except: continue if implantItem.category.name != "Implant": continue # Add implant to the fitting imp = Implant(implantItem) if entityState == "Active": imp.active = True elif entityState == "Inactive": imp.active = False f.implants.append(imp) elif entityType == "Booster": # Bail if we can't get item or it's not from implant category try: boosterItem = db.getItem(entityData, eager="group.category") except: continue # All boosters have implant category if boosterItem.category.name != "Implant": continue # Add booster to the fitting b = Booster(boosterItem) if entityState == "Active": b.active = True elif entityState == "Inactive": b.active = False f.boosters.append(b) # If we don't have any prefixes, then it's a module else: withCharge = re.match("(.+),(.+)", line) modName = withCharge.group(1) if withCharge else line chargeName = withCharge.group(2) if withCharge else None # If we can't get module item, skip it try: modItem = db.getItem(modName) except: continue # Create module and activate it if it's activable m = Module(modItem) if m.isValidState(State.ACTIVE): m.state = State.ACTIVE # Add charge to mod if applicable, on any errors just don't add anything if chargeName: try: chargeItem = db.getItem(chargeName, eager="group.category") if chargeItem.category.name == "Charge": m.charge = chargeItem except: pass # Append module to fit f.modules.append(m) # Append fit to list of fits fits.append(f) # Skip fit silently if we get an exception except Exception: pass return fits
def importEft(cls, eftString): from eos import db offineSuffix = " /OFFLINE" fit = cls() eftString = eftString.strip() lines = re.split('[\n\r]+', eftString) info = lines[0][1:-1].split(",", 1) if len(info) == 2: shipType = info[0].strip() fitName = info[1].strip() else: shipType = info[0].strip() fitName = "Imported %s" % shipType try: fit.ship = Ship(db.getItem(shipType)) fit.name = fitName except: return droneMap = {} for i in range(1, len(lines)): line = lines[i] setOffline = line.endswith(offineSuffix) if setOffline == True: line = line[:len(line) - len(offineSuffix)] modAmmo = line.split(",") modDrone = modAmmo[0].split(" x") if len(modAmmo) == 2: ammoName = modAmmo[1].strip() else: ammoName = None modName = modDrone[0].strip() if len(modDrone) == 2: droneAmount = modDrone[1].strip() else: droneAmount = None try: item = db.getItem(modName, eager="group.category") except: try: item = db.getItem(modAmmo[0], eager="group.category") except: continue if item.category.name == "Drone": droneAmount = int(droneAmount) if droneAmount is not None else 1 if not modName in droneMap: droneMap[modName] = 0 droneMap[modName] += droneAmount elif item.category.name == "Implant": fit.implants.append(Implant(item)) else: m = Module(item) if ammoName: try: m.charge = db.getItem(ammoName) except: pass if setOffline == True and m.isValidState(State.OFFLINE): m.state = State.OFFLINE elif m.isValidState(State.ACTIVE): m.state = State.ACTIVE fit.modules.append(m) for droneName in droneMap: d = Drone(db.getItem(droneName)) d.amount = droneMap[droneName] fit.drones.append(d) return fit
def fetchPrices(cls, prices): """Fetch all prices passed to this method""" # Dictionary for our price objects priceMap = {} # Check all provided price objects, and add invalid ones to dictionary for price in prices: if not price.isValid: priceMap[price.typeID] = price if len(priceMap) == 0: return # Set of items which are still to be requested from this service toRequest = set() # Compose list of items we're going to request for typeID in priceMap: # Get item object item = db.getItem(typeID) # We're not going to request items only with market group, as eve-central # doesn't provide any data for items not on the market if item is not None and item.marketGroupID: toRequest.add(typeID) # Do not waste our time if all items are not on the market if len(toRequest) == 0: return # This will store POST data for eve-central data = [] sFit = Fit.getInstance() # Base request URL baseurl = "https://eve-central.com/api/marketstat" data.append(("usesystem", cls.systemsList[sFit.serviceFittingOptions["priceSystem"]])) # Use Jita for market for typeID in toRequest: # Add all typeID arguments data.append(("typeid", typeID)) # Attempt to send request and process it try: network = Network.getInstance() data = network.request(baseurl, network.PRICES, data) xml = minidom.parse(data) types = xml.getElementsByTagName("marketstat").item(0).getElementsByTagName("type") # Cycle through all types we've got from request for type_ in types: # Get data out of each typeID details tree typeID = int(type_.getAttribute("id")) sell = type_.getElementsByTagName("sell").item(0) # If price data wasn't there, set price to zero try: percprice = float(sell.getElementsByTagName("percentile").item(0).firstChild.data) except (TypeError, ValueError): pyfalog.warning("Failed to get price for: {0}", type_) percprice = 0 # Fill price data priceobj = priceMap[typeID] priceobj.price = percprice priceobj.time = time.time() + VALIDITY priceobj.failed = None # delete price from working dict del priceMap[typeID] # If getting or processing data returned any errors except TimeoutError: # Timeout error deserves special treatment pyfalog.warning("Price fetch timout") for typeID in priceMap.keys(): priceobj = priceMap[typeID] priceobj.time = time.time() + TIMEOUT priceobj.failed = True del priceMap[typeID] except: # all other errors will pass and continue onward to the REREQUEST delay pyfalog.warning("Caught exception in fetchPrices") pass # if we get to this point, then we've got an error. Set to REREQUEST delay for typeID in priceMap.keys(): priceobj = priceMap[typeID] priceobj.time = time.time() + REREQUEST priceobj.failed = True
def fetchPrices(cls, prices, fetchTimeout, validityOverride): """Fetch all prices passed to this method""" # Dictionary for our price objects priceMap = {} # Check all provided price objects, and add those we want to update to # dictionary for price in prices: if not price.isValid(validityOverride): priceMap[price.typeID] = price if not priceMap: return # Compose list of items we're going to request for typeID in tuple(priceMap): # Get item object item = db.getItem(typeID) # We're not going to request items only with market group, as our current market # sources do not provide any data for items not on the market if item is None: continue if not item.marketGroupID: priceMap[typeID].update(PriceStatus.notSupported) del priceMap[typeID] continue if not priceMap: return sFit = Fit.getInstance() if len(cls.sources.keys()) == 0: pyfalog.warn('No price source can be found') return # attempt to find user's selected price source, otherwise get first one sourceAll = list(cls.sources.keys()) sourcePrimary = sFit.serviceFittingOptions["priceSource"] if sFit.serviceFittingOptions["priceSource"] in sourceAll else sourceAll[0] # Format: {source name: timeout weight} sources = {sourcePrimary: len(sourceAll)} for source in sourceAll: if source == sourcePrimary: continue sources[source] = min(sources.values()) - 1 timeoutWeightMult = fetchTimeout / sum(sources.values()) # Record timeouts as it will affect our final decision timedOutSources = {} for source, timeoutWeight in sources.items(): pyfalog.info('Trying {}'.format(source)) timedOutSources[source] = False sourceFetchTimeout = timeoutWeight * timeoutWeightMult try: sourceCls = cls.sources.get(source) sourceCls(priceMap, cls.systemsList[sFit.serviceFittingOptions["priceSystem"]], sourceFetchTimeout) except TimeoutError: pyfalog.warning("Price fetch timeout for source {}".format(source)) timedOutSources[source] = True except Exception as e: pyfalog.warn('Failed to fetch prices from price source {}: {}'.format(source, e)) # Sources remove price map items as they fetch info, if none remain then we're done if not priceMap: break # If we get to this point, then we've failed to get price with all our sources # If all sources failed due to timeouts, set one status if all(to is True for to in timedOutSources.values()): for typeID in priceMap.keys(): priceMap[typeID].update(PriceStatus.fetchTimeout) # If some sources failed due to any other reason, then it's definitely not network # timeout and we just set another status else: for typeID in priceMap.keys(): priceMap[typeID].update(PriceStatus.fetchFail)
def fetchPrices(cls, prices): """Fetch all prices passed to this method""" # Dictionary for our price objects priceMap = {} # Check all provided price objects, and add invalid ones to dictionary for price in prices: if not price.isValid: priceMap[price.typeID] = price if len(priceMap) == 0: return # Set of items which are still to be requested from this service toRequest = set() # Compose list of items we're going to request for typeID in priceMap: # Get item object item = db.getItem(typeID) # We're not going to request items only with market group, as eve-central # doesn't provide any data for items not on the market if item is not None and item.marketGroupID: toRequest.add(typeID) # Do not waste our time if all items are not on the market if len(toRequest) == 0: return sFit = Fit.getInstance() if len(cls.sources.keys()) == 0: pyfalog.warn('No price source can be found') return # attempt to find user's selected price source, otherwise get first one sourcesToTry = list(cls.sources.keys()) curr = sFit.serviceFittingOptions["priceSource"] if sFit.serviceFittingOptions["priceSource"] in sourcesToTry else sourcesToTry[0] while len(sourcesToTry) > 0: sourcesToTry.remove(curr) try: sourceCls = cls.sources.get(curr) sourceCls(toRequest, cls.systemsList[sFit.serviceFittingOptions["priceSystem"]], priceMap) break # If getting or processing data returned any errors except TimeoutError: # Timeout error deserves special treatment pyfalog.warning("Price fetch timout") for typeID in priceMap.keys(): priceobj = priceMap[typeID] priceobj.time = time.time() + TIMEOUT priceobj.failed = True del priceMap[typeID] except Exception as ex: # something happened, try another source pyfalog.warn('Failed to fetch prices from price source {}: {}'.format(curr, ex, sourcesToTry[0])) if len(sourcesToTry) > 0: pyfalog.warn('Trying {}'.format(sourcesToTry[0])) curr = sourcesToTry[0] # if we get to this point, then we've got an error in all of our sources. Set to REREQUEST delay for typeID in priceMap.keys(): priceobj = priceMap[typeID] priceobj.time = time.time() + REREQUEST priceobj.failed = True
def deleteFitting(self, event): sEsi = Esi.getInstance() selection = self.fitView.fitSelection if not selection: return data = json.loads(self.fitTree.fittingsTreeCtrl.GetItemData(selection)) dlg = wx.MessageDialog(self, "Do you really want to delete %s (%s) from EVE?" % (data['name'], getItem(data['ship_type_id']).name), "Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION) if dlg.ShowModal() == wx.ID_YES: try: sEsi.delFitting(self.getActiveCharacter(), data['fitting_id']) # repopulate the fitting list self.fitTree.populateSkillTree(self.fittings) self.fitView.update([]) except requests.exceptions.ConnectionError: msg = "Connection error, please check your internet connection" pyfalog.error(msg) self.statusbar.SetStatusText(msg)
def fetchPrices(cls, prices): """Fetch all prices passed to this method""" # Dictionary for our price objects priceMap = {} # Check all provided price objects, and add invalid ones to dictionary for price in prices: if not price.isValid: priceMap[price.typeID] = price if len(priceMap) == 0: return # Set of items which are still to be requested from this service toRequest = set() # Compose list of items we're going to request for typeID in tuple(priceMap): # Get item object item = db.getItem(typeID) # We're not going to request items only with market group, as eve-central # doesn't provide any data for items not on the market if item is None: continue if not item.marketGroupID: priceMap[typeID].status = PriceStatus.notSupported del priceMap[typeID] continue toRequest.add(typeID) # Do not waste our time if all items are not on the market if len(toRequest) == 0: return sFit = Fit.getInstance() if len(cls.sources.keys()) == 0: pyfalog.warn('No price source can be found') return # attempt to find user's selected price source, otherwise get first one sourcesToTry = list(cls.sources.keys()) curr = sFit.serviceFittingOptions[ "priceSource"] if sFit.serviceFittingOptions[ "priceSource"] in sourcesToTry else sourcesToTry[0] while len(sourcesToTry) > 0: sourcesToTry.remove(curr) try: sourceCls = cls.sources.get(curr) sourceCls( toRequest, cls.systemsList[sFit.serviceFittingOptions["priceSystem"]], priceMap) break # If getting or processing data returned any errors except TimeoutError: # Timeout error deserves special treatment pyfalog.warning("Price fetch timout") for typeID in tuple(priceMap): priceobj = priceMap[typeID] priceobj.time = time.time() + TIMEOUT priceobj.status = PriceStatus.fail del priceMap[typeID] except Exception as ex: # something happened, try another source pyfalog.warn( 'Failed to fetch prices from price source {}: {}'.format( curr, ex, sourcesToTry[0])) if len(sourcesToTry) > 0: pyfalog.warn('Trying {}'.format(sourcesToTry[0])) curr = sourcesToTry[0] # if we get to this point, then we've got an error in all of our sources. Set to REREQUEST delay for typeID in priceMap.keys(): priceobj = priceMap[typeID] priceobj.time = time.time() + REREQUEST priceobj.status = PriceStatus.fail
def fetchPrices(cls, prices, fetchTimeout, validityOverride): """Fetch all prices passed to this method""" # Dictionary for our price objects priceMap = {} # Check all provided price objects, and add those we want to update to # dictionary for price in prices: if not price.isValid(validityOverride): priceMap[price.typeID] = price if not priceMap: return # Compose list of items we're going to request for typeID in tuple(priceMap): # Get item object item = db.getItem(typeID) # We're not going to request items only with market group, as our current market # sources do not provide any data for items not on the market if item is None: continue if not item.marketGroupID: priceMap[typeID].update(PriceStatus.notSupported) del priceMap[typeID] continue if not priceMap: return sFit = Fit.getInstance() if len(cls.sources.keys()) == 0: pyfalog.warn('No price source can be found') return # attempt to find user's selected price source, otherwise get first one sourceAll = list(cls.sources.keys()) sourcePrimary = sFit.serviceFittingOptions["priceSource"] if sFit.serviceFittingOptions["priceSource"] in sourceAll else sourceAll[0] # Format: {source name: timeout weight} sources = {sourcePrimary: len(sourceAll)} for source in sourceAll: if source == sourcePrimary: continue sources[source] = min(sources.values()) - 1 # Record timeouts as it will affect our final decision timedOutSources = {} remainingTime = fetchTimeout for source in sorted(sources, key=sources.get, reverse=True): timeBefore = timeit.default_timer() pyfalog.info('Trying {}'.format(source)) timedOutSources[source] = False # Time we allocate for a source depends on source weight and remaining time sourceFetchTimeout = remainingTime * sources[source] / sum(sources.values()) try: sourceCls = cls.sources.get(source) sourceCls(priceMap, cls.systemsList[sFit.serviceFittingOptions["priceSystem"]], sourceFetchTimeout) except TimeoutError: pyfalog.warning("Price fetch timeout for source {}".format(source)) timedOutSources[source] = True except (KeyboardInterrupt, SystemExit): raise except Exception as e: pyfalog.warn('Failed to fetch prices from price source {}: {}'.format(source, e)) # Sources remove price map items as they fetch info, if none remain then we're done if not priceMap: break timeAfter = timeit.default_timer() # Remove source so it doesn't affect time weights of sources we're going to use next del sources[source] remainingTime -= timeAfter - timeBefore # No time remaining (should not happen) - mark remaining sources as timeout if remainingTime <= 0: for source in sources: timedOutSources[source] = True break # If we get to this point, then we've failed to get price with all our sources # If all sources failed due to timeouts, set one status if all(to is True for to in timedOutSources.values()): for typeID in priceMap.keys(): priceMap[typeID].update(PriceStatus.fetchTimeout) # If some sources failed due to any other reason, then it's definitely not network # timeout and we just set another status else: for typeID in priceMap.keys(): priceMap[typeID].update(PriceStatus.fetchFail)