268 lines
9.3 KiB
TypeScript
268 lines
9.3 KiB
TypeScript
import { APIRoute } from "astro";
|
|
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
|
import { getUserByAccessToken } from "../../../lib/db/users";
|
|
import { ObjectId } from "mongodb";
|
|
import locationManager from "../../../lib/classes/managers/LocationManager";
|
|
import { getAllShips } from "../../../lib/db/ships";
|
|
import DBShip from "../../../types/db/DBShip";
|
|
import { Planet } from "../../../lib/classes/managers/PlanetManager";
|
|
import MissionType from "../../../types/MissionType";
|
|
import { getAllResources } from "../../../lib/db/resources";
|
|
import FleetManager from "../../../lib/classes/managers/FleetManager";
|
|
|
|
export const POST: APIRoute = async({ request }) => {
|
|
const response = await validateAccessToken(request);
|
|
if(response instanceof Response) return response;
|
|
|
|
const userDB = await getUserByAccessToken(response);
|
|
if(userDB === null) {
|
|
return new Response(
|
|
JSON.stringify({
|
|
code: 401,
|
|
message: "Unauthorized"
|
|
}), { status: 401 }
|
|
)
|
|
}
|
|
|
|
const user = locationManager.getUser(userDB._id);
|
|
if(!user) {
|
|
return new Response(
|
|
JSON.stringify({
|
|
code: 401,
|
|
message: "Unauthorized"
|
|
}), { status: 401 }
|
|
)
|
|
}
|
|
|
|
let body: { source: string, destination: string, ships: Array<{ id: string, amount: number }>, cargo: Array<{ id: string, amount: number }>, mission: MissionType };
|
|
try {
|
|
body = await request.json()
|
|
} catch(e) {
|
|
return new Response(
|
|
JSON.stringify({
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Invalid JSON body"
|
|
}), { status: 400 }
|
|
)
|
|
}
|
|
|
|
const checkSource = checkPlanetId(body.source, 'source');
|
|
if(typeof checkSource.error !== "undefined") return new Response(JSON.stringify(checkSource), { status: checkSource.code });
|
|
|
|
const checkDestination = checkPlanetId(body.destination, 'destination');
|
|
if(typeof checkDestination.error !== "undefined") return new Response(JSON.stringify(checkDestination), { status: checkDestination.code });
|
|
|
|
const source = checkSource.planet;
|
|
const destination = checkDestination.planet;
|
|
|
|
const shipsDB = await getAllShips();
|
|
|
|
const checkShipsBody = checkShips(body.ships, shipsDB, source);
|
|
if(typeof checkShipsBody.error !== "undefined") return new Response(JSON.stringify(checkShipsBody), { status: checkShipsBody.code });
|
|
|
|
const resourcesDB = await getAllResources();
|
|
await source.resources.calculateCurrentAvailableResources();
|
|
|
|
const checkCargoBody = checkCargo(body.cargo, body.ships, source, body.mission);
|
|
if(typeof checkCargoBody.error !== "undefined") return new Response(JSON.stringify(checkCargoBody), { status: checkCargoBody.code });
|
|
|
|
const fleetManager = new FleetManager(
|
|
new ObjectId(),
|
|
source,
|
|
destination,
|
|
new Date(),
|
|
new Date(Date.now() + 1000 * 30), //TODO: calculate time based on distance
|
|
false,
|
|
body.mission,
|
|
body.ships,
|
|
body.cargo
|
|
);
|
|
|
|
const resourceDiff = await source.resources.getDifference(body.cargo.map(c => ({ id: c.id, amount: c.amount })));
|
|
|
|
for(const res of resourceDiff) {
|
|
if(res.amount < 0) {
|
|
return new Response(
|
|
JSON.stringify({
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Not enough resource with ID '" + res.id + "' on source planet"
|
|
}), { status: 400 }
|
|
)
|
|
}
|
|
}
|
|
|
|
source.resources.setAmount(resourceDiff);
|
|
await source.resources.sync();
|
|
|
|
for(const ship of body.ships) {
|
|
source.ships.removeShips(ship.id, ship.amount);
|
|
}
|
|
await source.ships.sync();
|
|
await fleetManager.sync();
|
|
|
|
locationManager.addFleet(fleetManager);
|
|
|
|
return new Response(
|
|
JSON.stringify({
|
|
code: 200,
|
|
message: "OK"
|
|
}), { status: 200 }
|
|
)
|
|
}
|
|
|
|
function checkPlanetId(id: string, type: string) {
|
|
if(typeof ObjectId === "undefined") return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: `Missing '${type}' in body`
|
|
}
|
|
|
|
let idToCheck;
|
|
try {
|
|
idToCheck = new ObjectId(id);
|
|
} catch(e) {
|
|
return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: `Invalid ID in '${type}'`
|
|
}
|
|
}
|
|
|
|
const planet = locationManager.getPlanet(idToCheck);
|
|
|
|
if(!planet) return {
|
|
code: 404,
|
|
message: "Not Found",
|
|
error: `Non-existent planet provided in '${type}'`
|
|
}
|
|
|
|
return {
|
|
code: 200,
|
|
message: "OK",
|
|
planet
|
|
}
|
|
}
|
|
|
|
function checkShips(ships: Array<{ id: string, amount: number }>, shipsDB: Array<DBShip>, sourcePlanet: Planet) {
|
|
if(typeof ships === "undefined") return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Missing 'ships' in body"
|
|
}
|
|
|
|
for(let i = 0; i < ships.length; i++) {
|
|
if(typeof ships[i].id === "undefined" || ships[i].id === "") return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Missing ship ID at position " + i
|
|
}
|
|
|
|
if(!shipsDB.find(ship => ship.id === ships[i].id)) return {
|
|
code: 404,
|
|
message: "Not Found",
|
|
error: "Non-existent ship ID '" + ships[i].id + "' at position " + i
|
|
}
|
|
|
|
if(typeof ships[i].amount === "undefined") return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Missing ship amount for ID '" + ships[i].id + "' at position " + i
|
|
}
|
|
|
|
if(ships[i].amount % 1 !== 0 || ships[i].amount < 0) return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Ship amount for ID '" + ships[i].id + "' is not a non-negative integer at position " + i
|
|
}
|
|
|
|
if(ships[i].amount > (sourcePlanet.ships.getShipById(ships[i].id)?.amount ?? 0)) return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Not enough ships on planet with ID '" + ships[i].id + "' at position " + i
|
|
}
|
|
}
|
|
|
|
return {
|
|
code: 200,
|
|
message: "OK"
|
|
}
|
|
}
|
|
|
|
function checkCargo(cargo: Array<{ id: string, amount: number }>, ships: Array<{ id: string, amount: number }>, planet: Planet, missionType: MissionType) {
|
|
if(missionType === "TRANSPORT" && cargo.length === 0) return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Missing 'cargo' in body for requested mission 'TRANSPORT'"
|
|
}
|
|
|
|
for(let i = 0; i < cargo.length; i++) {
|
|
if(typeof cargo[i].id === "undefined") return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Missing resource ID at position " + i
|
|
}
|
|
|
|
if(!planet.resources.resourcesDB.find(resource => resource.id === cargo[i].id)) return {
|
|
code: 404,
|
|
message: "Not Found",
|
|
error: "Non-existent resource ID '" + cargo[i].id + "' at position " + i
|
|
}
|
|
|
|
if(typeof cargo[i].amount === "undefined") return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Missing resource amount for ID '" + cargo[i].id + "' at position " + i
|
|
}
|
|
|
|
if(cargo[i].amount % 1 !== 0 || cargo[i].amount < 0) return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Resource amount for ID '" + cargo[i].id + "' is not a non-negative integer at position " + i
|
|
}
|
|
|
|
if(cargo[i].amount > (planet.resources.resources.find(res => res.id === cargo[i].id)?.amount ?? 0)) return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Not enough resources on planet with ID '" + cargo[i].id + "' at position " + i
|
|
}
|
|
}
|
|
|
|
const totalCargoAvailable = {
|
|
solid: ships.reduce((acc, ship) => acc + (planet.ships.shipsDB.find(s => s.id === ship.id)?.capacity.solid ?? 0) * ship.amount, 0),
|
|
liquid: ships.reduce((acc, ship) => acc + (planet.ships.shipsDB.find(s => s.id === ship.id)?.capacity.liquid ?? 0) * ship.amount, 0),
|
|
gas: ships.reduce((acc, ship) => acc + (planet.ships.shipsDB.find(s => s.id === ship.id)?.capacity.gas ?? 0) * ship.amount, 0)
|
|
}
|
|
|
|
const totalCargoUsed = {
|
|
solid: cargo.reduce((acc, resource) => planet.resources.resourcesDB.find(res => res.id === resource.id)?.type === "solid" ? acc + resource.amount : acc, 0),
|
|
liquid: cargo.reduce((acc, resource) => planet.resources.resourcesDB.find(res => res.id === resource.id)?.type === "liquid" ? acc + resource.amount : acc, 0),
|
|
gas: cargo.reduce((acc, resource) => planet.resources.resourcesDB.find(res => res.id === resource.id)?.type === "gas" ? acc + resource.amount : acc, 0)
|
|
}
|
|
|
|
if(totalCargoUsed.solid > totalCargoAvailable.solid) return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Not enough solid cargo capacity on ships"
|
|
}
|
|
|
|
if(totalCargoUsed.liquid > totalCargoAvailable.liquid) return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Not enough liquid cargo capacity on ships"
|
|
}
|
|
|
|
if(totalCargoUsed.gas > totalCargoAvailable.gas) return {
|
|
code: 400,
|
|
message: "Bad Request",
|
|
error: "Not enough gas cargo capacity on ships"
|
|
}
|
|
|
|
//TODO: check for fuel
|
|
|
|
return {
|
|
code: 200,
|
|
message: "OK"
|
|
}
|
|
} |