Break out market sources into their own classes and register them onto the price service. Create preference option to select which source user wants. Default to eve central

This commit is contained in:
blitzmann
2017-09-21 20:50:37 -04:00
parent d53ff0f502
commit 7d41260863
6 changed files with 197 additions and 106 deletions

View File

@@ -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()

View File

@@ -74,6 +74,7 @@ class Fit(object):
"exportCharges": True,
"openFitInNew": False,
"priceSystem": "Jita",
"priceSource": "eve-central.com",
"showShipBrowserTooltip": True,
"marketSearchDelay": 250
}

View File

@@ -0,0 +1 @@
__all__ = ['evecentral', 'evemarketdata']

View File

@@ -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 <http://www.gnu.org/licenses/>.
# =============================================================================
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)

View File

@@ -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 <http://www.gnu.org/licenses/>.
# =============================================================================
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)

View File

@@ -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