diff --git a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py index acdfb398b..6cb611797 100644 --- a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py +++ b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py @@ -90,7 +90,9 @@ class PFGeneralPref(PreferenceView): self.stDefaultSystem.Wrap(-1) priceSizer.Add(self.stDefaultSystem, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) + self.chPriceSource = wx.Choice(panel, choices=sorted(Price.sources.keys())) self.chPriceSystem = wx.Choice(panel, choices=Price.systemsList.keys()) + priceSizer.Add(self.chPriceSource, 1, wx.ALL | wx.EXPAND, 5) priceSizer.Add(self.chPriceSystem, 1, wx.ALL | wx.EXPAND, 5) mainSizer.Add(priceSizer, 0, wx.ALL | wx.EXPAND, 0) @@ -124,6 +126,7 @@ class PFGeneralPref(PreferenceView): self.cbGaugeAnimation.SetValue(self.sFit.serviceFittingOptions["enableGaugeAnimation"]) self.cbExportCharges.SetValue(self.sFit.serviceFittingOptions["exportCharges"]) self.cbOpenFitInNew.SetValue(self.sFit.serviceFittingOptions["openFitInNew"]) + self.chPriceSource.SetStringSelection(self.sFit.serviceFittingOptions["priceSource"]) self.chPriceSystem.SetStringSelection(self.sFit.serviceFittingOptions["priceSystem"]) self.cbShowShipBrowserTooltip.SetValue(self.sFit.serviceFittingOptions["showShipBrowserTooltip"]) self.intDelay.SetValue(self.sFit.serviceFittingOptions["marketSearchDelay"]) @@ -140,6 +143,7 @@ class PFGeneralPref(PreferenceView): self.cbGaugeAnimation.Bind(wx.EVT_CHECKBOX, self.onCBGaugeAnimation) self.cbExportCharges.Bind(wx.EVT_CHECKBOX, self.onCBExportCharges) self.cbOpenFitInNew.Bind(wx.EVT_CHECKBOX, self.onCBOpenFitInNew) + self.chPriceSource.Bind(wx.EVT_CHOICE, self.onPricesSourceSelection) self.chPriceSystem.Bind(wx.EVT_CHOICE, self.onPriceSelection) self.cbShowShipBrowserTooltip.Bind(wx.EVT_CHECKBOX, self.onCBShowShipBrowserTooltip) self.intDelay.Bind(wx.lib.intctrl.EVT_INT, self.onMarketDelayChange) @@ -224,5 +228,9 @@ class PFGeneralPref(PreferenceView): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) event.Skip() + def onPricesSourceSelection(self, event): + source = self.chPriceSource.GetString(self.chPriceSource.GetSelection()) + self.sFit.serviceFittingOptions["priceSource"] = source + PFGeneralPref.register() diff --git a/service/fit.py b/service/fit.py index 94cb67d0a..85c6ccffd 100644 --- a/service/fit.py +++ b/service/fit.py @@ -74,6 +74,7 @@ class Fit(object): "exportCharges": True, "openFitInNew": False, "priceSystem": "Jita", + "priceSource": "eve-central.com", "showShipBrowserTooltip": True, "marketSearchDelay": 250 } diff --git a/service/marketSources/__init__.py b/service/marketSources/__init__.py new file mode 100644 index 000000000..b093a0010 --- /dev/null +++ b/service/marketSources/__init__.py @@ -0,0 +1 @@ +__all__ = ['evecentral', 'evemarketdata'] \ No newline at end of file diff --git a/service/marketSources/evecentral.py b/service/marketSources/evecentral.py new file mode 100644 index 000000000..3a17ac957 --- /dev/null +++ b/service/marketSources/evecentral.py @@ -0,0 +1,87 @@ +# ============================================================================= +# Copyright (C) 2010 Diego Duclos +# +# This file is part of pyfa. +# +# pyfa is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pyfa is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pyfa. If not, see . +# ============================================================================= + +import time +from logbook import Logger +from xml.dom import minidom + +from service.network import Network +from service.price import Price, VALIDITY, TIMEOUT, TimeoutError + + +pyfalog = Logger(__name__) + + +class EveCentral(object): + + name = "eve-central.com" + + def __init__(self, types, system, priceMap): + data = [] + baseurl = "https://eve-central.com/api/marketstat" + data.append(("usesystem", system)) # Use Jita for market + + for typeID in types: # 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 + pass + + +Price.register(EveCentral) diff --git a/service/marketSources/evemarketdata.py b/service/marketSources/evemarketdata.py new file mode 100644 index 000000000..4ca7a3633 --- /dev/null +++ b/service/marketSources/evemarketdata.py @@ -0,0 +1,85 @@ +# ============================================================================= +# Copyright (C) 2010 Diego Duclos +# +# This file is part of pyfa. +# +# pyfa is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pyfa is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pyfa. If not, see . +# ============================================================================= + +import time +from logbook import Logger +from xml.dom import minidom + +from service.network import Network +from service.price import Price, VALIDITY, TIMEOUT, TimeoutError + + +pyfalog = Logger(__name__) + + +class EveMarketData(object): + + name = "eve-marketdata.com" + + def __init__(self, types, system, priceMap): + data = [] + baseurl = "https://eve-marketdata.com/api/item_prices.xml" + data.append(("system_id", system)) # Use Jita for market + data.append(("type_ids", ','.join(str(x) for x in types))) + + # Attempt to send request and process it + try: + network = Network.getInstance() + data = network.request(baseurl, network.PRICES, data) + xml = minidom.parse(data) + print (xml.getElementsByTagName("eve").item(0)) + types = xml.getElementsByTagName("eve").item(0).getElementsByTagName("price") + # 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")) + price = 0 + + try: + price = float(type_.firstChild.data) + except (TypeError, ValueError): + pyfalog.warning("Failed to get price for: {0}", type_) + + # Fill price data + priceobj = priceMap[typeID] + priceobj.price = price + 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 + pass + + +Price.register(EveMarketData) \ No newline at end of file diff --git a/service/price.py b/service/price.py index c6e089f79..b37d6a0d4 100644 --- a/service/price.py +++ b/service/price.py @@ -39,7 +39,6 @@ REREQUEST = 4 * 60 * 60 # Re-request delay for failed fetches, 4 hours TIMEOUT = 15 * 60 # Network timeout delay for connection issues, 15 minutes - class Price(object): instance = None @@ -51,12 +50,18 @@ class Price(object): "Hek": 30002053 } + sources = {} + def __init__(self): # Start price fetcher self.priceWorkerThread = PriceWorkerThread() self.priceWorkerThread.daemon = True self.priceWorkerThread.start() + @classmethod + def register(cls, source): + cls.sources[source.name] = source + @classmethod def getInstance(cls): if cls.instance is None: @@ -95,8 +100,13 @@ class Price(object): sFit = Fit.getInstance() - func = cls.evemarketdata - func(toRequest, cls.systemsList[sFit.serviceFittingOptions["priceSystem"]], priceMap) + 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(): @@ -163,109 +173,6 @@ class Price(object): pyfalog.debug("Clearing Prices") db.clearPrices() - # todo: create classes for these, inherit a base class that allows a simple api of setPrice() and stuff? - @classmethod - def evecentral(self, types, system, priceMap): - data = [] - baseurl = "https://eve-central.com/api/marketstat" - data.append(("usesystem", system)) # Use Jita for market - - for typeID in types: # 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 - pass - - @classmethod - def evemarketdata(self, types, system, priceMap): - data = [] - baseurl = "https://eve-marketdata.com/api/item_prices.xml" - data.append(("system_id", system)) # Use Jita for market - data.append(("type_ids", ','.join(str(x) for x in types))) - - # Attempt to send request and process it - try: - network = Network.getInstance() - data = network.request(baseurl, network.PRICES, data) - xml = minidom.parse(data) - print (xml.getElementsByTagName("eve").item(0)) - types = xml.getElementsByTagName("eve").item(0).getElementsByTagName("price") - # 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")) - price = 0 - - try: - price = float(type_.firstChild.data) - except (TypeError, ValueError): - pyfalog.warning("Failed to get price for: {0}", type_) - - # Fill price data - priceobj = priceMap[typeID] - priceobj.price = price - 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 - pass - class PriceWorkerThread(threading.Thread): def __init__(self): @@ -302,3 +209,5 @@ class PriceWorkerThread(threading.Thread): if itemID not in self.wait: self.wait[itemID] = [] self.wait[itemID].append(callback) + +from service.marketSources import * # noqa: E402,F401