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"
 | |
|     }
 | |
| } |