def getandsend(self, event=None, retrying=False):

        play_sound = event and event.type == '35' and not config.getint(
            'hotkey_mute')

        if not retrying:
            if time(
            ) < self.holdofftime:  # Was invoked by key while in cooldown
                self.status['text'] = ''
                if play_sound and (self.holdofftime -
                                   time()) < companion.holdoff * 0.75:
                    hotkeymgr.play_bad(
                    )  # Don't play sound in first few seconds to prevent repeats
                return
            elif play_sound:
                hotkeymgr.play_good()
            self.cmdr['text'] = self.system['text'] = self.station['text'] = ''
            self.system['image'] = ''
            self.status['text'] = _('Fetching data...')
            self.button['state'] = tk.DISABLED
            self.edit_menu.entryconfigure(_('Copy'), state=tk.DISABLED)
            self.w.update_idletasks()

        try:
            querytime = int(time())
            data = self.session.query()
            config.set('querytime', querytime)

            # Validation
            if not data.get('commander') or not data['commander'].get(
                    'name', '').strip():
                self.status['text'] = _("Who are you?!")  # Shouldn't happen
            elif not data.get('lastSystem') or not data['lastSystem'].get(
                    'name', '').strip() or not data.get(
                        'lastStarport') or not data['lastStarport'].get(
                            'name', '').strip():
                self.status['text'] = _("Where are you?!")  # Shouldn't happen
            elif not data.get('ship') or not data['ship'].get(
                    'modules') or not data['ship'].get('name', '').strip():
                self.status['text'] = _(
                    "What are you flying?!")  # Shouldn't happen

            else:
                if __debug__:  # Recording
                    with open(
                            '%s%s.%s.json' %
                        (data['lastSystem']['name'],
                         data['commander'].get('docked')
                         and '.' + data['lastStarport']['name'] or '',
                         strftime('%Y-%m-%dT%H.%M.%S', localtime())),
                            'wt') as h:
                        h.write(
                            json.dumps(data,
                                       ensure_ascii=False,
                                       indent=2,
                                       sort_keys=True).encode('utf-8'))

                self.cmdr['text'] = data.get('commander') and data.get(
                    'commander').get('name') or ''
                self.system['text'] = data.get('lastSystem') and data.get(
                    'lastSystem').get('name') or ''
                self.station['text'] = data.get('commander') and data.get(
                    'commander').get('docked') and data.get(
                        'lastStarport') and data.get('lastStarport').get(
                            'name') or (EDDB.system(self.system['text'])
                                        and self.STATION_UNDOCKED or '')
                self.status['text'] = ''
                self.edit_menu.entryconfigure(_('Copy'), state=tk.NORMAL)
                self.view_menu.entryconfigure(_('Status'), state=tk.NORMAL)

                # stuff we can do when not docked
                if config.getint('output') & config.OUT_SHIP_EDS:
                    loadout.export(data)
                if config.getint('output') & config.OUT_SHIP_CORIOLIS:
                    coriolis.export(data)
                if config.getint('output') & config.OUT_LOG_FILE:
                    flightlog.export(data)
                if config.getint('output') & config.OUT_LOG_EDSM:
                    # Catch any EDSM errors here so that they don't prevent station update
                    try:
                        self.status['text'] = _('Sending data to EDSM...')
                        self.w.update_idletasks()
                        edsm.export(data, lambda: self.edsm.lookup(
                            self.system['text'],
                            EDDB.system(self.system['text']))
                                    )  # Do EDSM lookup during EDSM export
                        self.status['text'] = ''
                    except Exception as e:
                        if __debug__: print_exc()
                        self.status['text'] = unicode(e)
                else:
                    self.edsm.link(self.system['text'])
                self.edsmpoll()

                if not (config.getint('output') &
                        (config.OUT_CSV | config.OUT_TD | config.OUT_BPC
                         | config.OUT_EDDN)):
                    # no station data requested - we're done
                    pass

                elif not data['commander'].get('docked'):
                    # signal as error because the user might actually be docked but the server hosting the Companion API hasn't caught up
                    if not self.status['text']:
                        self.status['text'] = _(
                            "You're not docked at a station!")

                else:
                    # Finally - the data looks sane and we're docked at a station
                    (station_id, has_market, has_outfitting,
                     has_shipyard) = EDDB.station(self.system['text'],
                                                  self.station['text'])

                    # No EDDN output at known station?
                    if (config.getint('output')
                            & config.OUT_EDDN) and station_id and not (
                                has_market or has_outfitting or has_shipyard):
                        if not self.status['text']:
                            self.status['text'] = _(
                                "Station doesn't have anything!")

                    # No EDDN output at unknown station?
                    elif (
                            config.getint('output') & config.OUT_EDDN
                    ) and not station_id and not (
                            data['lastStarport'].get('commodities')
                            or data['lastStarport'].get('modules')
                    ):  # Ignore usually spurious shipyard at unknown stations
                        if not self.status['text']:
                            self.status['text'] = _(
                                "Station doesn't have anything!")

                    # No market output at known station?
                    elif not (config.getint('output') & config.OUT_EDDN
                              ) and station_id and not has_market:
                        if not self.status['text']:
                            self.status['text'] = _(
                                "Station doesn't have a market!")

                    # No market output at unknown station?
                    elif not (config.getint('output') &
                              config.OUT_EDDN) and not station_id and not data[
                                  'lastStarport'].get('commodities'):
                        if not self.status['text']:
                            self.status['text'] = _(
                                "Station doesn't have a market!")

                    else:
                        if data['lastStarport'].get('commodities'):
                            # Fixup anomalies in the commodity data
                            self.session.fixup(
                                data['lastStarport']['commodities'])

                            if config.getint('output') & config.OUT_CSV:
                                bpc.export(data, True)
                            if config.getint('output') & config.OUT_TD:
                                td.export(data)
                            if config.getint('output') & config.OUT_BPC:
                                bpc.export(data, False)

                        elif has_market and (
                                config.getint('output') &
                            (config.OUT_CSV | config.OUT_TD | config.OUT_BPC
                             | config.OUT_EDDN)):
                            # Overwrite any previous error message
                            self.status['text'] = _(
                                "Error: Can't get market data!")

                        if config.getint('output') & config.OUT_EDDN:
                            old_status = self.status['text']
                            if not old_status:
                                self.status['text'] = _(
                                    'Sending data to EDDN...')
                            self.w.update_idletasks()
                            eddn.export_commodities(data)
                            if has_outfitting or not station_id:
                                # Only send if eddb says that the station provides outfitting, or unknown station
                                eddn.export_outfitting(data)
                            elif __debug__ and data['lastStarport'].get(
                                    'modules'):
                                print 'Spurious outfitting!'
                            if has_shipyard:
                                # Only send if eddb says that the station has a shipyard -
                                # https://github.com/Marginal/EDMarketConnector/issues/16
                                if data['lastStarport'].get('ships'):
                                    eddn.export_shipyard(data)
                                else:
                                    # API is flakey about shipyard info - silently retry if missing (<1s is usually sufficient - 5s for margin).
                                    self.w.after(int(SERVER_RETRY * 1000),
                                                 self.retry_for_shipyard)
                            elif __debug__ and data['lastStarport'].get(
                                    'ships'):
                                print 'Spurious shipyard!'
                            if not old_status:
                                self.status['text'] = ''

        except companion.VerificationRequired:
            return prefs.AuthenticationDialog(self.w, self.verify)

        # Companion API problem
        except companion.ServerError as e:
            if retrying:
                self.status['text'] = unicode(e)
            else:
                # Retry once if Companion server is unresponsive
                self.w.after(int(SERVER_RETRY * 1000),
                             lambda: self.getandsend(event, True))
                return  # early exit to avoid starting cooldown count

        except requests.exceptions.ConnectionError as e:
            if __debug__: print_exc()
            self.status['text'] = _("Error: Can't connect to EDDN")

        except requests.exceptions.Timeout as e:
            if __debug__: print_exc()
            self.status['text'] = _("Error: Connection to EDDN timed out")

        except Exception as e:
            if __debug__: print_exc()
            self.status['text'] = unicode(e)

        if not self.status['text']:  # no errors
            self.status['text'] = strftime(
                _('Last updated at {HH}:{MM}:{SS}').format(
                    HH='%H', MM='%M', SS='%S').encode('utf-8'),
                localtime(querytime)).decode('utf-8')
        elif play_sound:
            hotkeymgr.play_bad()

        self.holdofftime = querytime + companion.holdoff
        self.cooldown()
