hypixel-auction-notifier/app/AuctionHandler.worker.ts

179 lines
5.7 KiB
TypeScript
Raw Normal View History

2024-12-27 21:17:59 +01:00
import axios from 'axios';
import { getParsed, getProfit, splitNumber, getRawCraft } from './src/helperFunctions';
import { parentPort, workerData, isMainThread } from 'worker_threads';
2024-12-28 14:05:03 +01:00
import { Item } from './src/Types';
2024-12-27 22:58:39 +01:00
import { AuctionResponse, Auction, Bid } from './src/auctionType';
2024-12-27 21:17:59 +01:00
import { loadConfig } from './src/configLoader';
const config = loadConfig();
if (isMainThread || !parentPort) {
throw new Error('This module can only be run in a Worker thread.');
}
2024-12-27 22:58:39 +01:00
const worker_count: number = config.data.worker_count;
2024-06-05 23:02:29 +02:00
let minProfit = config.data.minSnipeProfit;
let minPercentProfit = config.data.minSnipePP;
2024-12-27 21:17:59 +01:00
let ignoredAuctions: any[] = [];
const promises: Promise<any>[] = [];
2024-06-05 23:02:29 +02:00
console.log(`[Worker ${workerData.workerNumber}] Worker started`);
2022-08-06 19:02:15 +02:00
parentPort.on('message', async (message) => {
console.log(
`[Worker ${workerData.workerNumber}] Received message: ${message.type}`
);
if (message.type === 'pageCount') {
await doTask(message.data);
} else if (message.type === 'moulberry') {
workerData.itemDatas = message.data;
console.log(`[Worker ${workerData.workerNumber}] Updated item data`);
}
2024-06-05 23:02:29 +02:00
});
2022-08-06 19:02:15 +02:00
2024-12-27 22:58:39 +01:00
async function parsePage(i: number) {
console.log(`[Worker ${workerData.workerNumber}] Parsing page ${i}`);
try {
2024-12-27 22:58:39 +01:00
const auctionPage = await axios.get<AuctionResponse>(
`https://api.hypixel.net/skyblock/auctions?page=${i}`
);
for (const auction of auctionPage.data.auctions) {
if (!auction.bin) continue;
const uuid = auction.uuid;
if (
ignoredAuctions.includes(uuid) ||
config.data.ignoreCategories[auction.category]
)
continue;
const item = await getParsed(auction.item_bytes);
const extraAtt = item['i'][0].tag.ExtraAttributes;
const itemID = extraAtt.id;
let startingBid = auction.starting_bid;
const itemData = workerData.itemDatas[itemID];
if (!itemData) continue;
const lbin = itemData.lbin;
const sales = itemData.sales;
const prettyItem = new Item(
item.i[0].tag.display.Name,
uuid,
startingBid,
auction.tier,
extraAtt.enchantments,
extraAtt.hot_potato_count > 10 ? 10 : extraAtt.hot_potato_count,
extraAtt.hot_potato_count > 10 ? extraAtt.hot_potato_count - 10 : 0,
extraAtt.rarity_upgrades === 1,
extraAtt.art_of_war_count === 1,
extraAtt.dungeon_item_level,
extraAtt.gems,
itemID,
auction.category,
0,
0,
lbin,
sales,
auction.item_lore
);
const unstableOrMarketManipulated =
Math.abs((lbin - itemData.cleanPrice) / lbin) >
config.data.maxAvgLbinDiff;
ignoredAuctions.push(uuid);
const rcCost = config.data.includeCraftCost
? getRawCraft(prettyItem, workerData.bazaarData, workerData.itemDatas)
: 0;
const carriedByRC = rcCost >= config.data.rawCraftMaxWeightPP * lbin;
2022-08-06 19:02:15 +02:00
if (
carriedByRC ||
unstableOrMarketManipulated ||
sales <= config.data.minSales ||
!sales
)
continue;
2022-08-06 19:02:15 +02:00
if (
config.filters.itemIDExclusions.find((name) =>
itemID.includes(name)
) === undefined
) {
if (lbin + rcCost - startingBid > minProfit) {
const profitData = getProfit(startingBid, rcCost, lbin);
2024-12-27 21:17:59 +01:00
let auctionType: string | null = null;
if (
rcCost > lbin - startingBid &&
profitData.snipeProfit < minProfit
) {
auctionType = 'VALUE';
} else if (
profitData.snipeProfit >= minProfit &&
rcCost < lbin - startingBid
) {
auctionType = 'SNIPE';
} else if (profitData.snipeProfit >= minProfit && rcCost > 0) {
auctionType = 'BOTH';
}
2022-08-06 19:02:15 +02:00
prettyItem.auctionData.ahType = auctionType;
2022-08-06 19:02:15 +02:00
if (auctionType === 'VALUE' || auctionType === 'BOTH') {
if (
profitData.RCProfit > config.data.minCraftProfit &&
profitData.RCPP > config.data.minCraftPP
) {
prettyItem.auctionData.profit = profitData.RCProfit;
prettyItem.auctionData.percentProfit = profitData.RCPP;
2024-12-27 21:17:59 +01:00
parentPort!.postMessage(prettyItem);
}
} else {
if (
profitData.snipeProfit > minProfit &&
profitData.snipePP > minPercentProfit
) {
prettyItem.auctionData.profit = profitData.snipeProfit;
prettyItem.auctionData.percentProfit = profitData.snipePP;
2024-12-27 21:17:59 +01:00
parentPort!.postMessage(prettyItem);
2022-08-06 19:02:15 +02:00
}
}
2022-08-06 19:02:15 +02:00
}
}
2022-08-06 19:02:15 +02:00
}
} catch (error) {
console.error(
`[Worker ${workerData.workerNumber}] Error parsing page ${i}:`,
error
);
}
2022-08-06 19:02:15 +02:00
}
2024-12-27 22:58:39 +01:00
async function doTask(totalPages: number) {
console.log(
`[Worker ${workerData.workerNumber}] Starting task for ${totalPages} pages`
);
let startingPage = 0;
2024-12-27 22:58:39 +01:00
const pagePerThread = splitNumber(totalPages, worker_count);
2022-08-06 19:02:15 +02:00
if (workerData.workerNumber !== 0 && startingPage === 0) {
const clonedStarting = pagePerThread.slice();
clonedStarting.splice(workerData.workerNumber, 9999);
clonedStarting.forEach((pagePer) => {
startingPage += pagePer;
});
}
2022-08-06 19:02:15 +02:00
2024-12-27 21:17:59 +01:00
let pageToStop = startingPage + pagePerThread[workerData.workerNumber];
2022-08-06 19:02:15 +02:00
if (pageToStop !== totalPages) {
pageToStop -= 1;
}
2022-08-06 19:02:15 +02:00
console.log(
`[Worker ${workerData.workerNumber}] Processing pages from ${startingPage} to ${pageToStop}`
);
2024-06-05 23:02:29 +02:00
for (let i = startingPage; i < pageToStop; i++) {
promises.push(parsePage(i));
}
await Promise.all(promises);
console.log(`[Worker ${workerData.workerNumber}] Finished task`);
2024-12-27 21:17:59 +01:00
parentPort!.postMessage('finished');
2022-08-06 19:02:15 +02:00
}