mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-04-14 08:17:13 +03:00
Communicate with EDSM asynchronously
This commit is contained in:
parent
8bc117ff32
commit
965c6c9afb
121
plugins/edsm.py
121
plugins/edsm.py
@ -8,6 +8,8 @@ import sys
|
||||
import time
|
||||
import urllib2
|
||||
from calendar import timegm
|
||||
from Queue import Queue
|
||||
from threading import Thread
|
||||
|
||||
import Tkinter as tk
|
||||
from ttkHyperlinkLabel import HyperlinkLabel
|
||||
@ -17,18 +19,19 @@ from config import appname, applongname, appversion, config
|
||||
import companion
|
||||
import coriolis
|
||||
import edshipyard
|
||||
import plug
|
||||
|
||||
if __debug__:
|
||||
from traceback import print_exc
|
||||
|
||||
EDSM_POLL = 0.1
|
||||
_TIMEOUT = 10
|
||||
_TIMEOUT = 20
|
||||
FAKE = ['CQC', 'Training', 'Destination'] # Fake systems that shouldn't be sent to EDSM
|
||||
|
||||
|
||||
this = sys.modules[__name__] # For holding module globals
|
||||
this.syscache = set() # Cache URLs of systems with known coordinates
|
||||
this.session = requests.Session()
|
||||
this.queue = Queue() # Items to be sent to EDSM by worker thread
|
||||
this.lastship = None # Description of last ship that we sent to EDSM
|
||||
this.lastlookup = False # whether the last lookup succeeded
|
||||
|
||||
@ -60,13 +63,24 @@ def plugin_start():
|
||||
config.delete('edsm_autoopen')
|
||||
config.delete('edsm_historical')
|
||||
|
||||
this.thread = Thread(target = worker, name = 'EDSM worker')
|
||||
this.thread.daemon = True
|
||||
this.thread.start()
|
||||
|
||||
return 'EDSM'
|
||||
|
||||
def plugin_app(parent):
|
||||
this.system_label = tk.Label(parent, text = _('System') + ':') # Main window
|
||||
this.system = HyperlinkLabel(parent, compound=tk.RIGHT, popup_copy = True)
|
||||
this.system.bind_all('<<EDSMStatus>>', update_status)
|
||||
return (this.system_label, this.system)
|
||||
|
||||
def plugin_close():
|
||||
# Signal thread to close and wait for it
|
||||
this.queue.put(None)
|
||||
this.thread.join()
|
||||
this.thread = None
|
||||
|
||||
def plugin_prefs(parent, cmdr, is_beta):
|
||||
|
||||
PADX = 10
|
||||
@ -201,7 +215,7 @@ def journal_entry(cmdr, is_beta, system, station, entry, state):
|
||||
if state['PaintJob'] is not None:
|
||||
props.append(('paintJob', state['PaintJob']))
|
||||
updateship(cmdr, state['ShipID'], state['ShipType'], props)
|
||||
elif entry['event'] in ['ShipyardBuy', 'ShipyardSell']:
|
||||
elif entry['event'] in ['ShipyardBuy', 'ShipyardSell', 'SellShipOnRebuy']:
|
||||
sellship(cmdr, entry.get('SellShipID'))
|
||||
|
||||
# Send cargo to EDSM on startup or change
|
||||
@ -222,8 +236,6 @@ def journal_entry(cmdr, is_beta, system, station, entry, state):
|
||||
if system and entry['event'] in ['Location', 'FSDJump']:
|
||||
this.lastlookup = False
|
||||
writelog(cmdr, timegm(time.strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ')), system, 'StarPos' in entry and tuple(entry['StarPos']), state['ShipID'])
|
||||
this.lastlookup = True
|
||||
this.system.update_idletasks()
|
||||
|
||||
except Exception as e:
|
||||
if __debug__: print_exc()
|
||||
@ -249,10 +261,7 @@ def cmdr_data(data, is_beta):
|
||||
# Send flightlog to EDSM if FSDJump failed to do so
|
||||
if not this.lastlookup:
|
||||
try:
|
||||
this.lastlookup = False
|
||||
this.writelog(data['commander']['name'], int(time.time()), system, None, data['ship']['id'])
|
||||
this.lastlookup = True
|
||||
this.system.update_idletasks()
|
||||
except Exception as e:
|
||||
if __debug__: print_exc()
|
||||
return unicode(e)
|
||||
@ -276,32 +285,51 @@ def cmdr_data(data, is_beta):
|
||||
if __debug__: print_exc()
|
||||
|
||||
|
||||
# Call an EDSM endpoint with args (which should be quoted)
|
||||
def call(cmdr, endpoint, args, check_msgnum=True):
|
||||
try:
|
||||
(username, apikey) = credentials(cmdr)
|
||||
url = 'https://www.edsm.net/%s?commanderName=%s&apiKey=%s&fromSoftware=%s&fromSoftwareVersion=%s' % (
|
||||
# Worker thread
|
||||
def worker():
|
||||
while True:
|
||||
item = this.queue.get()
|
||||
if not item:
|
||||
return # Closing
|
||||
else:
|
||||
(url, callback) = item
|
||||
|
||||
retrying = 0
|
||||
while retrying < 3:
|
||||
try:
|
||||
r = this.session.get(url, timeout=_TIMEOUT)
|
||||
r.raise_for_status()
|
||||
reply = r.json()
|
||||
(msgnum, msg) = reply['msgnum'], reply['msg']
|
||||
break
|
||||
except:
|
||||
retrying += 1
|
||||
else:
|
||||
if callback:
|
||||
callback(None)
|
||||
else:
|
||||
plug.show_error(_("Error: Can't connect to EDSM"))
|
||||
return
|
||||
|
||||
# Message numbers: 1xx = OK, 2xx = fatal error, 3xx = error (but not generated in practice), 4xx = ignorable errors
|
||||
if callback:
|
||||
callback(reply)
|
||||
elif msgnum // 100 != 1:
|
||||
plug.show_error(_('Error: EDSM {MSG}').format(MSG=msg))
|
||||
|
||||
|
||||
# Queue a call an EDSM endpoint with args (which should be quoted)
|
||||
def call(cmdr, endpoint, args, callback=None):
|
||||
(username, apikey) = credentials(cmdr)
|
||||
this.queue.put(
|
||||
('https://www.edsm.net/%s?commanderName=%s&apiKey=%s&fromSoftware=%s&fromSoftwareVersion=%s' % (
|
||||
endpoint,
|
||||
urllib2.quote(username.encode('utf-8')),
|
||||
urllib2.quote(apikey),
|
||||
urllib2.quote(applongname),
|
||||
urllib2.quote(appversion),
|
||||
) + args
|
||||
r = this.session.get(url, timeout=_TIMEOUT)
|
||||
r.raise_for_status()
|
||||
reply = r.json()
|
||||
if not check_msgnum:
|
||||
return reply
|
||||
(msgnum, msg) = reply['msgnum'], reply['msg']
|
||||
except:
|
||||
if __debug__: print_exc()
|
||||
raise Exception(_("Error: Can't connect to EDSM"))
|
||||
|
||||
# Message numbers: 1xx = OK, 2xx = fatal error, 3xx = error (but not generated in practice), 4xx = ignorable errors
|
||||
if msgnum // 100 not in (1,4):
|
||||
raise Exception(_('Error: EDSM {MSG}').format(MSG=msg))
|
||||
else:
|
||||
return reply
|
||||
) + args,
|
||||
callback))
|
||||
|
||||
|
||||
# Send flight log and also do lookup
|
||||
@ -318,16 +346,31 @@ def writelog(cmdr, timestamp, system_name, coordinates, shipid = None):
|
||||
args += '&x=%.3f&y=%.3f&z=%.3f' % coordinates
|
||||
if shipid is not None:
|
||||
args += '&shipId=%d' % shipid
|
||||
try:
|
||||
reply = call(cmdr, 'api-logs-v1/set-log', args)
|
||||
if reply.get('systemCreated'):
|
||||
this.system['image'] = this._IMG_NEW
|
||||
else:
|
||||
this.system['image'] = this._IMG_KNOWN
|
||||
this.syscache.add(system_name)
|
||||
except:
|
||||
call(cmdr, 'api-logs-v1/set-log', args, writelog_callback)
|
||||
|
||||
def writelog_callback(reply):
|
||||
this.lastlookup = reply
|
||||
this.system.event_generate('<<EDSMStatus>>', when="tail") # calls update_status in main thread
|
||||
|
||||
def update_status(event=None):
|
||||
reply = this.lastlookup
|
||||
if not reply or not reply.get('msgnum'):
|
||||
this.system['image'] = this._IMG_ERROR
|
||||
raise
|
||||
plug.show_error(_("Error: Can't connect to EDSM"))
|
||||
elif reply['msgnum'] // 100 not in (1,4):
|
||||
this.system['image'] = this._IMG_ERROR
|
||||
plug.show_error(_('Error: EDSM {MSG}').format(MSG=reply['msg']))
|
||||
elif reply.get('systemCreated'):
|
||||
this.system['image'] = this._IMG_NEW
|
||||
else:
|
||||
this.system['image'] = this._IMG_KNOWN
|
||||
|
||||
|
||||
# When we don't care about return msgnum from EDSM
|
||||
def null_callback(reply):
|
||||
if not reply or not reply.get('msgnum'):
|
||||
plug.show_error(_("Error: Can't connect to EDSM"))
|
||||
|
||||
|
||||
def setranks(cmdr, ranks):
|
||||
args = ''
|
||||
@ -365,4 +408,4 @@ def updateship(cmdr, shipid, shiptype, props=[]):
|
||||
|
||||
def sellship(cmdr, shipid):
|
||||
if shipid is not None:
|
||||
call(cmdr, 'api-commander-v1/sell-ship', '&shipId=%d' % shipid)
|
||||
call(cmdr, 'api-commander-v1/sell-ship', '&shipId=%d' % shipid, null_callback)
|
||||
|
Loading…
x
Reference in New Issue
Block a user