Example #2
0
    if not data.get('commander') or not data['commander'].get('name','').strip():
        sys.stderr.write('Who are you?!\n')
        sys.exit(EXIT_SERVER)
    elif not data.get('lastSystem') or not data['lastSystem'].get('name','').strip() or not data.get('lastStarport') or not data['lastStarport'].get('name','').strip():
        sys.stderr.write('Where are you?!\n')		# Shouldn't happen
        sys.exit(EXIT_SERVER)
    elif not data.get('ship') or not data['ship'].get('modules') or not data['ship'].get('name','').strip():
        sys.stderr.write('What are you flying?!\n')	# Shouldn't happen
        sys.exit(EXIT_SERVER)

    # stuff we can do when not docked
    if args.d:
        with open(args.d, 'wt') as h:
            h.write(json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True, separators=(',', ': ')).encode('utf-8'))
    if args.a:
        loadout.export(data, args.a)
    if args.c:
        coriolis.export(data, args.c)
    if args.e:
        edshipyard.export(data, args.e)
    if args.l:
        stats.export_ships(data, args.l)
    if args.t:
        stats.export_status(data, args.t)

    if not data['commander'].get('docked'):
        print data['lastSystem']['name']
        if (args.m or args.o or args.s):
            sys.stderr.write("You're not docked at a station!\n")
            sys.exit(EXIT_NOT_DOCKED)
        else:
    def getandsend(self, event=None, retrying=False):

        auto_update = not event
        play_sound = (auto_update or int(event.type) == self.EVENT_VIRTUAL
                      ) and not config.getint('hotkey_mute')

        if (monitor.cmdr and not monitor.mode) or monitor.is_beta:
            return  # In CQC - do nothing

        if not retrying:
            if time(
            ) < self.holdofftime:  # Was invoked by key while in cooldown
                self.status['text'] = ''
                if play_sound and (self.holdofftime -
                                   time()) < companion.holdoff * 0.75:
                    hotkeymgr.play_bad(
                    )  # Don't play sound in first few seconds to prevent repeats
                return
            elif play_sound:
                hotkeymgr.play_good()
            self.status['text'] = _('Fetching data...')
            self.button['state'] = self.theme_button['state'] = tk.DISABLED
            self.edit_menu.entryconfigure(0, state=tk.DISABLED)  # Copy
            self.w.update_idletasks()

        try:
            querytime = int(time())
            data = self.session.query()
            config.set('querytime', querytime)

            # Validation
            if not data.get('commander') or not data['commander'].get(
                    'name', '').strip():
                self.status['text'] = _("Who are you?!")  # Shouldn't happen
            elif not data.get('lastSystem') or not data['lastSystem'].get(
                    'name', '').strip() or not data.get(
                        'lastStarport') or not data['lastStarport'].get(
                            'name', '').strip():
                self.status['text'] = _("Where are you?!")  # Shouldn't happen
            elif not data.get('ship') or not data['ship'].get(
                    'modules') or not data['ship'].get('name', '').strip():
                self.status['text'] = _(
                    "What are you flying?!")  # Shouldn't happen
            elif monitor.cmdr and data['commander']['name'] != monitor.cmdr:
                raise companion.CredentialsError(
                )  # Companion API credentials don't match Journal
            elif (auto_update and not data['commander'].get('docked')) or (
                    monitor.system
                    and data['lastSystem']['name'] != monitor.system
            ) or (monitor.shipid and data['ship']['id'] != monitor.shipid) or (
                    monitor.shiptype
                    and data['ship']['name'].lower() != monitor.shiptype):
                raise companion.ServerLagging()

            else:

                if __debug__:  # Recording
                    if not isdir('dump'): mkdir('dump')
                    with open(
                            'dump/%s%s.%s.json' %
                        (data['lastSystem']['name'],
                         data['commander'].get('docked')
                         and '.' + data['lastStarport']['name'] or '',
                         strftime('%Y-%m-%dT%H.%M.%S', localtime())),
                            'wt') as h:
                        h.write(
                            json.dumps(data,
                                       ensure_ascii=False,
                                       indent=2,
                                       sort_keys=True,
                                       separators=(',', ': ')).encode('utf-8'))

                self.cmdr['text'] = data['commander']['name']
                self.ship['text'] = companion.ship_map.get(
                    data['ship']['name'].lower(), data['ship']['name'])
                if not monitor.system:
                    self.system['text'] = data['lastSystem']['name']
                    self.system['image'] = ''
                self.station['text'] = data['commander'].get(
                    'docked') and data.get('lastStarport') and data[
                        'lastStarport'].get('name') or (EDDB.system(
                            self.system['text']) and self.STATION_UNDOCKED
                                                        or '')
                self.status['text'] = ''
                self.edit_menu.entryconfigure(0, state=tk.NORMAL)  # Copy

                # stuff we can do when not docked
                plug.notify_newdata(data)
                if config.getint('output') & config.OUT_SHIP_EDS:
                    loadout.export(data)
                if config.getint('output') & config.OUT_SHIP_CORIOLIS:
                    coriolis.export(data)

                if not (config.getint('output') &
                        (config.OUT_MKT_CSV | config.OUT_MKT_TD
                         | config.OUT_MKT_BPC | config.OUT_MKT_EDDN)):
                    # no station data requested - we're done
                    pass

                elif not data['commander'].get('docked'):
                    if not event and not retrying:
                        # Silently retry if we got here by 'Automatically update on docking' and the server hasn't caught up
                        self.w.after(int(SERVER_RETRY * 1000),
                                     lambda: self.getandsend(event, True))
                        return  # early exit to avoid starting cooldown count
                    else:
                        # Signal as error because the user might actually be docked but the server hosting the Companion API hasn't caught up
                        if not self.status['text']:
                            self.status['text'] = _(
                                "You're not docked at a station!")

                else:
                    # Finally - the data looks sane and we're docked at a station
                    (station_id, has_market, has_outfitting,
                     has_shipyard) = EDDB.station(self.system['text'],
                                                  self.station['text'])

                    # No EDDN output?
                    if (config.getint('output') & config.OUT_MKT_EDDN
                        ) and not (data['lastStarport'].get('commodities')
                                   or data['lastStarport'].get('modules')
                                   ):  # Ignore possibly missing shipyard info
                        if not self.status['text']:
                            self.status['text'] = _(
                                "Station doesn't have anything!")

                    # No market output?
                    elif not (
                            config.getint('output') & config.OUT_MKT_EDDN
                    ) and not data['lastStarport'].get('commodities'):
                        if not self.status['text']:
                            self.status['text'] = _(
                                "Station doesn't have a market!")

                    else:
                        if data['lastStarport'].get(
                                'commodities') and config.getint('output') & (
                                    config.OUT_MKT_CSV | config.OUT_MKT_TD
                                    | config.OUT_MKT_BPC):
                            # Fixup anomalies in the commodity data
                            fixed = companion.fixup(data)

                            if config.getint('output') & config.OUT_MKT_CSV:
                                commodity.export(fixed, COMMODITY_CSV)
                            if config.getint('output') & config.OUT_MKT_TD:
                                td.export(fixed)
                            if config.getint('output') & config.OUT_MKT_BPC:
                                commodity.export(fixed, COMMODITY_BPC)

                        if config.getint('output') & config.OUT_MKT_EDDN:
                            old_status = self.status['text']
                            if not old_status:
                                self.status['text'] = _(
                                    'Sending data to EDDN...')
                            self.w.update_idletasks()
                            eddn.export_commodities(data)
                            eddn.export_outfitting(data)
                            if has_shipyard and not data['lastStarport'].get(
                                    'ships'):
                                # API is flakey about shipyard info - silently retry if missing (<1s is usually sufficient - 5s for margin).
                                self.w.after(int(SERVER_RETRY * 1000),
                                             self.retry_for_shipyard)
                            else:
                                eddn.export_shipyard(data)
                            if not old_status:
                                self.status['text'] = ''

                    # Update credits and ship info and send to EDSM
                    if config.getint(
                            'output'
                    ) & config.OUT_SYS_EDSM and not monitor.is_beta:
                        try:
                            if data['commander'].get('credits') is not None:
                                monitor.credits = (
                                    data['commander']['credits'],
                                    data['commander'].get('debt', 0))
                                self.edsm.setcredits(monitor.credits)
                            ship = companion.ship(data)
                            if ship == self.edsm.lastship:
                                props = []
                            else:
                                props = [
                                    ('cargoCapacity',
                                     ship['cargo']['capacity']),
                                    ('fuelMainCapacity',
                                     ship['fuel']['main']['capacity']),
                                    ('linkToCoriolis', coriolis.url(data)),
                                    ('linkToEDShipyard', edshipyard.url(data)),
                                ]
                            if monitor.shippaint is None:
                                # Companion API server can lag, so prefer Journal. But paintjob only reported in Journal on change.
                                monitor.shipid = data['ship']['id']
                                monitor.shiptype = data['ship']['name'].lower()
                                monitor.shippaint = data['ship']['modules'][
                                    'PaintJob'] and data['ship']['modules'][
                                        'PaintJob']['module']['name'].lower(
                                        ) or ''
                                props.append(('paintJob', monitor.shippaint))
                            if props:
                                self.edsm.updateship(monitor.shipid,
                                                     monitor.shiptype, props)
                                self.edsm.lastship = ship
                        except Exception as e:
                            # Not particularly important so silent on failure
                            if __debug__: print_exc()

        except companion.VerificationRequired:
            return prefs.AuthenticationDialog(
                self.w, partial(self.verify, self.getandsend))

        # Companion API problem
        except (companion.ServerError, companion.ServerLagging) as e:
            if retrying:
                self.status['text'] = unicode(e)
            else:
                # Retry once if Companion server is unresponsive
                self.w.after(int(SERVER_RETRY * 1000),
                             lambda: self.getandsend(event, True))
                return  # early exit to avoid starting cooldown count

        except requests.RequestException as e:
            if __debug__: print_exc()
            self.status['text'] = _("Error: Can't connect to EDDN")

        except Exception as e:
            if __debug__: print_exc()
            self.status['text'] = unicode(e)

        if not self.status['text']:  # no errors
            self.status['text'] = strftime(
                _('Last updated at {HH}:{MM}:{SS}').format(
                    HH='%H', MM='%M', SS='%S').encode('utf-8'),
                localtime(querytime)).decode('utf-8')
        elif play_sound:
            hotkeymgr.play_bad()

        self.holdofftime = querytime + companion.holdoff
        self.cooldown()
    def getandsend(self, event=None, retrying=False):

        play_sound = event and event.type=='35' and not config.getint('hotkey_mute')

        if not retrying:
            if time() < self.holdofftime:	# Was invoked by key while in cooldown
                self.status['text'] = ''
                if play_sound and (self.holdofftime-time()) < companion.holdoff*0.75:
                    hotkeymgr.play_bad()	# Don't play sound in first few seconds to prevent repeats
                return
            elif play_sound:
                hotkeymgr.play_good()
            self.cmdr['text'] = self.system['text'] = self.station['text'] = ''
            self.system['image'] = ''
            self.status['text'] = _('Fetching data...')
            self.button['state'] = tk.DISABLED
            self.edit_menu.entryconfigure(_('Copy'), state=tk.DISABLED)
            self.w.update_idletasks()

        try:
            querytime = int(time())
            data = self.session.query()
            config.set('querytime', querytime)

            # Validation
            if not data.get('commander') or not data['commander'].get('name','').strip():
                self.status['text'] = _("Who are you?!")		# Shouldn't happen
            elif not data.get('lastSystem') or not data['lastSystem'].get('name','').strip() or not data.get('lastStarport') or not data['lastStarport'].get('name','').strip():
                self.status['text'] = _("Where are you?!")		# Shouldn't happen
            elif not data.get('ship') or not data['ship'].get('modules') or not data['ship'].get('name','').strip():
                self.status['text'] = _("What are you flying?!")	# Shouldn't happen

            else:
                if __debug__:	# Recording
                    with open('%s%s.%s.json' % (data['lastSystem']['name'], data['commander'].get('docked') and '.'+data['lastStarport']['name'] or '', strftime('%Y-%m-%dT%H.%M.%S', localtime())), 'wt') as h:
                        h.write(json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True).encode('utf-8'))

                self.cmdr['text'] = data.get('commander') and data.get('commander').get('name') or ''
                self.system['text'] = data.get('lastSystem') and data.get('lastSystem').get('name') or ''
                self.station['text'] = data.get('commander') and data.get('commander').get('docked') and data.get('lastStarport') and data.get('lastStarport').get('name') or (EDDB.system(self.system['text']) and self.STATION_UNDOCKED or '')
                self.status['text'] = ''
                self.edit_menu.entryconfigure(_('Copy'), state=tk.NORMAL)
                self.view_menu.entryconfigure(_('Status'), state=tk.NORMAL)

                # stuff we can do when not docked
                if config.getint('output') & config.OUT_SHIP_EDS:
                    loadout.export(data)
                if config.getint('output') & config.OUT_SHIP_CORIOLIS:
                    coriolis.export(data)
                if config.getint('output') & config.OUT_LOG_FILE:
                    flightlog.export(data)
                if config.getint('output') & config.OUT_LOG_EDSM:
                    # Catch any EDSM errors here so that they don't prevent station update
                    try:
                        self.status['text'] = _('Sending data to EDSM...')
                        self.w.update_idletasks()
                        edsm.export(data, lambda:self.edsm.lookup(self.system['text'], EDDB.system(self.system['text'])))	# Do EDSM lookup during EDSM export
                        self.status['text'] = ''
                    except Exception as e:
                        if __debug__: print_exc()
                        self.status['text'] = unicode(e)
                else:
                    self.edsm.link(self.system['text'])
                self.edsmpoll()

                if not (config.getint('output') & (config.OUT_CSV|config.OUT_TD|config.OUT_BPC|config.OUT_EDDN)):
                    # no station data requested - we're done
                    pass

                elif not data['commander'].get('docked'):
                    # signal as error because the user might actually be docked but the server hosting the Companion API hasn't caught up
                    if not self.status['text']:
                        self.status['text'] = _("You're not docked at a station!")

                else:
                    # Finally - the data looks sane and we're docked at a station
                    (station_id, has_market, has_outfitting, has_shipyard) = EDDB.station(self.system['text'], self.station['text'])


                    # No EDDN output at known station?
                    if (config.getint('output') & config.OUT_EDDN) and station_id and not (has_market or has_outfitting or has_shipyard):
                        if not self.status['text']:
                            self.status['text'] = _("Station doesn't have anything!")

                    # No EDDN output at unknown station?
                    elif (config.getint('output') & config.OUT_EDDN) and not station_id and not (data['lastStarport'].get('commodities') or data['lastStarport'].get('modules')):	# Ignore usually spurious shipyard at unknown stations
                        if not self.status['text']:
                            self.status['text'] = _("Station doesn't have anything!")

                    # No market output at known station?
                    elif not (config.getint('output') & config.OUT_EDDN) and station_id and not has_market:
                        if not self.status['text']:
                            self.status['text'] = _("Station doesn't have a market!")

                    # No market output at unknown station?
                    elif not (config.getint('output') & config.OUT_EDDN) and not station_id and not data['lastStarport'].get('commodities'):
                        if not self.status['text']:
                            self.status['text'] = _("Station doesn't have a market!")

                    else:
                        if data['lastStarport'].get('commodities'):
                            # Fixup anomalies in the commodity data
                            self.session.fixup(data['lastStarport']['commodities'])

                            if config.getint('output') & config.OUT_CSV:
                                bpc.export(data, True)
                            if config.getint('output') & config.OUT_TD:
                                td.export(data)
                            if config.getint('output') & config.OUT_BPC:
                                bpc.export(data, False)

                        elif has_market and (config.getint('output') & (config.OUT_CSV|config.OUT_TD|config.OUT_BPC|config.OUT_EDDN)):
                            # Overwrite any previous error message
                            self.status['text'] = _("Error: Can't get market data!")

                        if config.getint('output') & config.OUT_EDDN:
                            old_status = self.status['text']
                            if not old_status:
                                self.status['text'] = _('Sending data to EDDN...')
                            self.w.update_idletasks()
                            eddn.export_commodities(data)
                            if has_outfitting or not station_id:
                                # Only send if eddb says that the station provides outfitting, or unknown station
                                eddn.export_outfitting(data)
                            elif __debug__ and data['lastStarport'].get('modules'):
                                print 'Spurious outfitting!'
                            if has_shipyard:
                                # Only send if eddb says that the station has a shipyard -
                                # https://github.com/Marginal/EDMarketConnector/issues/16
                                if data['lastStarport'].get('ships'):
                                    eddn.export_shipyard(data)
                                else:
                                    # API is flakey about shipyard info - silently retry if missing (<1s is usually sufficient - 5s for margin).
                                    self.w.after(int(SERVER_RETRY * 1000), self.retry_for_shipyard)
                            elif __debug__ and data['lastStarport'].get('ships'):
                                print 'Spurious shipyard!'
                            if not old_status:
                                self.status['text'] = ''

        except companion.VerificationRequired:
            return prefs.AuthenticationDialog(self.w, self.verify)

        # Companion API problem
        except companion.ServerError as e:
            if retrying:
                self.status['text'] = unicode(e)
            else:
                # Retry once if Companion server is unresponsive
                self.w.after(int(SERVER_RETRY * 1000), lambda:self.getandsend(event, True))
                return	# early exit to avoid starting cooldown count

        except requests.exceptions.ConnectionError as e:
            if __debug__: print_exc()
            self.status['text'] = _("Error: Can't connect to EDDN")

        except requests.exceptions.Timeout as e:
            if __debug__: print_exc()
            self.status['text'] = _("Error: Connection to EDDN timed out")

        except Exception as e:
            if __debug__: print_exc()
            self.status['text'] = unicode(e)

        if not self.status['text']:	# no errors
            self.status['text'] = strftime(_('Last updated at {HH}:{MM}:{SS}').format(HH='%H', MM='%M', SS='%S').encode('utf-8'), localtime(querytime)).decode('utf-8')
        elif play_sound:
            hotkeymgr.play_bad()

        self.holdofftime = querytime + companion.holdoff
        self.cooldown()
    def getandsend(self, event=None, retrying=False):

        if not retrying:
            if time() < self.holdofftime: return	# Was invoked by Return key while in cooldown
            self.cmdr['text'] = self.system['text'] = self.station['text'] = ''
            self.status['text'] = 'Fetching station data...'
            self.button['state'] = tk.DISABLED
            self.w.update_idletasks()

        try:
            querytime = int(time())

            data = self.session.query()

            self.cmdr['text'] = data.get('commander') and data.get('commander').get('name') or ''
            self.system['text'] = data.get('lastSystem') and data.get('lastSystem').get('name') or ''
            self.station['text'] = data.get('commander') and data.get('commander').get('docked') and data.get('lastStarport') and data.get('lastStarport').get('name') or '-'

            config.set('querytime', querytime)
            self.holdofftime = querytime + companion.holdoff

            # Validation
            if not data.get('commander') or not data['commander'].get('name','').strip():
                self.status['text'] = "Who are you?!"		# Shouldn't happen
            elif not data.get('lastSystem') or not data['lastSystem'].get('name','').strip() or not data.get('lastStarport') or not data['lastStarport'].get('name','').strip():
                self.status['text'] = "Where are you?!"		# Shouldn't happen
            elif not data.get('ship') or not data['ship'].get('modules') or not data['ship'].get('name','').strip():
                self.status['text'] = "What are you flying?!"	# Shouldn't happen
            elif (config.getint('output') & config.OUT_EDDN) and not data['lastStarport'].get('ships') and not retrying:
                # API is flakey about shipyard info - retry if missing (<1s is usually sufficient - 2.5s for margin).
                self.w.after(2500, lambda:self.getandsend(retrying=True))
                return
            else:
                if __debug__ and retrying: print data['lastStarport'].get('ships') and 'Retry for shipyard - Success' or 'Retry for shipyard - Fail'

                # stuff we can do when not docked
                if __debug__:	# Recording
                    with open('%s%s.%s.json' % (data['lastSystem']['name'], data['commander'].get('docked') and '.'+data['lastStarport']['name'] or '', strftime('%Y-%m-%dT%H.%M.%S', localtime())), 'wt') as h:
                        h.write(json.dumps(data, indent=2, sort_keys=True))
                if config.getint('output') & config.OUT_LOG:
                    flightlog.export(data)
                if config.getint('output') & config.OUT_SHIP:
                    loadout.export(data)

                if not (config.getint('output') & (config.OUT_CSV|config.OUT_TD|config.OUT_BPC|config.OUT_EDDN)):
                    # no further output requested
                    self.status['text'] = strftime('Last updated at %H:%M:%S', localtime(querytime))

                elif not data['commander'].get('docked'):
                    self.status['text'] = "You're not docked at a station!"
                else:
                    if data['lastStarport'].get('commodities'):
                        # Fixup anomalies in the commodity data
                        self.session.fixup(data['lastStarport']['commodities'])

                        if config.getint('output') & config.OUT_CSV:
                            bpc.export(data, True)
                        if config.getint('output') & config.OUT_TD:
                            td.export(data)
                        if config.getint('output') & config.OUT_BPC:
                            bpc.export(data, False)

                    if config.getint('output') & config.OUT_EDDN:
                        if data['lastStarport'].get('commodities') or data['lastStarport'].get('modules') or data['lastStarport'].get('ships'):
                            self.status['text'] = 'Sending data to EDDN...'
                            self.w.update_idletasks()
                            eddn.export(data)
                            self.status['text'] = strftime('Last updated at %H:%M:%S', localtime(querytime))
                        else:
                            self.status['text'] = "Station doesn't have anything!"
                    elif not data['lastStarport'].get('commodities'):
                        self.status['text'] = "Station doesn't have a market!"
                    else:
                        self.status['text'] = strftime('Last updated at %H:%M:%S', localtime(querytime))

        except companion.VerificationRequired:
            return prefs.AuthenticationDialog(self.w, self.verify)

        # Companion API problem
        except companion.ServerError as e:
            self.status['text'] = str(e)

        except requests.exceptions.ConnectionError as e:
            if __debug__: print_exc()
            self.status['text'] = "Error: Can't connect to EDDN"

        except requests.exceptions.Timeout as e:
            if __debug__: print_exc()
            self.status['text'] = "Error: Connection to EDDN timed out"

        except Exception as e:
            if __debug__: print_exc()
            self.status['text'] = str(e)

        self.cooldown()
    def getandsend(self, event=None):
        if time() < self.holdofftime: return	# Was invoked by Return key while in cooldown

        self.cmdr['text'] = self.system['text'] = self.station['text'] = ''
        self.status['text'] = 'Fetching market data...'
        self.button['state'] = tk.DISABLED
        self.w.update_idletasks()

        try:
            querytime = int(time())

            data = self.session.query()

            self.cmdr['text'] = data.get('commander') and data.get('commander').get('name') or ''
            self.system['text'] = data.get('lastSystem') and data.get('lastSystem').get('name') or ''
            self.station['text'] = data.get('commander') and data.get('commander').get('docked') and data.get('lastStarport') and data.get('lastStarport').get('name') or '-'

            config.set('querytime', querytime)
            self.holdofftime = querytime + companion.holdoff

            # Validation
            if not data.get('commander') or not data['commander'].get('name','').strip():
                self.status['text'] = "Who are you?!"		# Shouldn't happen
            elif not data.get('lastSystem') or not data['lastSystem'].get('name','').strip() or not data.get('lastStarport') or not data['lastStarport'].get('name','').strip():
                self.status['text'] = "Where are you?!"		# Shouldn't happen
            elif not data.get('ship') or not data['ship'].get('modules') or not data['ship'].get('name','').strip():
                self.status['text'] = "What are you flying?!"	# Shouldn't happen
            else:
                # stuff we can do when not docked
                if config.getint('output') & config.OUT_LOG:
                    flightlog.export(data)
                if config.getint('output') & config.OUT_SHIP:
                    loadout.export(data)

                if not (config.getint('output') & (config.OUT_CSV|config.OUT_TD|config.OUT_BPC|config.OUT_EDDN)):
                    # no further output requested
                    self.status['text'] = strftime('Last updated at %H:%M:%S', localtime(querytime))

                elif not data['commander'].get('docked'):
                    self.status['text'] = "You're not docked at a station!"
                elif not data['lastStarport'].get('commodities'):
                    self.status['text'] = "Station doesn't have a market!"
                else:
                    if config.getint('output') & config.OUT_CSV:
                        bpc.export(data, True)
                    if config.getint('output') & config.OUT_TD:
                        td.export(data)
                    if config.getint('output') & config.OUT_BPC:
                        bpc.export(data, False)
                    if config.getint('output') & config.OUT_EDDN:
                        self.status['text'] = 'Sending data to EDDN...'
                        self.w.update_idletasks()
                        eddn.export(data)
                    self.status['text'] = strftime('Last updated at %H:%M:%S', localtime(querytime))

        except companion.VerificationRequired:
            return prefs.AuthenticationDialog(self.w, self.verify)

        except companion.ServerError as e:
            self.status['text'] = str(e)

        except Exception as e:
            if __debug__: print_exc()
            self.status['text'] = str(e)

        self.cooldown()
