Skip to content

Commit

Permalink
#minor updated API sources, integrated fly.io deployment, various com…
Browse files Browse the repository at this point in the history
…mand cleanup

- updated deployment to use fly.io instead of k8s
- no longer calling official AHG APIs, replaced with chats' and dealloc's APIs
- increased API interval to 20s
- removed `/planet list` with `/summary`
- added button links to status persistent message (and `/summary`)
- added various stats to `/campaign` and `/planet` commands
- fixed planetary images from helldiverscompanion
  • Loading branch information
jgaribsin committed Apr 23, 2024
1 parent 8c928c5 commit 666275d
Show file tree
Hide file tree
Showing 18 changed files with 394 additions and 318 deletions.
19 changes: 19 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# flyctl launch added from .gitignore
node_modules
api_responses
.history
build
**\.env*
**\foo*
**\newrelic_agent.log
**\data.json
**\strippedData.json
**\differences.json

# flyctl launch added from .idea\.gitignore
# Default ignored files
.idea\shelf
.idea\workspace.xml
# Editor-based HTTP Client requests
.idea\httpRequests
fly.toml
13 changes: 9 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,12 @@ jobs:
with:
fetch-depth: 0

- uses: steebchen/[email protected]
with:
config: ${{ secrets.KUBECONFIG }}
command: rollout restart deployment/helldivers2-bot-deployment -n=helldivers2
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

# - uses: steebchen/[email protected]
# with:
# config: ${{ secrets.KUBECONFIG }}
# command: rollout restart deployment/helldivers2-bot-deployment -n=helldivers2
9 changes: 9 additions & 0 deletions fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
app = 'hellcom'
primary_region = 'sea'

[build]
image = 'ghcr.io/helldivers-2/discord-bot:latest'

[[vm]]
size = 'shared-cpu-1x'
memory = '256mb'
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@types/newrelic": "^9.14.3",
"@types/node": "^20.8.2",
"@types/node-cron": "^3.0.11",
"drizzle-kit": "^0.20.16",
"drizzle-kit": "^0.20.17",
"gts": "^5.2.0",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
Expand Down
156 changes: 64 additions & 92 deletions src/api-wrapper/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,28 @@ import {
Assignment,
NewsFeedItem,
PlanetStats,
PlanetStatsItem,
StoreRotation,
AdditionalPlanetInfo,
} from './types';
import {getFactionName, getPlanetEventType, getPlanetName} from './mapping';
import {writeFileSync} from 'fs';
import {getAllPlanets} from './planets';
import axios, {AxiosRequestConfig} from 'axios';
import axios from 'axios';
import {config} from '../config';
import {logger} from '../handlers';

const API_URL = 'https://api.live.prod.thehelldiversgame.com/api';
// const API_URL = 'https://api.live.prod.thehelldiversgame.com/api';
const CHATS_URL = 'https://api.diveharder.com/v1/all';
const CHATS_URL_RAW = 'https://api.diveharder.com/raw/all';
const FALLBACK_URL = 'https://helldivers-2-dotnet.fly.dev/raw/api';
const {IDENTIFIER} = config;

export const seasons = {
current: 801,
seasons: [801, 805],
};
const apiClient = axios.create({
headers: {
'Accept-Language': 'en-us',
'User-Agent': IDENTIFIER,
},
});

// create an empty object to store the data
export let data: ApiData = {
Expand Down Expand Up @@ -56,6 +61,7 @@ export let data: ApiData = {
superEarthWarResults: [],
},
Planets: [],
additionalPlanetInfo: {},
Campaigns: [],
PlanetEvents: [],
ActivePlanets: [],
Expand Down Expand Up @@ -91,96 +97,63 @@ export let data: ApiData = {
},
};

const axiosOpts: AxiosRequestConfig = {
headers: {
'Accept-Language': 'en-us',
'User-Agent': 'HellComBot/1.0',
},
};

