refactor(KaiqiuService): optimize caching for finished matches
- Move `parseEventInfo` and `fetchEventContentHTML` logic into `KaiqiuService`. - Implement differentiated caching strategies: - For finished matches: Cache indefinitely (no TTL) to stop unnecessary HTTP requests since the result is final. - For ongoing matches: Retain the 5-minute TTL to fetch live updates. - Remove unused utility functions from `server.ts`. - Update type imports to include `EventDetail` and `Player`. This change reduces server load by avoiding repeated requests for matches with confirmed results, while ensuring live games remain up-to-date.
This commit is contained in:
parent
6cf2d13a73
commit
8be15d51b1
@ -1,6 +1,6 @@
|
||||
import * as cheerio from "cheerio";
|
||||
import { htmlRequestHeaders, parseEventInfo, redis } from "../utils/server";
|
||||
import type { ClubInfo, IEventInfo } from "../types";
|
||||
import { htmlRequestHeaders, redis } from "../utils/server";
|
||||
import type { ClubInfo, EventDetail, IEventInfo, Player } from "../types";
|
||||
import dayjs from "dayjs";
|
||||
import utc from 'dayjs/plugin/utc';
|
||||
import timezone from 'dayjs/plugin/timezone';
|
||||
@ -157,6 +157,9 @@ export class KaiqiuService {
|
||||
const now = dayjs();
|
||||
const isProcessing = now.isAfter(startTime) && now.isBefore(overTime);
|
||||
const isFinished = now.isAfter(overTime);
|
||||
if (isFinished) {
|
||||
await redis.set(key, eventPage);
|
||||
}
|
||||
return {
|
||||
title,
|
||||
eventId,
|
||||
@ -176,9 +179,37 @@ export class KaiqiuService {
|
||||
let html = await redis.get(key) ?? '';
|
||||
if (!html || html.includes('连接超时') || force) {
|
||||
html = await fetch(url, { headers: htmlRequestHeaders }).then(res => res.text() || '');
|
||||
await redis.setex(key, 60 * 5, html);
|
||||
const info = await this.getEventInfo(eventId)
|
||||
if (info.isFinished) {
|
||||
await redis.set(key, html);
|
||||
} else {
|
||||
await redis.setex(key, 60 * 5, html);
|
||||
}
|
||||
}
|
||||
return this.parseEventInfo(html, eventId);
|
||||
}
|
||||
|
||||
private static parseEventInfo(html: string, eventId: string): EventDetail {
|
||||
const $ = cheerio.load(html);
|
||||
const title = $('h2.title a').text();
|
||||
const itemHref = $('.sub_menu a.active').attr('href') ?? '';
|
||||
const itemId = /\S+item_id=(\d+)$/.exec(itemHref)?.[1] ?? '';
|
||||
const players: Player[] = [];
|
||||
const playersEl = $('.thumb');
|
||||
for (const player of playersEl) {
|
||||
const img = $(player).find('.image img').attr('src') ?? '';
|
||||
const name = $(player).find('h6').text().trim();
|
||||
const uid = /space-(?<uid>\d+).html/.exec($(player).find('h6 a').attr('href') ?? '')?.groups?.uid ?? '';
|
||||
const info = $(player).find('p:nth-of-type(2)').text().replace(/\s/g, '');
|
||||
const score = /^.*?\b(\d+)\b/.exec(info)?.[1] ?? '';
|
||||
players.push({ name, avatar: img, score, info, uid });
|
||||
}
|
||||
return {
|
||||
itemId,
|
||||
eventId,
|
||||
title,
|
||||
players,
|
||||
}
|
||||
return parseEventInfo(html, eventId);
|
||||
}
|
||||
|
||||
public static async login(username: string, password: string) {
|
||||
|
||||
@ -41,41 +41,6 @@ export const htmlRequestHeaders = {
|
||||
"cookie": "SECKEY_ABVK=oTGgqH4ypGPFVdQ3J9K7PoAOPdZ+8R7CsUzi75gelcg%3D; uchome_sendmail=1"
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param matchId 比赛 ID
|
||||
* @returns HTML
|
||||
*/
|
||||
export async function fetchEventContentHTML(matchId: string) {
|
||||
const url = `${KAIQIU_BASE_URL}/home/space.php?do=event&id=${matchId}&view=member&status=2`;
|
||||
const resp = await fetch(url, { headers: htmlRequestHeaders });
|
||||
return resp.text() ?? ''
|
||||
}
|
||||
|
||||
export function parseEventInfo(html: string, eventId: string): EventDetail {
|
||||
const $ = cheerio.load(html);
|
||||
const title = $('h2.title a').text();
|
||||
const itemHref = $('.sub_menu a.active').attr('href') ?? '';
|
||||
const itemId = /\S+item_id=(\d+)$/.exec(itemHref)?.[1] ?? '';
|
||||
const players: Player[] = [];
|
||||
const playersEl = $('.thumb');
|
||||
for (const player of playersEl) {
|
||||
const img = $(player).find('.image img').attr('src') ?? '';
|
||||
const name = $(player).find('h6').text().trim();
|
||||
const uid = /space-(?<uid>\d+).html/.exec($(player).find('h6 a').attr('href') ?? '')?.groups?.uid ?? '';
|
||||
const info = $(player).find('p:nth-of-type(2)').text().replace(/\s/g, '');
|
||||
const score = /^.*?\b(\d+)\b/.exec(info)?.[1] ?? '';
|
||||
players.push({ name, avatar: img, score, info, uid });
|
||||
}
|
||||
return {
|
||||
itemId,
|
||||
eventId,
|
||||
title,
|
||||
players,
|
||||
}
|
||||
}
|
||||
|
||||
export const extractBearerTokenFromHeaders = (authorization: string | null) => {
|
||||
if (!authorization) {
|
||||
return null;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user