junk.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import {cachedFetchJSON} from './cache';
  2. const username = document.querySelector('#username') as HTMLInputElement;
  3. const apiKey = document.querySelector('#api-key') as HTMLInputElement;
  4. const cxSelect = document.querySelector('#cx') as HTMLSelectElement;
  5. {
  6. const storedUsername = localStorage.getItem('fio-username');
  7. if (storedUsername)
  8. username.value = storedUsername;
  9. const storedApiKey = localStorage.getItem('fio-api-key');
  10. if (storedApiKey)
  11. apiKey.value = storedApiKey;
  12. }
  13. document.querySelector('#fetch')!.addEventListener('click', async () => {
  14. const loader = document.querySelector('#loader') as HTMLElement;
  15. loader.style.display = 'block';
  16. try {
  17. await calculate(username.value, apiKey.value, cxSelect.value);
  18. localStorage.setItem('fio-username', username.value);
  19. localStorage.setItem('fio-api-key', apiKey.value);
  20. } catch (e) {
  21. console.error(e);
  22. (document.querySelector('#junk') as HTMLElement).innerText = e instanceof Error ? e.message : String(e);
  23. }
  24. loader.style.display = 'none';
  25. });
  26. const format = new Intl.NumberFormat(undefined, {maximumFractionDigits: 2}).format;
  27. async function calculate(username: string, apiKey: string, cx: string): Promise<void> {
  28. const renderTarget = document.querySelector('#junk')!;
  29. renderTarget.innerHTML = '';
  30. const fioBurns: FIOBurn[] = await cachedFetchJSON('https://rest.fnar.net/fioweb/burn/user/' + username,
  31. {headers: {'Authorization': apiKey}});
  32. const totalConsumption = new Map<string, number>();
  33. for (const fioBurn of fioBurns) {
  34. const netConsumption = new Map<string, number>();
  35. for (const item of fioBurn.OrderProduction)
  36. netConsumption.set(item.MaterialTicker, -item.DailyAmount);
  37. for (const item of [...fioBurn.OrderConsumption, ...fioBurn.WorkforceConsumption])
  38. netConsumption.set(item.MaterialTicker, (netConsumption.get(item.MaterialTicker) ?? 0) + item.DailyAmount);
  39. for (const [ticker, consumption] of netConsumption)
  40. if (consumption > 0)
  41. totalConsumption.set(ticker, (totalConsumption.get(ticker) ?? 0) + consumption);
  42. }
  43. const warehouse = await warehouseInventory(username, apiKey, cx);
  44. const supplies = [...warehouse.entries()].map(([ticker, amount]) => {
  45. const consumption = totalConsumption.get(ticker);
  46. return {
  47. ticker,
  48. amount,
  49. days: consumption === undefined || consumption <= 0 ? Number.POSITIVE_INFINITY : amount / consumption,
  50. consumption: consumption ?? 0,
  51. };
  52. });
  53. supplies.sort((a, b) => b.days - a.days);
  54. const h2 = document.createElement('h2');
  55. h2.textContent = 'warehouse supply';
  56. renderTarget.appendChild(h2);
  57. const table = document.createElement('table');
  58. table.innerHTML = `
  59. <thead>
  60. <tr>
  61. <th>mat</th>
  62. <th>have</th>
  63. <th>consumption/day</th>
  64. <th>supply</th>
  65. </tr>
  66. </thead>`;
  67. const tbody = document.createElement('tbody');
  68. for (const supply of supplies) {
  69. const tr = document.createElement('tr');
  70. tr.innerHTML = `
  71. <td>${supply.ticker}</td>
  72. <td>${format(supply.amount)}</td>
  73. <td>${format(supply.consumption)}</td>
  74. <td>${Number.isFinite(supply.days) ? format(supply.days) + ' d' : '∞'}</td>
  75. `;
  76. tbody.appendChild(tr);
  77. }
  78. table.appendChild(tbody);
  79. renderTarget.appendChild(table);
  80. }
  81. async function warehouseInventory(username: string, apiKey: string, cx: string): Promise<Map<string, number>> {
  82. const warehouses: Warehouse[] = await cachedFetchJSON('https://rest.fnar.net/sites/warehouses/' + username,
  83. {headers: {'Authorization': apiKey}});
  84. const inventory = new Map<string, number>();
  85. for (const warehouse of warehouses)
  86. if (warehouse.LocationNaturalId === cx) {
  87. const storage: Storage = await cachedFetchJSON(`https://rest.fnar.net/storage/${username}/${warehouse.StoreId}`,
  88. {headers: {'Authorization': apiKey}});
  89. for (const item of storage.StorageItems)
  90. inventory.set(item.MaterialTicker, item.MaterialAmount);
  91. break;
  92. }
  93. return inventory;
  94. }
  95. interface StorageItem {
  96. MaterialTicker: string;
  97. MaterialAmount: number;
  98. }
  99. interface Storage {
  100. Name: string;
  101. StorageItems: StorageItem[];
  102. WeightLoad: number;
  103. VolumeLoad: number;
  104. Type: 'STORE' | 'WAREHOUSE_STORE' | 'FTL_FUEL_STORE' | 'STL_FUEL_STORE' | 'SHIP_STORE';
  105. }
  106. interface Warehouse {
  107. StoreId: string;
  108. LocationNaturalId: string;
  109. }
  110. interface Amount {
  111. MaterialTicker: string;
  112. DailyAmount: number;
  113. }
  114. interface FIOBurn {
  115. PlanetId: string;
  116. PlanetName: string;
  117. PlanetNaturalId: string;
  118. Error: any;
  119. OrderConsumption: Amount[];
  120. WorkforceConsumption: Amount[];
  121. Inventory: StorageItem[];
  122. OrderProduction: Amount[];
  123. }