export async function getData() {
const season = seasons.current;
// https://api.live.prod.thehelldiversgame.com/api/WarSeason/801/Status
// https://api.live.prod.thehelldiversgame.com/api/WarSeason/801/WarInfo
// https://api.live.prod.thehelldiversgame.com/api/NewsFeed/801
// https://api.live.prod.thehelldiversgame.com/api/v2/Assignment/War/801
const warInfoApi = await (
await axios.get(`${API_URL}/WarSeason/${season}/WarInfo`, axiosOpts)
).data;
const warInfo = warInfoApi as WarInfo;

const statusApi = await (
await axios.get(`${API_URL}/WarSeason/${season}/Status`, axiosOpts)
).data;
const status = statusApi as Status;
status.timeUtc = Date.now();

const assignmentApi = await (
await axios.get(`${API_URL}/v2/Assignment/War/${season}`, axiosOpts)
).data;
const assignment = assignmentApi as Assignment[];
let chatsAPI;

// Unofficial: api wrapper for the authed planetStats endpoint
// https://api.diveharder.com/raw/planetStats
const statsApi = await (
await axios.get(`${API_URL}/Stats/War/${season}/Summary`, axiosOpts)
).data;
const planetStats = statsApi as PlanetStats;
let warInfo: WarInfo;
let status: Status;
let UTCOffset: number;
let assignment: Assignment[];
let planetStats: PlanetStats;
let newsFeed: NewsFeedItem[];
let storeRotation: StoreRotation | undefined = undefined;
let additionalPlanetInfo: AdditionalPlanetInfo | undefined = undefined;

let chatsAPI;
try {
// Unofficial: api wrapper for the authed chats endpoint
chatsAPI = await (
await axios.get(CHATS_URL, {...axiosOpts, timeout: 10_000})
).data;
chatsAPI = await (await apiClient.get(CHATS_URL)).data;
} catch (err) {
logger.error('Failed to fetch chats data.', {
type: 'API',
...(err as Error),
});
}

// let planetStats: PlanetStats = data.PlanetStats;
// if (getDataCounter % 2 === 0) {
// const planetStatsApi = await (
// await axios.get('https://api.diveharder.com/raw/planetStats', {
// ...axiosOpts,
// params: {
// source: IDENTIFIER,
// },
// })
// ).data;

// planetStats = {
// galaxy_stats: stats.galaxy_stats,
// planets_stats: stats.planets_stats.map(
// (p: Omit<PlanetStatsItem, 'planetName'>) => ({
// ...p,
// planetName: getPlanetName(p.planetIndex),
// })
// ),
// };
// }

//https://api.live.prod.thehelldiversgame.com/api/NewsFeed/801
// fetch the earliest possible news, then using the latest timestamp, fetch more news until it returns empty
const newsFeed: NewsFeedItem[] = [];
const newsFeedApi = await (
await axios.get(`${API_URL}/NewsFeed/${season}`, {
...axiosOpts,
params: {
maxEntries: 512,
},
})
).data;

newsFeed.push(
...(newsFeedApi.map((item: Omit<NewsFeedItem, 'publishedUtc'>) => ({
if (chatsAPI) {
warInfo = chatsAPI['war_info'] as WarInfo;
status = chatsAPI['status'] as Status;
status.timeUtc = Date.now();
UTCOffset = Math.floor(status.timeUtc - status.time * 1000); // use this value to add to the time to get the UTC time in seconds
assignment = chatsAPI['major_order'] as Assignment[];
planetStats = chatsAPI['planet_stats'] as PlanetStats;
newsFeed = chatsAPI['news_feed'].map(
(item: Omit<NewsFeedItem, 'publishedUtc'>) => ({
...item,
publishedUtc: UTCOffset + item.published * 1000,
})
) as NewsFeedItem[];
newsFeed.sort((a, b) => b.published - a.published);
storeRotation = chatsAPI['store_rotation'] as StoreRotation;
additionalPlanetInfo = chatsAPI['planets'] as AdditionalPlanetInfo;
} else {
logger.warn('Fallback to dealloc APIs', {type: 'API'});
// create a fallback API client
apiClient.defaults.baseURL = FALLBACK_URL;
const {id} = await (await apiClient.get('/WarSeason/current/WarID')).data;
warInfo = await (await apiClient.get(`/WarSeason/${id}/WarInfo`)).data;
status = await (await apiClient.get(`/WarSeason/${id}/Status`)).data;
status.timeUtc = Date.now();
UTCOffset = Math.floor(status.timeUtc - status.time * 1000); // use this value to add to the time to get the UTC time in seconds
assignment = await (await apiClient.get(`/v2/Assignment/War/${id}`)).data;
planetStats = await (await apiClient.get(`/Stats/War/${id}/Summary`)).data;
newsFeed = (await (
await apiClient.get(`/NewsFeed/${id}`)
).data.map((item: Omit<NewsFeedItem, 'publishedUtc'>) => ({
...item,
publishedUtc: data.UTCOffset + item.published * 1000,
})) as NewsFeedItem[])
);
newsFeed.sort((a, b) => b.published - a.published);
publishedUtc: UTCOffset + item.published * 1000,
}))) as NewsFeedItem[];
newsFeed.sort((a, b) => b.published - a.published);
}

const planets: MergedPlanetData[] = [];
const players = {
Expand Down Expand Up @@ -216,6 +189,9 @@ export async function getData() {
...planetStatus,
initialOwner: initialOwner,
owner: owner,
sectorName: additionalPlanetInfo?.[index]?.sector,
biome: additionalPlanetInfo?.[index]?.biome,
environmentals: additionalPlanetInfo?.[index]?.environmentals,
});
}
}
Expand Down Expand Up @@ -251,6 +227,7 @@ export async function getData() {
NewsFeed: newsFeed,
PlanetStats: planetStats,
Planets: planets,
// additionalPlanetInfo: additionalPlanetInfo,
Campaigns: campaigns,
PlanetEvents: planetEvents,
ActivePlanets: planets.filter(
Expand All @@ -261,16 +238,13 @@ export async function getData() {
target: getPlanetName(p.target),
})),
Events: status.globalEvents,
// SuperStore: storeRotation,
Players: players,
// this is the starting point in unix for whatever time thing they use
UTCOffset: Math.floor(status.timeUtc - status.time * 1000), // use this value to add to the time to get the UTC time in seconds
};
if (
chatsAPI &&
chatsAPI['store_rotation'] &&
chatsAPI['store_rotation'].items
)
data.SuperStore = chatsAPI['store_rotation'];
if (additionalPlanetInfo) data.additionalPlanetInfo = additionalPlanetInfo;
if (storeRotation) data.SuperStore = storeRotation;