Example #7
0
    def send(self, event=None):
        data = self.data
        try:
            if True:  # validation now done in get part
                # stuff we can do when not docked
                if config.getint('output') & config.OUT_SHIP_EDS:
                    loadout.export(data)
                if config.getint('output') & config.OUT_SHIP_CORIOLIS:
                    coriolis.export(data)
                if config.getint('output') & config.OUT_LOG_FILE:
                    flightlog.export(data)
                if config.getint('output') & config.OUT_LOG_EDSM:
                    # Catch any EDSM errors here so that they don't prevent station update
                    try:
                        self.status['text'] = _('Sending data to EDSM...')
                        self.w.update_idletasks()
                        edsm.export(data, lambda: self.edsm.lookup(
                            self.system['text'],
                            EDDB.system(self.system['text']))
                                    )  # Do EDSM lookup during EDSM export
                        self.status['text'] = ''
                    except Exception as e:
                        if __debug__: print_exc()
                        self.status['text'] = unicode(e)
                else:
                    self.edsm.link(self.system['text'])
                self.edsmpoll()

                if not (config.getint('output') &
                        (config.OUT_CSV | config.OUT_TD | config.OUT_BPC
                         | config.OUT_EDDN)):
                    # no station data requested - we're done
                    pass

                elif not data['commander'].get('docked'):
                    # signal as error because the user might actually be docked but the server hosting the Companion API hasn't caught up
                    if not self.status['text']:
                        self.status['text'] = _(
                            "You're not docked at a station!")

                else:
                    # Finally - the data looks sane and we're docked at a station
                    (station_id, has_market, has_outfitting,
                     has_shipyard) = EDDB.station(self.system['text'],
                                                  self.station['text'])

                    # No EDDN output at known station?
                    if (
                            config.getint('output') & config.OUT_EDDN
                    ) and station_id and not has_market and not has_outfitting and not has_shipyard:
                        if not self.status['text']:
                            self.status['text'] = _(
                                "Station doesn't have anything!")

                    # No EDDN output at unknown station?
                    elif (
                            config.getint('output') & config.OUT_EDDN
                    ) and not station_id and not data['lastStarport'].get(
                            'commodities') and not data['lastStarport'].get(
                                'modules') and not data['lastStarport'].get(
                                    'ships'):
                        if not self.status['text']:
                            self.status['text'] = _(
                                "Station doesn't have anything!")

                    # No market output at known station?
                    elif not (config.getint('output') & config.OUT_EDDN
                              ) and station_id and not has_market:
                        if not self.status['text']:
                            self.status['text'] = _(
                                "Station doesn't have a market!")

                    # No market output at unknown station?
                    elif not (config.getint('output') &
                              config.OUT_EDDN) and not station_id and not data[
                                  'lastStarport'].get('commodities'):
                        if not self.status['text']:
                            self.status['text'] = _(
                                "Station doesn't have a market!")

                    else:
                        if data['lastStarport'].get('commodities'):
                            # Fixup anomalies in the commodity data
                            self.session.fixup(
                                data['lastStarport']['commodities'])

                            if config.getint('output') & config.OUT_CSV:
                                bpc.export(data, True)
                            if config.getint('output') & config.OUT_TD:
                                td.export(data)
                            if config.getint('output') & config.OUT_BPC:
                                bpc.export(data, False)

                        elif has_market and (
                                config.getint('output') &
                            (config.OUT_CSV | config.OUT_TD | config.OUT_BPC
                             | config.OUT_EDDN)):
                            # Overwrite any previous error message
                            self.status['text'] = _(
                                "Error: Can't get market data!")

                        if config.getint('output') & config.OUT_EDDN:
                            old_status = self.status['text']
                            if not old_status:
                                self.status['text'] = _(
                                    'Sending data to EDDN...')
                            self.w.update_idletasks()
                            eddn.export_commodities(data)
                            if has_outfitting or not station_id:
                                # Only send if eddb says that the station provides outfitting
                                eddn.export_outfitting(data)
                            elif __debug__ and data['lastStarport'].get(
                                    'modules'):
                                print 'Spurious outfitting!'
                            if has_shipyard or not station_id:
                                # Only send if eddb says that the station has a shipyard -
                                # https://github.com/Marginal/EDMarketConnector/issues/16
                                if data['lastStarport'].get('ships'):
                                    eddn.export_shipyard(data)
                                else:
                                    # API is flakey about shipyard info - silently retry if missing (<1s is usually sufficient - 5s for margin).
                                    self.w.after(int(SERVER_RETRY * 1000),
                                                 self.retry_for_shipyard)
                            elif __debug__ and data['lastStarport'].get(
                                    'ships'):
                                print 'Spurious shipyard!'
                            if not old_status:
                                self.status['text'] = ''

        except requests.exceptions.ConnectionError as e:
            if __debug__: print_exc()
            self.status['text'] = _("Error: Can't connect to EDDN")

        except requests.exceptions.Timeout as e:
            if __debug__: print_exc()
            self.status['text'] = _("Error: Connection to EDDN timed out")

        except Exception as e:
            if __debug__: print_exc()
            self.status['text'] = unicode(e)

        if not self.status['text']:  # no errors
            self.status['text'] = strftime(
                _('Last updated at {HH}:{MM}:{SS}').format(
                    HH='%H', MM='%M', SS='%S').encode('utf-8'),
                localtime(self.querytime)).decode('utf-8')
        elif play_sound:
            hotkeymgr.play_bad()

        self.holdofftime = self.querytime + companion.holdoff
        self.cooldown()
