planet_bases.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. from __future__ import annotations
  2. import collections
  3. import concurrent.futures
  4. import sys
  5. import typing
  6. import tap
  7. import cache
  8. class Args(tap.Tap):
  9. planets: list[str] = []
  10. sector: tuple[str, ...] = ()
  11. def configure(self) -> None:
  12. self.add_argument('planets', nargs='*', metavar='planet') # take planets as positional args instead of flag
  13. def main() -> None:
  14. args = Args().parse_args()
  15. if args.sector:
  16. sectors = []
  17. all_sector_ids, sector_systems = get_sectors()
  18. for sector in args.sector:
  19. if len(sector) == 2:
  20. if len(sector_ids := all_sector_ids[sector]) > 1:
  21. print(sector, 'has multiple sector ids')
  22. for sector_id in sector_ids:
  23. print(f'\t{sector_id}:', ', '.join(system['Name'] for system in sector_systems[sector_id]))
  24. return
  25. else:
  26. (sector_id,) = sector_ids
  27. sectors.append(sector_id)
  28. elif sector.startswith('sector-'):
  29. sectors.append(sector)
  30. else:
  31. sys.exit(f'invalid sector: {sector}')
  32. system_ids = set()
  33. for sector_id in sectors:
  34. system_ids.update(system['SystemId'] for system in sector_systems[sector_id])
  35. all_planets: typing.Sequence[Planet] = cache.get('https://rest.fnar.net/planet/allplanets/full')
  36. for planet in all_planets:
  37. if planet['SystemId'] in system_ids:
  38. args.planets.append(planet['PlanetName'])
  39. with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
  40. for planet, bases in zip(args.planets, executor.map(get_bases, args.planets)):
  41. print(planet)
  42. companies = executor.map(get_company, (base['OwnerCode'] for base in bases if base['OwnerCode'] is not None))
  43. for co in sorted(companies, key=lambda co: co['CorporationCode'] or '\uffff'):
  44. print('\t', end='')
  45. if co['CorporationCode'] is not None:
  46. print(f'[{co["CorporationCode"]}]', end=' ')
  47. print(f'{co["UserName"]}\t{co["CompanyCode"]}\t{co["CompanyName"]}')
  48. def get_sectors() -> tuple[typing.Mapping[str, typing.Collection[str]], typing.Mapping[str, typing.Sequence[System]]]:
  49. systems: typing.Sequence[System] = cache.get('https://rest.fnar.net/systemstars')
  50. sector_ids = collections.defaultdict(set)
  51. sector_systems = collections.defaultdict(list)
  52. for system in systems:
  53. sector_name = system['NaturalId'][:2]
  54. sector_ids[sector_name].add(system['SectorId'])
  55. sector_systems[system['SectorId']].append(system)
  56. return sector_ids, sector_systems
  57. def get_bases(planet: str) -> typing.Sequence[Site]:
  58. return cache.get('https://rest.fnar.net/planet/sites/' + planet, expiry=cache.ONE_DAY)
  59. def get_company(code: str) -> typing.Mapping[str, typing.Any]:
  60. try:
  61. return cache.get('https://rest.fnar.net/company/code/' + code, expiry=cache.ONE_DAY)
  62. except cache.NoContent:
  63. return {'CorporationCode': None, 'CompanyCode': code, 'CompanyName': None, 'UserName': None}
  64. class System(typing.TypedDict):
  65. SystemId: str
  66. NaturalId: str
  67. Name: str
  68. SectorId: str
  69. class Planet(typing.TypedDict):
  70. PlanetNaturalId: str
  71. PlanetName: str
  72. SystemId: str
  73. class Site(typing.TypedDict):
  74. OwnerId: str
  75. OwnerName: str
  76. OwnerCode: str | None
  77. class Company(typing.TypedDict):
  78. UserName: str
  79. CompanyCode: str
  80. CompanyName: str
  81. CorporationCode: str
  82. if __name__ == '__main__':
  83. main()