1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
/**
* Fetch the clean Hypixel API
*/
import { CleanPlayer, cleanPlayerResponse } from './cleaners/player'
import { chooseApiKey, HypixelResponse, sendApiRequest } from './hypixelApi'
import * as cached from './hypixelCached'
import { CleanMemberProfile } from './cleaners/skyblock/member'
import { cleanSkyblockProfileResponse, CleanProfile, CleanBasicProfile } from './cleaners/skyblock/profile'
import { cleanSkyblockProfilesResponse } from './cleaners/skyblock/profiles'
export type Included = 'profiles' | 'player' | 'stats'
// the interval at which the "last_save" parameter updates in the hypixel api, this is 3 minutes
export const saveInterval = 60 * 3 * 1000
// the highest level a minion can be
export const maxMinion = 11
/**
* Send a request to api.hypixel.net using a random key, clean it up to be more useable, and return it
*/
export async function sendCleanApiRequest({ path, args }, included?: Included[], cleaned=true) {
const key = await chooseApiKey()
const rawResponse = await sendApiRequest({ path, key, args })
if (rawResponse.throttled) {
// if it's throttled, wait a second and try again
console.log('throttled :/')
await new Promise(resolve => setTimeout(resolve, 1000))
return await sendCleanApiRequest({ path, args }, included, cleaned)
}
if (cleaned) {
// if it needs to clean the response, call cleanResponse
return await cleanResponse({ path, data: rawResponse }, included=included)
} else {
// this is provided in case the caller wants to do the cleaning itself
// used in skyblock/profile, as cleaning the entire profile would use too much cpu
return rawResponse
}
}
async function cleanResponse({ path, data }: { path: string, data: HypixelResponse }, included?: Included[]) {
// Cleans up an api response
switch (path) {
case 'player': return await cleanPlayerResponse(data.player)
case 'skyblock/profile': return await cleanSkyblockProfileResponse(data.profile)
case 'skyblock/profiles': return await cleanSkyblockProfilesResponse(data.profiles)
}
}
/* ----------------------------- */
export interface UserAny {
user?: string
uuid?: string
username?: string
}
export interface CleanUser {
player: any
profiles?: any
activeProfile?: string
online?: boolean
}
/**
* Higher level function that requests the api for a user, and returns the cleaned response
* This is safe to fetch many times because the results are cached!
* @param included lets you choose what is returned, so there's less processing required on the backend
* used inclusions: player, profiles
*/
export async function fetchUser({ user, uuid, username }: UserAny, included: Included[]=['player']): Promise<CleanUser> {
if (!uuid) {
// If the uuid isn't provided, get it
uuid = await cached.uuidFromUser(user || username)
}
const includePlayers = included.includes('player')
const includeProfiles = included.includes('profiles')
let profilesData: CleanProfile[]
let basicProfilesData: CleanBasicProfile[]
let playerData: CleanPlayer
if (includePlayers) {
playerData = await cached.fetchPlayer(uuid)
// if not including profiles, include lightweight profiles just in case
if (!includeProfiles)
basicProfilesData = playerData.profiles
playerData.profiles = undefined
}
if (includeProfiles) {
profilesData = await cached.fetchSkyblockProfiles(uuid)
}
let activeProfile: CleanProfile = null
let lastOnline: number = 0
if (includeProfiles) {
for (const profile of profilesData) {
const member = profile.members.find(member => member.uuid === uuid)
if (member.last_save > lastOnline) {
lastOnline = member.last_save
activeProfile = profile
}
}
}
return {
player: playerData ?? null,
profiles: profilesData ?? basicProfilesData,
activeProfile: includeProfiles ? activeProfile?.uuid : undefined,
online: includeProfiles ? lastOnline > (Date.now() - saveInterval): undefined
}
}
|