Example #8
0
    def getandsend(self, event=None, retrying=False):

        auto_update = not event
        play_sound = (auto_update or int(event.type) == self.EVENT_VIRTUAL) and not config.getint('hotkey_mute')
        play_bad = False

        if not monitor.cmdr or not monitor.mode or monitor.state['Captain'] or not monitor.system:
            return	# In CQC or on crew - do nothing

        if not retrying:
            if time() < self.holdofftime:	# Was invoked by key while in cooldown
                self.status['text'] = ''
                if play_sound and (self.holdofftime-time()) < companion.holdoff*0.75:
                    hotkeymgr.play_bad()	# Don't play sound in first few seconds to prevent repeats
                return
            elif play_sound:
                hotkeymgr.play_good()
            self.status['text'] = _('Fetching data...')
            self.button['state'] = self.theme_button['state'] = tk.DISABLED
            self.w.update_idletasks()

        try:
            querytime = int(time())
            data = self.session.station()
            config.set('querytime', querytime)

            # Validation
            if not data.get('commander', {}).get('name'):
                self.status['text'] = _("Who are you?!")		# Shouldn't happen
            elif (not data.get('lastSystem', {}).get('name') or
                  (data['commander'].get('docked') and not data.get('lastStarport', {}).get('name'))):	# Only care if docked
                self.status['text'] = _("Where are you?!")		# Shouldn't happen
            elif not data.get('ship', {}).get('name') or not data.get('ship', {}).get('modules'):
                self.status['text'] = _("What are you flying?!")	# Shouldn't happen
            elif monitor.cmdr and data['commander']['name'] != monitor.cmdr:
                raise companion.CmdrError()				# Companion API return doesn't match Journal
            elif ((auto_update and not data['commander'].get('docked')) or
                  (data['lastSystem']['name'] != monitor.system) or
                  ((data['commander']['docked'] and data['lastStarport']['name'] or None) != monitor.station) or
                  (data['ship']['id'] != monitor.state['ShipID']) or
                  (data['ship']['name'].lower() != monitor.state['ShipType'])):
                raise companion.ServerLagging()

            else:

                if __debug__:	# Recording
                    if isdir('dump'):
                        with open('dump/%s%s.%s.json' % (data['lastSystem']['name'], data['commander'].get('docked') and '.'+data['lastStarport']['name'] or '', strftime('%Y-%m-%dT%H.%M.%S', localtime())), 'wt') as h:
                            h.write(json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True, separators=(',', ': ')).encode('utf-8'))

                if not monitor.state['ShipType']:	# Started game in SRV or fighter
                    self.ship['text'] = companion.ship_map.get(data['ship']['name'].lower(), data['ship']['name'])
                    monitor.state['ShipID'] =   data['ship']['id']
                    monitor.state['ShipType'] = data['ship']['name'].lower()

                if data['commander'].get('credits') is not None:
                    monitor.state['Credits'] = data['commander']['credits']
                    monitor.state['Loan'] = data['commander'].get('debt', 0)

                # stuff we can do when not docked
                err = plug.notify_newdata(data, monitor.is_beta)
                self.status['text'] = err and err or ''
                if err:
                    play_bad = True

                if config.getint('output') & config.OUT_SHIP:
                    loadout.export(data)

                if not (config.getint('output') & ~config.OUT_SHIP & config.OUT_STATION_ANY):
                    # no station data requested - we're done
                    pass

                elif not data['commander'].get('docked'):
                    if not self.status['text']:
                        # Signal as error because the user might actually be docked but the server hosting the Companion API hasn't caught up
                        self.status['text'] = _("You're not docked at a station!")
                        play_bad = True

                else:
                    # Finally - the data looks sane and we're docked at a station

                    # No EDDN output?
                    if (config.getint('output') & config.OUT_MKT_EDDN) and not (data['lastStarport'].get('commodities') or data['lastStarport'].get('modules')):	# Ignore possibly missing shipyard info
                        if not self.status['text']:
                            self.status['text'] = _("Station doesn't have anything!")

                    # No market output?
                    elif not (config.getint('output') & config.OUT_MKT_EDDN) and not data['lastStarport'].get('commodities'):
                        if not self.status['text']:
                            self.status['text'] = _("Station doesn't have a market!")

                    else:
                        if data['lastStarport'].get('commodities') and config.getint('output') & (config.OUT_MKT_CSV|config.OUT_MKT_TD):
                            # Fixup anomalies in the commodity data
                            fixed = companion.fixup(data)

                            if config.getint('output') & config.OUT_MKT_CSV:
                                commodity.export(fixed, COMMODITY_CSV)
                            if config.getint('output') & config.OUT_MKT_TD:
                                td.export(fixed)

                        if config.getint('output') & config.OUT_MKT_EDDN:
                            old_status = self.status['text']
                            if not old_status:
                                self.status['text'] = _('Sending data to EDDN...')
                            self.w.update_idletasks()
                            self.eddn.export_commodities(data, monitor.is_beta)
                            self.eddn.export_outfitting(data, monitor.is_beta)
                            if data['lastStarport'].get('ships'):
                                self.eddn.export_shipyard(data, monitor.is_beta)
                            elif data['lastStarport'].get('services', {}).get('shipyard'):
                                # API is flakey about shipyard info - silently retry if missing (<1s is usually sufficient - 5s for margin).
                                self.w.after(int(SERVER_RETRY * 1000), lambda:self.retry_for_shipyard(2))
                            if not old_status:
                                self.status['text'] = ''

        except companion.VerificationRequired:
            return prefs.AuthenticationDialog(self.w, partial(self.verify, self.getandsend))

        # Companion API problem
        except (companion.ServerError, companion.ServerLagging) as e:
            if retrying:
                self.status['text'] = unicode(e)
                play_bad = True
            else:
                # Retry once if Companion server is unresponsive
                self.w.after(int(SERVER_RETRY * 1000), lambda:self.getandsend(event, True))
                return	# early exit to avoid starting cooldown count

        except requests.RequestException as e:
            if __debug__: print_exc()
            self.status['text'] = _("Error: Can't connect to EDDN")
            play_bad = True

        except Exception as e:
            if __debug__: print_exc()
            self.status['text'] = unicode(e)
            play_bad = True

        if not self.status['text']:	# no errors
            self.status['text'] = strftime(_('Last updated at {HH}:{MM}:{SS}').format(HH='%H', MM='%M', SS='%S').encode('utf-8'), localtime(querytime)).decode('utf-8')
        if play_sound and play_bad:
            hotkeymgr.play_bad()

        self.holdofftime = querytime + companion.holdoff
        self.cooldown()
