wynn/ts/src/activities/players.ts
a 4368ec9104
Some checks failed
commit-tag / commit-tag-image (push) Has been cancelled
commit-tag / commit-tag-image (./cmd/caddy) (push) Has been cancelled
noot
2025-03-02 03:23:41 -06:00

121 lines
3.2 KiB
TypeScript

import { c } from "#/di"
import { WApi } from "#/lib/wynn/wapi"
import { PG } from "#/services/pg"
import { log } from "@temporalio/activity"
import { type } from "arktype"
import axios from "axios"
const playerSchemaFail = type({
code: "string",
message: "string",
data: type({
player: {
meta: {
cached_at: "number"
},
username: "string",
id: "string",
raw_id: "string",
avatar: "string",
skin_texture: "string",
properties: [{
name: "string",
value: "string",
signature: "string"
}],
name_history: "unknown[]"
}
}),
success: "false"
})
const playerSchemaSuccess = type({
code: "string",
message: "string",
data: type({
player: {
meta: {
cached_at: "number"
},
username: "string",
id: "string",
raw_id: "string",
avatar: "string",
skin_texture: "string",
properties: [{
name: "string",
value: "string",
signature: "string"
}],
name_history: "unknown[]"
}
}),
success: "true"
})
const playerSchema = playerSchemaFail.or(playerSchemaSuccess)
export const scrape_online_players = async()=>{
const api = await c.getAsync(WApi)
const raw = await api.get('/v3/player')
const onlineList = type({
total: "number",
players: {
"[string]": "string | null",
}
}).assert(raw.data)
const { sql } = await c.getAsync(PG)
for(const [playerName, server] of Object.entries(onlineList.players)){
// we do this optimistically without a tx, because temporal will probably handle
// the race, and the worst case is we do extra requests.
const ans = await sql`select uid from minecraft_user where name = ${playerName} limit 1`
if(ans.length === 0){
// the user doesn't exist, so we need to grab their uuid
try {
const resp = await axios.get(`https://playerdb.co/api/player/minecraft/${playerName}`, {
headers: {
"User-Agent": "lil-robot-guy (a@tuxpa.in)",
}
})
const parsedPlayer = playerSchema.assert(resp.data)
if(!parsedPlayer.success){
log.warn(`failed to get uuid for ${playerName}`, {
"payload": parsedPlayer,
})
continue
}
const uuid = parsedPlayer.data.player.id
// insert the user.
await sql`insert into minecraft_user (name, uid, server) values (${playerName}, ${uuid},${server})
on conflict (uid) do update set
name = EXCLUDED.name,
server = EXCLUDED.server
`
log.info(`inserted ${playerName} with uuid ${uuid} on ${server}`)
}catch(e) {
log.warn(`failed to get uuid for ${playerName}`, {
"err": e,
})
continue
}
}
}
await sql.begin(async (sql)=>{
await sql`update minecraft_user set server = null`
for(const [playerName, server] of Object.entries(onlineList.players)){
try {
await sql`update minecraft_user set server = ${server} where name = ${playerName}`
}catch(e) {
log.warn(`failed to update server for ${playerName}`, {
"err": e,
})
continue
}
}
})
}