writeFileSync('data.json', JSON.stringify(data, null, 2));
return data;
Expand All @@ -288,5 +262,3 @@ export const mappedNames: {
sectors: [],
};
export const planetNames = getAllPlanets().map(p => p.name);

export {API_URL};
43 changes: 43 additions & 0 deletions src/api-wrapper/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,45 @@ export type Faction = 'Humans' | 'Total' | 'Automaton' | 'Terminids';
export type PlanetEventType = 'Defend';
export type CampaignType = 'Defend' | 'Liberation';

export type PlanetBiome = {
name: string;
description: string;
};

export type PlanetEnvironment = {
name: string;
description: string;
};

export type TranslationLangs =
| 'en-US'
| 'en-GB'
| 'pt-BR'
| 'de-DE'
| 'es-ES'
| 'fr-FR'
| 'it-IT'
| 'ja-JP'
| 'ko-KO'
| 'ms-MY'
| 'pl-PL'
| 'pt-PT'
| 'ru-RU'
| 'zh-Hans'
| 'zh-Hant';

export type AdditionalPlanetInfo = {
[key: string]: {
name: string;
sector: string;
biome: PlanetBiome;
environmentals: PlanetEnvironment[];
names: {
[key in TranslationLangs]: string;
};
};
};

export type PlanetInfo = {
index: number;
settingsHash: number;
Expand Down Expand Up @@ -94,6 +133,9 @@ export type MergedPlanetData = {
players: number;
playerPerc: number;
liberation: number;
sectorName?: string;
biome?: PlanetBiome;
environmentals?: PlanetEnvironment[];
};
/*
Defend missions are a race against the clock
Expand Down Expand Up @@ -324,6 +366,7 @@ export type ApiData = {
NewsFeed: NewsFeedItem[];
PlanetStats: PlanetStats;
Planets: MergedPlanetData[];
additionalPlanetInfo?: AdditionalPlanetInfo;
Campaigns: MergedCampaignData[];
PlanetEvents: MergedPlanetEventData[];
ActivePlanets: MergedPlanetData[];
Expand Down
Loading

0 comments on commit 666275d

Please sign in to comment.