Example #9
0
def main():
    """Run the main code of the program."""
    try:
        # arg parsing
        parser = argparse.ArgumentParser(
            prog=appcmdname,
            description='Prints the current system and station (if docked) to stdout and optionally writes player '
                        'status, ship locations, ship loadout and/or station data to file. '
                        'Requires prior setup through the accompanying GUI app.'
        )

        parser.add_argument('-v', '--version', help='print program version and exit', action='store_const', const=True)
        group_loglevel = parser.add_mutually_exclusive_group()
        group_loglevel.add_argument('--loglevel',
                                    metavar='loglevel',
                                    help='Set the logging loglevel to one of: '
                                         'CRITICAL, ERROR, WARNING, INFO, DEBUG, TRACE',
                                    )
        group_loglevel.add_argument('--trace',
                                    help='Set the Debug logging loglevel to TRACE',
                                    action='store_true',
                                    )
        parser.add_argument('-a', metavar='FILE', help='write ship loadout to FILE in Companion API json format')
        parser.add_argument('-e', metavar='FILE', help='write ship loadout to FILE in E:D Shipyard plain text format')
        parser.add_argument('-l', metavar='FILE', help='write ship locations to FILE in CSV format')
        parser.add_argument('-m', metavar='FILE', help='write station commodity market data to FILE in CSV format')
        parser.add_argument('-o', metavar='FILE', help='write station outfitting data to FILE in CSV format')
        parser.add_argument('-s', metavar='FILE', help='write station shipyard data to FILE in CSV format')
        parser.add_argument('-t', metavar='FILE', help='write player status to FILE in CSV format')
        parser.add_argument('-d', metavar='FILE', help='write raw JSON data to FILE')
        parser.add_argument('-n', action='store_true', help='send data to EDDN')
        parser.add_argument('-p', metavar='CMDR', help='Returns data from the specified player account')
        parser.add_argument('-j', help=argparse.SUPPRESS)  # Import JSON dump
        args = parser.parse_args()

        if args.version:
            updater = Updater(provider='internal')
            newversion: Optional[EDMCVersion] = updater.check_appcast()
            if newversion:
                print(f'{appversion} ({newversion.title!r} is available)')
            else:
                print(appversion)

            return

        if args.trace:
            edmclogger.set_channels_loglevel(logging.TRACE)

        elif args.loglevel:
            if args.loglevel not in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'TRACE'):
                print('loglevel must be one of: CRITICAL, ERROR, WARNING, INFO, DEBUG, TRACE', file=sys.stderr)
                sys.exit(EXIT_ARGS)
            edmclogger.set_channels_loglevel(args.loglevel)

        logger.debug(f'Startup v{appversion} : Running on Python v{sys.version}')
        logger.debug(f'''Platform: {sys.platform}
argv[0]: {sys.argv[0]}
exec_prefix: {sys.exec_prefix}
executable: {sys.executable}
sys.path: {sys.path}'''
                     )

        log_locale('Initial Locale')

        if args.j:
            logger.debug('Import and collate from JSON dump')
            # Import and collate from JSON dump
            data = json.load(open(args.j))
            config.set('querytime', int(getmtime(args.j)))

        else:
            # Get state from latest Journal file
            logger.debug('Getting state from latest journal file')
            try:
                logdir = config.get('journaldir') or config.default_journal_dir
                logger.debug(f'logdir = "{logdir}"')
                logfiles = sorted((x for x in os.listdir(logdir) if JOURNAL_RE.search(x)),
                                  key=lambda x: x.split('.')[1:])

                logfile = join(logdir, logfiles[-1])

                logger.debug(f'Using logfile "{logfile}"')
                with open(logfile, 'r') as loghandle:
                    for line in loghandle:
                        try:
                            monitor.parse_entry(line)
                        except Exception:
                            logger.debug(f'Invalid journal entry {line!r}')

            except Exception:
                logger.exception("Can't read Journal file")
                sys.exit(EXIT_SYS_ERR)

            if not monitor.cmdr:
                logger.error('Not available while E:D is at the main menu')
                sys.exit(EXIT_SYS_ERR)

            # Get data from Companion API
            if args.p:
                logger.debug(f'Attempting to use commander "{args.p}"')
                cmdrs = config.get('cmdrs') or []
                if args.p in cmdrs:
                    idx = cmdrs.index(args.p)

                else:
                    for idx, cmdr in enumerate(cmdrs):
                        if cmdr.lower() == args.p.lower():
                            break

                    else:
                        raise companion.CredentialsError()

                companion.session.login(cmdrs[idx], monitor.is_beta)

            else:
                logger.debug(f'Attempting to use commander "{monitor.cmdr}" from Journal File')
                cmdrs = config.get('cmdrs') or []
                if monitor.cmdr not in cmdrs:
                    raise companion.CredentialsError()

                companion.session.login(monitor.cmdr, monitor.is_beta)

            querytime = int(time())
            data = companion.session.station()
            config.set('querytime', querytime)

        # Validation
        if not deep_get(data, 'commander', 'name', default='').strip():
            logger.error("No data['command']['name'] from CAPI")
            sys.exit(EXIT_SERVER)

        elif not deep_get(data, 'lastSystem', 'name') or \
                data['commander'].get('docked') and not \
                deep_get(data, 'lastStarport', 'name'):  # Only care if docked

            logger.error("No data['lastSystem']['name'] from CAPI")
            sys.exit(EXIT_SERVER)

        elif not deep_get(data, 'ship', 'modules') or not deep_get(data, 'ship', 'name', default=''):
            logger.error("No data['ship']['modules'] from CAPI")
            sys.exit(EXIT_SERVER)

        elif args.j:
            pass  # Skip further validation

        elif data['commander']['name'] != monitor.cmdr:
            logger.error(f'Commander "{data["commander"]["name"]}" from CAPI doesn\'t match "{monitor.cmdr}" from Journal')  # noqa: E501
            sys.exit(EXIT_CREDENTIALS)

        elif data['lastSystem']['name'] != monitor.system or \
                ((data['commander']['docked'] and data['lastStarport']['name'] or None) != monitor.station) or \
                data['ship']['id'] != monitor.state['ShipID'] or \
                data['ship']['name'].lower() != monitor.state['ShipType']:

            logger.error('Mismatch(es) between CAPI and Journal for at least one of: StarSystem, Last Star Port, Ship ID or Ship Name/Type')  # noqa: E501
            sys.exit(EXIT_LAGGING)

        # stuff we can do when not docked
        if args.d:
            logger.debug(f'Writing raw JSON data to "{args.d}"')
            out = json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True, separators=(',', ': '))
            with open(args.d, 'wb') as f:
                f.write(out.encode("utf-8"))

        if args.a:
            logger.debug(f'Writing Ship Loadout in Companion API JSON format to "{args.a}"')
            loadout.export(data, args.a)

        if args.e:
            logger.debug(f'Writing Ship Loadout in ED Shipyard plain text format to "{args.e}"')
            edshipyard.export(data, args.e)

        if args.l:
            logger.debug(f'Writing Ship Locations in CSV format to "{args.l}"')
            stats.export_ships(data, args.l)

        if args.t:
            logger.debug(f'Writing Player Status in CSV format to "{args.t}"')
            stats.export_status(data, args.t)

        if data['commander'].get('docked'):
            print(f'{deep_get(data, "lastSystem", "name", default="Unknown")},'
                  f'{deep_get(data, "lastStarport", "name", default="Unknown")}'
                  )

        else:
            print(deep_get(data, 'lastSystem', 'name', default='Unknown'))

        if (args.m or args.o or args.s or args.n or args.j):
            if not data['commander'].get('docked'):
                logger.error("Can't use -m, -o, -s, -n or -j because you're not currently docked!")
                return

            elif not deep_get(data, 'lastStarport', 'name'):
                logger.error("No data['lastStarport']['name'] from CAPI")
                sys.exit(EXIT_LAGGING)

            # Ignore possibly missing shipyard info
            elif not (data['lastStarport'].get('commodities') or data['lastStarport'].get('modules')):
                logger.error("No commodities or outfitting (modules) in CAPI data")
                return

        else:
            return

        # Finally - the data looks sane and we're docked at a station

        if args.j:
            logger.debug('Importing data from the CAPI return...')
            # Collate from JSON dump
            collate.addcommodities(data)
            collate.addmodules(data)
            collate.addships(data)

        if args.m:
            logger.debug(f'Writing Station Commodity Market Data in CSV format to "{args.m}"')
            if data['lastStarport'].get('commodities'):
                # Fixup anomalies in the commodity data
                fixed = companion.fixup(data)
                commodity.export(fixed, COMMODITY_DEFAULT, args.m)

            else:
                logger.error("Station doesn't have a market")

        if args.o:
            if data['lastStarport'].get('modules'):
                logger.debug(f'Writing Station Outfitting in CSV format to "{args.o}"')
                outfitting.export(data, args.o)

            else:
                logger.error("Station doesn't supply outfitting")

        if (args.s or args.n) and not args.j and not \
                data['lastStarport'].get('ships') and data['lastStarport']['services'].get('shipyard'):

            # Retry for shipyard
            sleep(SERVER_RETRY)
            new_data = companion.session.station()
            # might have undocked while we were waiting for retry in which case station data is unreliable
            if new_data['commander'].get('docked') and \
                    deep_get(new_data, 'lastSystem', 'name') == monitor.system and \
                    deep_get(new_data, 'lastStarport', 'name') == monitor.station:

                data = new_data

        if args.s:
            if deep_get(data, 'lastStarport', 'ships', 'shipyard_list'):
                logger.debug(f'Writing Station Shipyard in CSV format to "{args.s}"')
                shipyard.export(data, args.s)

            elif not args.j and monitor.stationservices and 'Shipyard' in monitor.stationservices:
                logger.error('Failed to get shipyard data')

            else:
                logger.error("Station doesn't have a shipyard")

        if args.n:
            try:
                eddn_sender = eddn.EDDN(None)
                logger.debug('Sending Market, Outfitting and Shipyard data to EDDN...')
                eddn_sender.export_commodities(data, monitor.is_beta)
                eddn_sender.export_outfitting(data, monitor.is_beta)
                eddn_sender.export_shipyard(data, monitor.is_beta)

            except Exception:
                logger.exception('Failed to send data to EDDN')

    except companion.ServerError:
        logger.error('Frontier CAPI Server returned an error')
        sys.exit(EXIT_SERVER)

    except companion.SKUError:
        logger.error('Frontier CAPI Server SKU problem')
        sys.exit(EXIT_SERVER)

    except companion.CredentialsError:
        logger.error('Frontier CAPI Server: Invalid Credentials')
        sys.exit(EXIT_CREDENTIALS)
