Update api.py, command_line.py and five other files

This commit is contained in:
Richard Bronkhorst 2023-06-16 13:03:19 +02:00
parent 92a5a02180
commit 2c96cbb533
7 changed files with 117 additions and 32 deletions

View File

@ -90,17 +90,27 @@ class Api:
system = waypoint.system() system = waypoint.system()
symbol = str(waypoint) symbol = str(waypoint)
data = self.request('get', f'systems/{system}/waypoints/{waypoint}/market') data = self.request('get', f'systems/{system}/waypoints/{waypoint}/market')
return self.store.update(Marketplace, symbol, data) return self.store.update(Marketplace, data)
def jumps(self, waypoint): def jumps(self, waypoint):
data = self.request('get', f'systems/{waypoint.system()}/waypoints/{waypoint}/jump-gate') data = self.request('get', f'systems/{waypoint.system()}/waypoints/{waypoint}/jump-gate')
symbol = str(waypoint) symbol = str(waypoint)
return self.store.update(Jumpgate, symbol, data) return self.store.update(Jumpgate, data)
def list_ships(self): def list_ships(self):
data = self.request('get', 'my/ships') data = self.request('get', 'my/ships')
return self.store.update_list(Ship, data) return self.store.update_list(Ship, data)
def list_contracts(self):
data = self.request('get', 'my/contracts')
return self.store.update_list('Contract', data)
def negotiate(self, ship):
data = self.request('post', f'my/ships/{ship}/negotiate/contract')
if data is not None and 'contract' in data:
contract = self.store.update('Contract', data['contract'])
return contract
def navigate(self, ship, wp): def navigate(self, ship, wp):
data = {'waypointSymbol': str(wp)} data = {'waypointSymbol': str(wp)}
response = self.request('post', f'my/ships/{ship}/navigate', data) response = self.request('post', f'my/ships/{ship}/navigate', data)

View File

@ -41,7 +41,7 @@ class CommandLine:
print(f'command not found; {c}') print(f'command not found; {c}')
def handle_error(self, cmd, args, e): def handle_error(self, cmd, args, e):
logging.error(e, exc_info=str(type(e))!='ApiErrorp') logging.error(e, exc_info=type(e).__name__ !='ApiError')
def handle_empty(self): def handle_empty(self):
pass pass

View File

@ -81,8 +81,14 @@ class Commander(CommandLine):
system = self.store.get(System, system_str) system = self.store.get(System, system_str)
r = self.store.all_members(system, 'Waypoint') r = self.store.all_members(system, 'Waypoint')
for w in r: for w in r:
traits = ','.join(w.traits) traits = []
print(w.symbol, traits) if 'MARKETPLACE' in w.traits:
traits.append('MARKET')
if 'SHIPYARD' in w.traits:
traits.append('SHIPYARD')
if w.type == 'JUMP_GATE':
traits.append('JUMP')
print(w.symbol.split('-')[2], ', '.join(traits))
def do_marketplace(self, waypoint_str): def do_marketplace(self, waypoint_str):
waypoint = self.store.get(Waypoint, waypoint_str.upper()) waypoint = self.store.get(Waypoint, waypoint_str.upper())
@ -119,6 +125,13 @@ class Commander(CommandLine):
r = list(self.store.all('Ship')) r = list(self.store.all('Ship'))
pprint(r) pprint(r)
def do_contracts(self, arg=''):
if arg.startswith('r'):
r = self.api.list_contracts()
else:
r = list(self.store.all('Contract'))
pprint(r)
def do_ship(self, arg=''): def do_ship(self, arg=''):
if arg != '': if arg != '':
symbol = f'{self.agent.symbol}-{arg}' symbol = f'{self.agent.symbol}-{arg}'
@ -128,7 +141,7 @@ class Commander(CommandLine):
return return
else: else:
self.ship = ship self.ship = ship
pprint(ship) pprint(self.ship)
def do_pp(self): def do_pp(self):
pprint(self.api.last_result) pprint(self.api.last_result)
@ -151,3 +164,8 @@ class Commander(CommandLine):
self.api.orbit(self.ship) self.api.orbit(self.ship)
pprint(self.ship) pprint(self.ship)
def do_negotiate(self):
if not self.has_ship(): return
r = self.api.negotiate(self.ship)
pprint(r)

