Skip to content

Commit

Permalink
Feature/evemarketdata (pyfa-org#1297)
Browse files Browse the repository at this point in the history
* Add preliminary support for eve market data

* 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

* fix tox stuff
  • Loading branch information
blitzmann committed Sep 23, 2017
1 parent 4484b68 commit da5aaf2
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 51 deletions.
8 changes: 8 additions & 0 deletions gui/builtinPreferenceViews/pyfaGeneralPreferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ def populatePanel(self, panel):
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)
Expand Down Expand Up @@ -124,6 +126,7 @@ def populatePanel(self, panel):
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"])
Expand All @@ -140,6 +143,7 @@ def populatePanel(self, panel):
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)
Expand Down Expand Up @@ -224,5 +228,9 @@ def onPriceSelection(self, event):
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()
1 change: 1 addition & 0 deletions service/fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def __init__(self):
"exportCharges": True,
"openFitInNew": False,
"priceSystem": "Jita",
"priceSource": "eve-central.com",
"showShipBrowserTooltip": True,
"marketSearchDelay": 250
}
Expand Down
1 change: 1 addition & 0 deletions service/marketSources/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__all__ = ['evecentral', 'evemarketdata']
87 changes: 87 additions & 0 deletions service/marketSources/evecentral.py
Original file line number Diff line number Diff line change
@@ -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)
85 changes: 85 additions & 0 deletions service/marketSources/evemarketdata.py
Original file line number Diff line number Diff line change
@@ -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)
68 changes: 17 additions & 51 deletions service/price.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,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:
Expand Down Expand Up @@ -92,58 +98,15 @@ def fetchPrices(cls, prices):
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 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():
Expand Down Expand Up @@ -246,3 +209,6 @@ def setToWait(self, itemID, callback):
if itemID not in self.wait:
self.wait[itemID] = []
self.wait[itemID].append(callback)


from service.marketSources import evecentral, evemarketdata # noqa: E402

0 comments on commit da5aaf2

Please sign in to comment.