Example #10
0
    # Validation
    if not data.get('commander') or not data['commander'].get('name','').strip():
        sys.stderr.write('Who are you?!\n')
        sys.exit(EXIT_SERVER)
    elif not data.get('lastSystem') or not data['lastSystem'].get('name','').strip() or not data.get('lastStarport') or not data['lastStarport'].get('name','').strip():
        sys.stderr.write('Where are you?!\n')		# Shouldn't happen
        sys.exit(EXIT_SERVER)
    elif not data.get('ship') or not data['ship'].get('modules') or not data['ship'].get('name','').strip():
        sys.stderr.write('What are you flying?!\n')	# Shouldn't happen
        sys.exit(EXIT_SERVER)

    # stuff we can do when not docked
    if args.c:
        coriolis.export(data, args.c)
    if args.e:
        loadout.export(data, args.e)
    if args.l:
        stats.export_ships(data, args.l)
    if args.t:
        stats.export_status(data, args.t)

    if not data['commander'].get('docked'):
        print data['lastSystem']['name']
        if (args.m or args.o or args.s):
            sys.stderr.write("You're not docked at a station!\n")
            sys.exit(EXIT_NOT_DOCKED)
        else:
            sys.exit(EXIT_SUCCESS)

    # Finally - the data looks sane and we're docked at a station
    print '%s,%s' % (data['lastSystem']['name'], data['lastStarport']['name'])
    def getandsend(self, event=None, retrying=False):

        if not retrying:
            if time() < self.holdofftime:
                return  # Was invoked by Return key while in cooldown
            self.cmdr['text'] = self.system['text'] = self.station['text'] = ''
            self.status['text'] = 'Fetching station data...'
            self.button['state'] = tk.DISABLED
            self.w.update_idletasks()

        try:
            querytime = int(time())

            data = self.session.query()

            self.cmdr['text'] = data.get('commander') and data.get(
                'commander').get('name') or ''
            self.system['text'] = data.get('lastSystem') and data.get(
                'lastSystem').get('name') or ''
            self.station['text'] = data.get('commander') and data.get(
                'commander').get('docked') and data.get(
                    'lastStarport') and data.get('lastStarport').get(
                        'name') or '-'

            config.set('querytime', querytime)
            self.holdofftime = querytime + companion.holdoff

            # Validation
            if not data.get('commander') or not data['commander'].get(
                    'name', '').strip():
                self.status['text'] = "Who are you?!"  # Shouldn't happen
            elif not data.get('lastSystem') or not data['lastSystem'].get(
                    'name', '').strip() or not data.get(
                        'lastStarport') or not data['lastStarport'].get(
                            'name', '').strip():
                self.status['text'] = "Where are you?!"  # Shouldn't happen
            elif not data.get('ship') or not data['ship'].get(
                    'modules') or not data['ship'].get('name', '').strip():
                self.status[
                    'text'] = "What are you flying?!"  # Shouldn't happen
            elif (config.getint('output') & config.OUT_EDDN
                  ) and not data['lastStarport'].get('ships') and not retrying:
                # API is flakey about shipyard info - retry if missing (<1s is usually sufficient - 2.5s for margin).
                self.w.after(2500, lambda: self.getandsend(retrying=True))
                return
            else:
                if __debug__ and retrying:
                    print data['lastStarport'].get(
                        'ships'
                    ) and 'Retry for shipyard - Success' or 'Retry for shipyard - Fail'

                # stuff we can do when not docked
                if __debug__:  # Recording
                    with open(
                            '%s%s.%s.json' %
                        (data['lastSystem']['name'],
                         data['commander'].get('docked')
                         and '.' + data['lastStarport']['name'] or '',
                         strftime('%Y-%m-%dT%H.%M.%S', localtime())),
                            'wt') as h:
                        h.write(json.dumps(data, indent=2, sort_keys=True))
                if config.getint('output') & config.OUT_LOG:
                    flightlog.export(data)
                if config.getint('output') & config.OUT_SHIP:
                    loadout.export(data)

                if not (config.getint('output') &
                        (config.OUT_CSV | config.OUT_TD | config.OUT_BPC
                         | config.OUT_EDDN)):
                    # no further output requested
                    self.status['text'] = strftime('Last updated at %H:%M:%S',
                                                   localtime(querytime))

                elif not data['commander'].get('docked'):
                    self.status['text'] = "You're not docked at a station!"
                else:
                    if data['lastStarport'].get('commodities'):
                        # Fixup anomalies in the commodity data
                        self.session.fixup(data['lastStarport']['commodities'])

                        if config.getint('output') & config.OUT_CSV:
                            bpc.export(data, True)
                        if config.getint('output') & config.OUT_TD:
                            td.export(data)
                        if config.getint('output') & config.OUT_BPC:
                            bpc.export(data, False)

                    if config.getint('output') & config.OUT_EDDN:
                        if data['lastStarport'].get(
                                'commodities') or data['lastStarport'].get(
                                    'modules') or data['lastStarport'].get(
                                        'ships'):
                            self.status['text'] = 'Sending data to EDDN...'
                            self.w.update_idletasks()
                            eddn.export(data)
                            self.status['text'] = strftime(
                                'Last updated at %H:%M:%S',
                                localtime(querytime))
                        else:
                            self.status[
                                'text'] = "Station doesn't have anything!"
                    elif not data['lastStarport'].get('commodities'):
                        self.status['text'] = "Station doesn't have a market!"
                    else:
                        self.status['text'] = strftime(
                            'Last updated at %H:%M:%S', localtime(querytime))

        except companion.VerificationRequired:
            return prefs.AuthenticationDialog(self.w, self.verify)

        # Companion API problem
        except companion.ServerError as e:
            self.status['text'] = str(e)

        except requests.exceptions.ConnectionError as e:
            if __debug__: print_exc()
            self.status['text'] = "Error: Can't connect to EDDN"

        except requests.exceptions.Timeout as e:
            if __debug__: print_exc()
            self.status['text'] = "Error: Connection to EDDN timed out"

        except Exception as e:
            if __debug__: print_exc()
            self.status['text'] = str(e)

        self.cooldown()