View File

@ -4,6 +4,7 @@ from nullptr.util import sg
@dataclass @dataclass
class Base: class Base:
identifier = 'symbol'
symbol: str symbol: str
store: object store: object
@ -17,11 +18,13 @@ class Base:
def __eq__(self, other): def __eq__(self, other):
return self.symbol == other.symbol and type(self) == type(other) return self.symbol == other.symbol and type(self) == type(other)
def seta(self, attr, d, name=None): def seta(self, attr, d, name=None, interp=None):
if name is None: if name is None:
name = attr name = attr
val = sg(d, name) val = sg(d, name)
if val is not None: if val is not None:
if interp is not None:
val = interp(val)
setattr(self, attr, val) setattr(self, attr, val)
def setlst(self, attr, d, name, member): def setlst(self, attr, d, name, member):
@ -37,6 +40,9 @@ class Base:
def update(self, d): def update(self, d):
pass pass
def load(self, d):
self.__dict__ = d
def dict(self): def dict(self):
r = {} r = {}

View File

@ -0,0 +1,59 @@
from time import time
from nullptr.util import *
from .base import Base
from typing import List
class Contract(Base):
identifier = 'id'
type: str
deliveries: List
accepted: bool
fulfilled: bool
expires: int
expires_str: str
pay: int
@classmethod
def ext(cls):
return 'cnt'
def path(self):
return f'contracts/{self.symbol}.{self.ext()}'
def is_expired(self):
return time() > self.expires
def api_dict(self):
return {
'id': self.symbol,
'expiration': self.expires_str,
}
def update(self, d):
self.seta('expires',d, 'terms.deadline',parse_timestamp)
self.seta('expires_str', d,'terms.deadline')
self.seta('accepted', d, 'accepted')
self.seta('fulfilled', d, 'fulfilled')
self.seta('type', d, 'type')
self.pay = mg(d, 'terms.payment.onAccepted') + mg(d, 'terms.payment.onFulfilled')
deliveries = must_get(d, 'terms.deliver')
self.deliveries = []
for e in deliveries:
delivery = {}
delivery['trade_symbol'] = must_get(e, 'tradeSymbol')
delivery['units_fulfilled'] = must_get(e, 'unitsFulfilled')
delivery['units_required'] = must_get(e, 'unitsRequired')
delivery['destination'] = must_get(e, 'destinationSymbol')
self.deliveries.append(delivery)
def f(self, detail=1):
hours = int(max(0, self.expires - time()) / 3600)
accepted = 'A' if self.accepted else '-'
fulfilled = 'F' if self.fulfilled else '-'
result = f'{self.symbol} {hours}h {accepted}{fulfilled}'
if detail > 1:
result += '\n'
for d in self.deliveries:
result += f"({d['units_fulfilled']} / {d['units_required']}) {d['trade_symbol']} to {d['destination']}"
return result

View File

