Update commander.py, Dockerfile and twenty-five other files

This commit is contained in:
Richard Bronkhorst 2023-06-11 20:51:03 +02:00
parent 042b931133
commit 1c46d25081
18 changed files with 209 additions and 75 deletions

View File

@ -8,5 +8,5 @@ RUN pip3 install -r requirements.txt
ADD --chown=user . /app
RUN chmod +x /app/commander.py
VOLUME /data
ENTRYPOINT [ "/app/commander.py"]
CMD ["-s", "/data/store.db"]
ENTRYPOINT [ "/app/main.py"]
CMD ["-s", "/data/"]

View File

@ -1,50 +0,0 @@
from store import Store
from command_line import CommandLine
import argparse
from models.agent import Agent
from api import Api
from util import *
class Commander(CommandLine):
def __init__(self, store_dir='data', agent=None):
self.store_dir = store_dir
self.store = Store(store_dir)
self.agent = self.select_agent(agent)
self.api = Api(self.store, self.agent)
self.store.flush()
super().__init__()
def select_agent(self, agent_str):
if agent_str is not None:
return self.store.get(Agent, agent_str)
else:
agents = self.store.all('', Agent)
agent = next(agents, None)
if agent is None:
symbol = input('agent name: ')
agent = self.store.get(Agent, symbol)
return agent
def after_cmd(self):
self.store.flush()
def do_info(self):
pprint(self.api.info(), 100)
def do_register(self, faction):
self.api.register(faction.upper())
def do_systems(self, page=1):
self.api.list_systems(int(page))
def main(args):
c = Commander(args.store_dir, args.agent)
c.run()
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--store-dir', default='data')
parser.add_argument('-a', '--agent', default=None)
args = parser.parse_args()
main(args)

15
main.py Normal file
View File

@ -0,0 +1,15 @@
import argparse
from nullptr.commander import Commander
def main(args):
c = Commander(args.store_dir, args.agent)
c.run()
# X1-AG74-41076A
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--store-dir', default='data')
parser.add_argument('-a', '--agent', default=None)
args = parser.parse_args()
main(args)

View File

@ -1,7 +0,0 @@
from .base import Base
class Waypoint(Base):
@classmethod
def ext(self):
return 'way'

View File

@ -1,6 +1,8 @@
import requests
from models.system import System
from util import *
from nullptr.models.system import System
from nullptr.models.waypoint import Waypoint
from nullptr.models.marketplace import Marketplace
from .util import *
class ApiError(Exception):
def __init__(self, msg, code):
@ -11,6 +13,7 @@ class Api:
def __init__(self, store, agent):
self.agent = agent
self.store = store
self.meta = None
self.root = 'https://api.spacetraders.io/v2/'
def token(self):
@ -30,7 +33,9 @@ class Api:
self.last_result = result
if result is None:
raise ApiError('http call failed', r.status_code)
elif 'data' not in result:
if 'meta' in result:
self.last_meta = result['meta']
if 'data' not in result:
error_code = sg(result, 'error.code', -1)
self.last_error = error_code
error_message = sg(result, 'error.message')
@ -56,6 +61,16 @@ class Api:
def list_systems(self, page=1):
data = self.request('get', 'systems', params={'page': page})
#pprint(self.last_meta)
return self.store.update_list(System, data)
def list_waypoints(self, system):
data = self.request('get', f'systems/{system}/waypoints/')
# pprintz(self.last_meta)
return self.store.update_list(Waypoint, data)
def marketplace(self, waypoint):
system = waypoint.system()
symbol = f'{waypoint}-market'
data = self.request('get', f'systems/{system}/waypoints/{waypoint}/market')
return self.store.update(Marketplace, symbol, data)

View File

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

98
nullptr/commander.py Normal file
View File

@ -0,0 +1,98 @@
from nullptr.command_line import CommandLine
from nullptr.store import Store
import argparse
from nullptr.models.agent import Agent
from nullptr.models.system import System
from nullptr.models.waypoint import Waypoint
from nullptr.api import Api
from .util import *
from time import sleep
from threading import Thread
class Commander(CommandLine):
def __init__(self, store_dir='data', agent=None):
self.store_dir = store_dir
self.store = Store(store_dir)
self.agent = self.select_agent(agent)
self.api = Api(self.store, self.agent)
self.store.flush()
self.stop_auto= False
super().__init__()
def select_agent(self, agent_str):
if agent_str is not None:
return self.store.get(Agent, agent_str)
else:
agents = self.store.all('', Agent)
agent = next(agents, None)
if agent is None:
symbol = input('agent name: ')
agent = self.store.get(Agent, symbol)
return agent
def after_cmd(self):
self.store.flush()
def do_info(self):
pprint(self.api.info(), 100)
def do_register(self, faction):
self.api.register(faction.upper())
def wait_for_stop(self):
input()
self.stop_auto = True
print('stopping...')
def do_universe(self):
print('universe mode. hit enter to stop')
t = Thread(target=self.wait_for_stop)
t.daemon = True
t.start()
self.all_systems()
print('manual mode')
def all_specials(self, waypoints):
for w in waypoints:
if 'MARKETPLACE' in w.traits:
self.api.marketplace(w)
sleep(0.5)
def all_waypoints(self, systems):
for s in systems:
if self.stop_auto:
break
r = self.api.list_waypoints(s)
print(f'system {s}: {len(r)} waypoints')
sleep(0.5)
def all_systems(self):
self.stop_auto = False
data = self.api.list_systems(1)
pages = total_pages(self.api.last_meta)
print(f'page {1}: {len(data)} results')
self.all_waypoints(data)
print(f'{pages} more pages of systems')
for p in range(2, pages):
if self.stop_auto:
break
data = self.api.list_systems(p)
print(f'page {p}: {len(data)} systems')
self.all_waypoints(data)
sleep(0.5)
self.store.flush()
def do_systems(self, page=1):
r = self.api.list_systems(int(page))
pprint(self.api.last_meta)
def do_waypoints(self, system_str):
system = self.store.get(System, system_str.upper())
r = self.api.list_waypoints(system)
pprint(r)
def do_marketplace(self, waypoint_str):
waypoint = self.store.get(Waypoint, waypoint_str.upper())
r = self.api.marketplace(waypoint)

View File

View File

@ -1,6 +1,6 @@
from copy import deepcopy
from dataclasses import dataclass
from util import sg
from nullptr.util import sg
@dataclass
class Base:
symbol: str
@ -18,6 +18,12 @@ class Base:
if val is not None:
setattr(self, attr, val)
def setlst(self, attr, d, name, member):
val = sg(d, name)
if val is not None:
lst = [sg(x, member) for x in val]
setattr(self, attr, lst)
def __setattr__(self, name, value):
if name != 'dirty':
self.dirty = True

View File

@ -0,0 +1,21 @@
from .base import Base
from typing import List
class Marketplace(Base):
imports:List[str] = []
exports:List[str] = []
exchange:List[str] = []
def update(self, d):
self.setlst('imports', d, 'imports', 'symbol')
self.setlst('exports', d, 'exports', 'symbol')
self.setlst('exchange', d, 'exchange', 'symbol')
@classmethod
def ext(self):
return 'mkt'
def path(self):
sector, system, symbol, _ = self.symbol.split('-')
return f'atlas/{sector}/{system[0:1]}/{system}/{symbol}.{self.ext()}'

View File

@ -18,4 +18,4 @@ class System(Base):
def path(self):
sector, symbol = self.symbol.split('-')
return f'atlas/{sector}/{symbol}.{self.ext()}'
return f'atlas/{sector}/{symbol[0:1]}/{symbol}.{self.ext()}'

View File

@ -0,0 +1,30 @@
from .base import Base
from nullptr.util import *
from typing import List
class Waypoint(Base):
x:int = 0
y:int = 0
type:str = 'unknown'
traits:List[str]=[]
faction:str = ''
def update(self, d):
self.seta('x', d)
self.seta('y', d)
self.seta('type', d)
self.seta('faction', d, 'faction.symbol')
if 'traits' in d:
self.traits = [mg(t, 'symbol') for t in d['traits'] ]
@classmethod
def ext(self):
return 'way'
def path(self):
sector, system, symbol = self.symbol.split('-')
return f'atlas/{sector}/{system[0:1]}/{system}/{symbol}.{self.ext()}'
def system(self):
p = self.symbol.split('-')
return f'{p[0]}-{p[1]}'

View File

@ -1,12 +1,12 @@
from models.base import Base
from models.waypoint import Waypoint
from models.sector import Sector
from models.system import System
from models.agent import Agent
from nullptr.models.base import Base
from nullptr.models.waypoint import Waypoint
from nullptr.models.sector import Sector
from nullptr.models.system import System
from nullptr.models.agent import Agent
from os.path import isfile, dirname, isdir
import os
import json
from util import *
from .util import *
class Store:
def __init__(self, data_dir):

View File

@ -1,4 +1,5 @@
from datetime import datetime
from math import ceil
def must_get(d, k):
if type(k) == str:
@ -57,6 +58,12 @@ def trim(s, l):
s += ' ' * (l-len(s))
return s
def total_pages(meta):
total = mg(meta, 'total')
limit = mg(meta, 'limit')
pages = ceil(total / limit)
return pages
# >>> parse_timestamp('2023-06-02T20:34:48.293Z')
# 1685738088
def parse_timestamp(ts):

View File

@ -1,2 +1 @@
requests
sqlalchemy