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 ADD --chown=user . /app
RUN chmod +x /app/commander.py RUN chmod +x /app/commander.py
VOLUME /data VOLUME /data
ENTRYPOINT [ "/app/commander.py"] ENTRYPOINT [ "/app/main.py"]
CMD ["-s", "/data/store.db"] 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 import requests
from models.system import System from nullptr.models.system import System
from util import * from nullptr.models.waypoint import Waypoint
from nullptr.models.marketplace import Marketplace
from .util import *
class ApiError(Exception): class ApiError(Exception):
def __init__(self, msg, code): def __init__(self, msg, code):
@ -11,6 +13,7 @@ class Api:
def __init__(self, store, agent): def __init__(self, store, agent):
self.agent = agent self.agent = agent
self.store = store self.store = store
self.meta = None
self.root = 'https://api.spacetraders.io/v2/' self.root = 'https://api.spacetraders.io/v2/'
def token(self): def token(self):
@ -30,7 +33,9 @@ class Api:
self.last_result = result self.last_result = result
if result is None: if result is None:
raise ApiError('http call failed', r.status_code) 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) error_code = sg(result, 'error.code', -1)
self.last_error = error_code self.last_error = error_code
error_message = sg(result, 'error.message') error_message = sg(result, 'error.message')
@ -56,6 +61,16 @@ class Api:
def list_systems(self, page=1): def list_systems(self, page=1):
data = self.request('get', 'systems', params={'page': page}) data = self.request('get', 'systems', params={'page': page})
#pprint(self.last_meta)
return self.store.update_list(System, data) 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}') 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))=='ApiError') logging.error(e, exc_info=str(type(e))=='ApiErrorp')
def handle_empty(self): def handle_empty(self):
pass 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 copy import deepcopy
from dataclasses import dataclass from dataclasses import dataclass
from util import sg from nullptr.util import sg
@dataclass @dataclass
class Base: class Base:
symbol: str symbol: str
@ -18,6 +18,12 @@ class Base:
if val is not None: if val is not None:
setattr(self, attr, val) 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): def __setattr__(self, name, value):
if name != 'dirty': if name != 'dirty':
self.dirty = True 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): def path(self):
sector, symbol = self.symbol.split('-') 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 nullptr.models.base import Base
from models.waypoint import Waypoint from nullptr.models.waypoint import Waypoint
from models.sector import Sector from nullptr.models.sector import Sector
from models.system import System from nullptr.models.system import System
from models.agent import Agent from nullptr.models.agent import Agent
from os.path import isfile, dirname, isdir from os.path import isfile, dirname, isdir
import os import os
import json import json
from util import * from .util import *
class Store: class Store:
def __init__(self, data_dir): def __init__(self, data_dir):

View File

@ -1,4 +1,5 @@
from datetime import datetime from datetime import datetime
from math import ceil
def must_get(d, k): def must_get(d, k):
if type(k) == str: if type(k) == str:
@ -57,6 +58,12 @@ def trim(s, l):
s += ' ' * (l-len(s)) s += ' ' * (l-len(s))
return 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') # >>> parse_timestamp('2023-06-02T20:34:48.293Z')
# 1685738088 # 1685738088
def parse_timestamp(ts): def parse_timestamp(ts):

View File

@ -1,2 +1 @@
requests requests
sqlalchemy