@ -3,13 +3,6 @@ from time import time
from nullptr.util import * from nullptr.util import *
from dataclasses import dataclass from dataclasses import dataclass
@dataclass
class InventoryItem:
symbol: str
units: int
def __str__(self):
return self.symbol + ': ' + str(self.units)
class Ship(Base): class Ship(Base):
cargo:dict = {} cargo:dict = {}
mission_state:dict = {} mission_state:dict = {}
@ -38,7 +31,6 @@ class Ship(Base):
def update(self, d): def update(self, d):
self.seta('status', d, 'nav.status') self.seta('status', d, 'nav.status')
self.seta('location_str', d, 'nav.waypointSymbol') self.seta('location_str', d, 'nav.waypointSymbol')
self.seta('cargo_capacity', d, 'cargo.capacity') self.seta('cargo_capacity', d, 'cargo.capacity')
self.seta('cargo_units', d, 'cargo.units') self.seta('cargo_units', d, 'cargo.units')
self.seta('fuel_capacity', d, 'fuel.capacity') self.seta('fuel_capacity', d, 'fuel.capacity')
@ -46,13 +38,9 @@ class Ship(Base):
cargo = sg(d, 'cargo.inventory') cargo = sg(d, 'cargo.inventory')
if cargo is not None: if cargo is not None:
self.load_cargo(cargo) self.load_cargo(cargo)
cooldown = sg(d, 'cooldown.expiration') self.seta('cooldown', d, 'cooldown.expiration', parse_timestamp)
if cooldown: self.seta('arrival', d, 'nav.route.arrival', parse_timestamp)
self.cooldown = parse_timestamp(cooldown)
arrival = sg(d, 'nav.route.arrival')
if arrival:
self.arrival = parse_timestamp(arrival)
def tick(self): def tick(self):
if self.status == 'IN_TRANSIT' and self.arrival < time(): if self.status == 'IN_TRANSIT' and self.arrival < time():
self.status = 'IN_ORBIT' self.status = 'IN_ORBIT'
@ -66,26 +54,26 @@ class Ship(Base):
def get_cargo(self, typ): def get_cargo(self, typ):
if typ not in self.cargo: if typ not in self.cargo:
return 0 return 0
return self.cargo[typ].units return self.cargo[typ]
def load_cargo(self, cargo): def load_cargo(self, cargo):
result = {} result = {}
for i in cargo: for i in cargo:
symbol = must_get(i, 'symbol') symbol = must_get(i, 'symbol')
units = must_get(i, 'units') units = must_get(i, 'units')
result[symbol] = InventoryItem(symbol, units) result[symbol] = units
self.cargo = result self.cargo = result
def deliverable_cargo(self, contract): def deliverable_cargo(self, contract):
result = [] result = []
for d in contract.deliveries: for d in contract.deliveries:
if self.get_cargo(d.trade_symbol) > 0: if self.get_cargo(d['trade_symbol']) > 0:
result.append(d.trade_symbol) result.append(d['trade_symbol'])
return result return result
def nondeliverable_cargo(self, contract): def nondeliverable_cargo(self, contract):
cargo = [c.symbol for c in self.cargo.values()] cargo = self.cargo.keys()
deliveries = [d.trade_symbol for d in contract.deliveries] deliveries = [d['trade_symbol'] for d in contract.deliveries]
garbage = [c for c in cargo if c not in deliveries] garbage = [c for c in cargo if c not in deliveries]
return garbage return garbage

View File

@ -7,6 +7,7 @@ from nullptr.models.marketplace import Marketplace
from nullptr.models.system_member import SystemMember from nullptr.models.system_member import SystemMember
from nullptr.models.jumpgate import Jumpgate from nullptr.models.jumpgate import Jumpgate
from nullptr.models.ship import Ship from nullptr.models.ship import Ship
from nullptr.models.contract import Contract
from os.path import isfile, dirname, isdir from os.path import isfile, dirname, isdir
import os import os
from os.path import basename from os.path import basename
@ -46,8 +47,8 @@ class Store:
typ = self.extensions[ext] typ = self.extensions[ext]
obj = self.create(typ, symbol) obj = self.create(typ, symbol)
data['store'] = self obj.load(data)
obj.__dict__ = data obj.store = self
return obj return obj
def load(self): def load(self):
@ -92,13 +93,16 @@ class Store:
return None return None
return self.data[typ][symbol] return self.data[typ][symbol]
def update(self, typ, symbol, data): def update(self, typ, data):
if type(typ) == str and typ in self.model_names:
typ = self.model_names[typ]
symbol = mg(data, typ.identifier)
obj = self.get(typ, symbol, True) obj = self.get(typ, symbol, True)
obj.update(data) obj.update(data)
return obj return obj
def update_list(self, typ, lst): def update_list(self, typ, lst):
return [self.update(typ, mg(d, 'symbol'), d) for d in lst] return [self.update(typ, d) for d in lst]
def all(self, typ): def all(self, typ):
if type(typ) == str and typ in self.model_names: if type(typ) == str and typ in self.model_names: