diff options
author | Julien Dessaux | 2023-05-25 01:20:56 +0200 |
---|---|---|
committer | Julien Dessaux | 2023-05-25 01:20:56 +0200 |
commit | b1157af9cd66878623ad1f9fadac862e4990901c (patch) | |
tree | 3e95713b4ede9d292a2bf00af88f36e7cbe12e0d | |
parent | Rewrote the api rate limiter with promises instead of callbacks (diff) | |
download | spacetraders-b1157af9cd66878623ad1f9fadac862e4990901c.tar.gz spacetraders-b1157af9cd66878623ad1f9fadac862e4990901c.tar.bz2 spacetraders-b1157af9cd66878623ad1f9fadac862e4990901c.zip |
Updated the lib for the new api
-rw-r--r-- | lib/agent.js | 157 | ||||
-rw-r--r-- | lib/api.js | 4 | ||||
-rw-r--r-- | lib/contracts.js | 17 | ||||
-rw-r--r-- | lib/ships.js | 63 | ||||
-rwxr-xr-x | main.js | 79 |
5 files changed, 227 insertions, 93 deletions
diff --git a/lib/agent.js b/lib/agent.js index ca9da0d..69e64a5 100644 --- a/lib/agent.js +++ b/lib/agent.js @@ -1,52 +1,124 @@ import { registerAgent } from '../database/config.js'; import * as api from './api.js'; +import * as contracts from './contracts.js'; import * as ships from './ships.js'; +import * as systems from './systems.js'; -// This starts an extraction loop with a ship which ends when the ship's cargo is at least 90% full with only one desired good -// ctx must must have two attributes: `ship` and `good` -export function extract(ctx, response) { - if (response !== undefined) { - if (response.error !== undefined) { - switch(response.error.code) { - case 4000: // ship is on cooldown - setTimeout(extract, response.error.data.cooldown.remainingSeconds * 1000, ctx); - return; - case 4228: // ship is full. Running the ship inventory function to list the cargo so that know if we need to sell - ships.ship({ship: ctx.ship, next:{action: extract, ship: ctx.ship, good: ctx.good}}); - return; - default: - throw response; - } - } - if (response.data.extraction !== undefined && response.data.extraction.yield !== undefined) { // yield won't be defined if we reached this point from an inventory request - console.log(`${ctx.ship}: extracted ${response.data.extraction.yield.units} of ${response.data.extraction.yield.symbol}`); - } - if (response.data.cargo !== undefined && response.data.cargo.capacity * 0.9 <= response.data.cargo.units) { // > 90% full - const good = response.data.cargo.inventory.filter(i => i.symbol === ctx.good)[0]; - const inventory = response.data.cargo.inventory.filter(i => i.symbol !== ctx.good); - if (good?.units >= response.data.cargo.capacity * 0.9) { // > 90% full - console.log(`ship's cargo is full with ${response.data.cargo.units} of ${ctx.good}!`); - return; - } - let actions = [{ action: ships.dock, ship: ctx.ship }]; - inventory.forEach(i => actions.push({action: ships.sell, ship: ctx.ship, good: i.symbol, units: i.units})); - actions.push({action: ships.orbit, ship: ctx.ship}); - actions.push({action: extract, ship: ctx.ship, good: ctx.good}); - api.chain(actions); - return; - } else { // we need to mine more - if (response.data.cooldown) { // we are on cooldown, call ourselves again in a moment - setTimeout(extract, response.data.cooldown.remainingSeconds * 1000, ctx); - return; - } - } - } - ships.extract({ship: ctx.ship, good: ctx.good, next: { action: extract, ship: ctx.ship, good: ctx.good }}); -} +// This starts a delivery loop with a ship which ends when the delivery is fullfilled +// ctx must must have multiple attributes: `ship`, `contract` (with the contractId), `good`, `destination` (the delivery waypoint), `field` (the asteroid field waypoint). The ship needs to be orbiting the asteroid field. +//export function deliver(ctx, response) { +// let next = {...ctx}; +// next.action = deliver; // calling ourselves after the action is a good default +// if (response !== undefined) { +// if (response.error !== undefined) { +// console.log("ctx:", JSON.stringify(ctx, null, 2)); +// console.log("response:", JSON.stringify(response, null, 2)); +// switch(response.error.code) { +// case 4000: // ship is on cooldown +// setTimeout(deliver, response.error.data.cooldown.remainingSeconds * 1000, ctx); +// return; +// case 4228: // ship cannot extract because it is full. Running the ship inventory function to list the cargo so that we know if we need to sell +// ships.ship({ship: ctx.ship, next: next}); +// return; +// default: // yet unhandled error +// throw response; +// } +// } +// if (response.data.extraction !== undefined && response.data.extraction.yield !== undefined) { // yield won't be defined if we reached this point from an inventory request +// console.log(`${ctx.ship}: extracted ${response.data.extraction.yield.units} of ${response.data.extraction.yield.symbol}`); +// } +// if (response.data.cargo !== undefined && response.data.cargo.capacity * 0.9 <= response.data.cargo.units) { // > 90% full +// const good = response.data.cargo.inventory.filter(i => i.symbol === ctx.good)[0]; +// const inventory = response.data.cargo.inventory.filter(i => i.symbol !== ctx.good); +// if (good?.units >= response.data.cargo.capacity * 0.9) { // > 90% full +// console.log(`ship's cargo is full with ${good.units} of ${ctx.good}!`); +// next.units = good.units; // set the unit property so that we know how much to deliver +// ships.navigate({ship: ctx.ship, waypoint: ctx.destination, next: next}); +// } +// let actions = [{ action: ships.dock, ship: ctx.ship }]; +// inventory.forEach(i => actions.push({action: ships.sell, ship: ctx.ship, good: i.symbol, units: i.units})); +// actions.push({action: ships.orbit, ship: ctx.ship}); +// actions.push({action: deliver, ship: ctx.ship, good: ctx.good}); +// api.chain(actions); +// return; +// } else if (response.data.nav !== undefined) { // we are moving +// const delay = new Date(response.data.nav.route.arrival) - new Date(); +// console.log(new Date(response.data.nav.route.arrival), new Date(), delay); +// if (delay > 0) { // the ship did not arrive yet, we wait +// setTimeout(deliver, delay+1000, ctx, response); +// return; +// } +// if (response.data.nav.route.destination.symbol === ctx.destination) { // we arrived to the delivery point +// api.chain([{ action: ships.dock, ship: ctx.ship }, +// { action: ships.refuel, ship: ctx.ship }, +// { action: ships.deliver, contract: ctx.contract, ship: ctx.ship, good: ctx.good, units: ctx.units }, +// { action: ships.navigate, ship: ctx.ship, waypoint: ctx.field, next: next }]); +// return; +// } else if (next.units !== undefined) { // we arrived to the asteroid field +// delete next.units; // remove the unit property +// api.chain([{ action: ships.dock, ship: ctx.ship }, +// { action: ships.refuel, ship: ctx.ship }, +// { action: ships.orbit, ship: ctx.ship, next: next }]); // TODO we are on cooldown and cannot mine right now +// return; +// } +// } else { // we need to mine more +// if (response.data.cooldown) { // we are on cooldown, call ourselves again in a moment +// setTimeout(deliver, response.data.cooldown.remainingSeconds * 1000, ctx); +// return; +// } +// } +// } +// ships.extract({ship: ctx.ship, good: ctx.good, next: next}); +//} +// +//// This starts an extraction loop with a ship which ends when the ship's cargo is at least 90% full with only one desired good +//// ctx must must have two attributes: `ship` and `good`. The ship needs to be orbiting an asteroid field +//export function extract(ctx, response) { +// if (response !== undefined) { +// if (response.error !== undefined) { +// switch(response.error.code) { +// case 4000: // ship is on cooldown +// setTimeout(extract, response.error.data.cooldown.remainingSeconds * 1000, ctx); +// return; +// case 4228: // ship is full. Running the ship inventory function to list the cargo so that know if we need to sell +// ships.ship({ship: ctx.ship, next:{action: extract, ship: ctx.ship, good: ctx.good}}); +// return; +// default: +// throw response; +// } +// } +// if (response.data.extraction !== undefined && response.data.extraction.yield !== undefined) { // yield won't be defined if we reached this point from an inventory request +// console.log(`${ctx.ship}: extracted ${response.data.extraction.yield.units} of ${response.data.extraction.yield.symbol}`); +// } +// if (response.data.cargo !== undefined && response.data.cargo.capacity * 0.9 <= response.data.cargo.units) { // > 90% full +// const good = response.data.cargo.inventory.filter(i => i.symbol === ctx.good)[0]; +// const inventory = response.data.cargo.inventory.filter(i => i.symbol !== ctx.good); +// if (good?.units >= response.data.cargo.capacity * 0.9) { // > 90% full +// console.log(`ship's cargo is full with ${response.data.cargo.units} of ${ctx.good}!`); +// return; +// } +// let actions = [{ action: ships.dock, ship: ctx.ship }]; +// inventory.forEach(i => actions.push({action: ships.sell, ship: ctx.ship, good: i.symbol, units: i.units})); +// actions.push({action: ships.orbit, ship: ctx.ship}); +// actions.push({action: extract, ship: ctx.ship, good: ctx.good}); +// api.chain(actions); +// return; +// } else { // we need to mine more +// if (response.data.cooldown) { // we are on cooldown, call ourselves again in a moment +// setTimeout(extract, response.data.cooldown.remainingSeconds * 1000, ctx); +// return; +// } +// } +// } +// ships.extract({ship: ctx.ship, good: ctx.good, next: { action: extract, ship: ctx.ship, good: ctx.good }}); +//} // This function inits the database in case we have an already registered game export function init(symbol, faction, token) { registerAgent(symbol, faction, token); + // TODO ships + // TODO contract + // TODO agent } // This function registers then inits the database @@ -67,6 +139,9 @@ export function register(symbol, faction) { .then(response => { console.log(JSON.stringify(response, null, 2)); init(symbol, faction, response.data.token); + // TODO ship + // TODO contract + // TODO agent }) .catch(err => console.error(err)); } @@ -69,3 +69,7 @@ export function debugLog(ctx) { console.log(`--- ${Date()} -----------------------------------------------------------------------------`); console.log(JSON.stringify(ctx, null, 2)); } + +export function sleep(delay) { + return new Promise((resolve) => setTimeout(resolve, delay)) +} diff --git a/lib/contracts.js b/lib/contracts.js new file mode 100644 index 0000000..9494595 --- /dev/null +++ b/lib/contracts.js @@ -0,0 +1,17 @@ +import * as api from './api.js'; + +export async function accept(ctx) { + return await api.send({endpoint: `/my/contracts/${ctx.id}/accept`, method: 'POST'}); +} + +export async function contracts() { + return await api.send({endpoint: '/my/contracts'}); +} + +export async function deliver(ctx) { + return await api.send({ endpoint: `/my/contracts/${ctx.contract}/deliver`, method: 'POST', payload: { + shipSymbol: ctx.ship, + tradeSymbol: ctx.good, + units: ctx.units, + }}); +} diff --git a/lib/ships.js b/lib/ships.js index e536e73..9a57c12 100644 --- a/lib/ships.js +++ b/lib/ships.js @@ -1,35 +1,58 @@ import * as api from './api.js'; -export function extract(ctx) { - console.log(`${ctx.ship}: extracting`); - api.send({endpoint: `/my/ships/${ctx.ship}/extract`, method: 'POST', next: ctx.next}); +export async function extract(ctx) { + const response = await api.send({endpoint: `/my/ships/${ctx.ship}/extract`, method: 'POST'}); + if (response.error !== undefined) { + switch(response.error.code) { + case 4000: // ship is on cooldown + await api.sleep(response.error.data.remainingSeconds * 1000); + return extract(ctx); + case 4228: // ship is full + return null; + default: // yet unhandled error + throw response; + } + } + return response; } -export function dock(ctx) { - console.log(`${ctx.ship}: docking`); - api.send({endpoint: `/my/ships/${ctx.ship}/dock`, method: 'POST', next: ctx.next}); +export async function dock(ctx) { + const response = await api.send({endpoint: `/my/ships/${ctx.ship}/dock`, method: 'POST'}); + if (response.error !== undefined) { + switch(response.error.code) { + case 4214: // ship is in transit + await api.sleep(response.error.data.secondsToArrival * 1000); + return dock(ctx); + default: // yet unhandled error + throw response; + } + } + return response; } -export function navigate(ctx) { - console.log(`${ctx.ship}: navigating to ${ctx.waypoint}`); - api.send({endpoint: `/my/ships/${ctx.ship}/navigate`, method: 'POST', payload: { waypointSymbol: ctx.waypoint }, next: ctx.next}); +export async function navigate(ctx) { + return await api.send({endpoint: `/my/ships/${ctx.ship}/navigate`, method: 'POST', payload: { waypointSymbol: ctx.waypoint }}); } -export function orbit(ctx) { - console.log(`${ctx.ship}: orbiting`); - api.send({endpoint: `/my/ships/${ctx.ship}/orbit`, method: 'POST', next: ctx.next}); +export async function orbit(ctx) { + return await api.send({endpoint: `/my/ships/${ctx.ship}/orbit`, method: 'POST'}); } -export function refuel(ctx) { - console.log(`${ctx.ship}: refueling`); - api.send({endpoint: `/my/ships/${ctx.ship}/refuel`, method: 'POST', next: ctx.next}); +export async function purchase(ctx) { + return await api.send({endpoint: '/my/ships', method: 'POST', payload: { + shipType: ctx.shipType, + waypointSymbol: ctx.waypoint, + }}); } -export function sell(ctx) { - console.log(`${ctx.ship}: selling ${ctx.units} of ${ctx.good}`); - api.send({endpoint: `/my/ships/${ctx.ship}/sell`, method: 'POST', payload: { symbol: ctx.good, units: ctx.units }, next: ctx.next}); +export async function refuel(ctx) { + return await api.send({endpoint: `/my/ships/${ctx.ship}/refuel`, method: 'POST'}); } -export function ship(ctx) { - api.send({endpoint: `/my/ships/${ctx.ship}`, next: ctx.next}); +export async function sell(ctx) { + return await api.send({endpoint: `/my/ships/${ctx.ship}/sell`, method: 'POST', payload: { symbol: ctx.good, units: ctx.units }}); +} + +export async function ship(ctx) { + return await api.send({endpoint: `/my/ships/${ctx.ship}`}); } @@ -1,5 +1,6 @@ import * as agent from './lib/agent.js'; import * as api from './lib/api.js'; +import * as contracts from './lib/contracts.js'; import * as ships from './lib/ships.js'; import * as systems from './lib/systems.js'; @@ -13,16 +14,24 @@ ships\t\t\tRetrieve all of your ships.`); } switch(process.argv[2]) { -case 'contracts': - api.send({ endpoint: '/my/contracts'}); - break; -case 'extract': - if (process.argv[3] !== undefined && process.argv[4] !== undefined) { - agent.extract({ship: process.argv[3], good: process.argv[4]}); - } else { - usage(); - } break; +//case 'deliver': +// agent.deliver({ +// contract: process.argv[3], +// ship: process.argv[4], +// good: process.argv[5], +// destination: process.argv[6], +// field: process.argv[7], +// //units: process.argv[8], +// }); +// break; +//case 'extract': +// if (process.argv[3] !== undefined && process.argv[4] !== undefined) { +// agent.extract({ship: process.argv[3], good: process.argv[4]}); +// } else { +// usage(); +// } +// break; case 'init': if (process.argv[3] !== undefined && process.argv[4] !== undefined && process.argv[5] !== undefined) { agent.init(process.argv[3], process.argv[4], process.argv[5]); @@ -31,7 +40,7 @@ case 'init': } break; case 'my-agent': - api.send({endpoint: '/my/agent'}); + api.debugLog(await api.send({endpoint: '/my/agent'})); break; case 'register': if (process.argv[3] !== undefined && process.argv[4] !== undefined) { @@ -41,42 +50,48 @@ case 'register': } break; case 'ships': - api.send({endpoint: '/my/ships'}); + api.debugLog(await api.send({endpoint: '/my/ships'})); break; default: // wip and manual actions switch(process.argv[2]) { - case 'contract-accept': - api.send({endpoint: `/my/contracts/${process.argv[3]}/accept`, method: 'POST'}); + case 'contracts.contracts': + api.debugLog(await contracts.contracts()); + break; + case 'contracts.accept': + api.debugLog(await contracts.accept({id: process.argv[3]})); + break; + case 'ships.dock': + api.debugLog(await ships.dock({ship: process.argv[3]})); break; - case 'dock': - ships.dock({ship: process.argv[3]}); + case 'ships.extract': + api.debugLog(await ships.extract({ship: process.argv[3]})); break; - case 'market': - api.send({endpoint: `/systems/${process.argv[3]}/waypoints/${process.argv[4]}/market`}); + //case 'market': + // api.send({endpoint: `/systems/${process.argv[3]}/waypoints/${process.argv[4]}/market`}); + // break; + case 'ships.navigate': + api.debugLog(await ships.navigate({ship: process.argv[3], waypoint: process.argv[4]})); break; - case 'navigate': - ships.navigate({ship: process.argv[3], waypoint: process.argv[4]}); + case 'ships.orbit': + api.debugLog(await ships.orbit({ship: process.argv[3]})); break; - case 'orbit': - ships.orbit({ship: process.argv[3]}); + case 'ships.purchase': + api.debugLog(await ships.purchase({shipType: process.argv[3], waypoint: process.argv[4]})); break; - case 'purchase': - api.send({endpoint: '/my/ships', method: 'POST', payload: { - shipType: 'SHIP_MINING_DRONE', - waypointSymbol: process.argv[3], - }}); + case 'ships.refuel': + api.debugLog(await ships.refuel({ship: process.argv[3]})); break; - case 'refuel': - ships.refuel({ship: process.argv[3]}); + case 'ships.sell': + api.debugLog(await ships.sell({ship: process.argv[3], good: process.argv[4], units: process.argv[5]})); break; - case 'sell': - ships.sell({ship: process.argv[3], good: process.argv[4], units: process.argv[5]}); + case 'ships.ship': + api.debugLog(await ships.ship({ship: process.argv[3]})); break; - case 'asteroids': + case 'systems.asteroids': api.debugLog(await systems.type({symbol: process.argv[3], type: 'ASTEROID_FIELD'})); break; - case 'shipyards': + case 'systems.shipyards': api.debugLog(await systems.trait({symbol: process.argv[3], trait: 'SHIPYARD'})); break; default: |