Skip to content

Commit

Permalink
feat: Start on channelApi
Browse files Browse the repository at this point in the history
  • Loading branch information
Sup3rFire committed Mar 2, 2024
1 parent 10694a5 commit 12007bb
Show file tree
Hide file tree
Showing 12 changed files with 467 additions and 26 deletions.
10 changes: 2 additions & 8 deletions src/client/ClientUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,16 +172,10 @@ export default class ClientUser extends EventEmitter {

export default interface Client extends EventEmitter {
/** Emitted when a user sends a direct message to the client. */
on(
eventName: "dm",
listener: (message: { content: string; author: User }) => void
): this;
on(eventName: "dm", listener: (message: { content: string; author: User }) => void): this;

/** Emitted when a user sends an invite to the client.*/
on(
eventName: "invite",
listener: (invite: { room: string; author: User }) => void
): this;
on(eventName: "invite", listener: (invite: { room: string; author: User }) => void): this;

/** Emitted when the server sends an update on how many users online. */
on(eventName: "online", listener: (online: number) => void): this;
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import User from "./user/User";
import Game from "./game/Game";
import Player from "./game/Player";
import ClientPlayer from "./client/ClientPlayer";
import { TetraChannel } from "./util/channelApi";

export {
Client,
Expand All @@ -16,4 +17,5 @@ export {
Player,
GameOptions,
ClientPlayer,
TetraChannel,
};
19 changes: 5 additions & 14 deletions src/user/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ export default class User {
this.role = user.role;
if (user.ts) this.ts = new Date(user.ts);
this.botMaster = user.botmaster;
this.badges = user.badges.map(
(badge: { id: string; label: string; ts?: string }) => {
if (badge.ts) return { ...badge, ts: new Date(badge.ts) };
return badge;
}
);
this.badges = user.badges.map((badge: { id: string; label: string; ts?: string }) => {
if (badge.ts) return { ...badge, ts: new Date(badge.ts) };
return badge;
});
this.xp = user.xp;
this.gamesPlayed = user.gamesplayed;
this.gamesWon = user.gameswon;
Expand Down Expand Up @@ -74,14 +72,7 @@ export default class User {
*
* @readonly
*/
public readonly role:
| "anon"
| "user"
| "bot"
| "halfmod"
| "mod"
| "admin"
| "sysop";
public readonly role: "anon" | "user" | "bot" | "halfmod" | "mod" | "admin" | "sysop";
/**
* When the user account was created. If not set, this account was created before join dates were recorded.
*
Expand Down
77 changes: 74 additions & 3 deletions src/util/channelApi.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import { APIResponse } from "./types";
import {
APIResponse,
GeneralActivityType,
GeneralStatsType,
UserInfoType,
UserRecordsType,
UserSearchType,
} from "./types";

const cacheSessionID = `SESS-${Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)}`;

const cache: Map<string, any> = new Map();

export default async function (endpoint: string, method = "GET", body?: any): Promise<APIResponse> {
export default async function channelApi(
endpoint: string,
method = "GET",
body?: any
): Promise<APIResponse> {
if (method == "GET" && !body) {
let cacheData = cache.get(endpoint);
if (!!cacheData) {
Expand All @@ -13,7 +24,7 @@ export default async function (endpoint: string, method = "GET", body?: any): Pr
return cacheData.data;
}
}
let response: Promise<APIResponse> = fetch(`https://ch.tetr.io/api${endpoint}`, {
let response: Promise<APIResponse> = fetch(`https://ch.tetr.io/api${encodeURI(endpoint)}`, {
method,
body,
headers: {
Expand All @@ -27,3 +38,63 @@ export default async function (endpoint: string, method = "GET", body?: any): Pr

return (await response).data;
}

/**
* @description Some statistics about the service.
* @returns {Promise<GeneralStatsType>}
*/
function generalStats(): Promise<GeneralStatsType> {
return channelApi("/general/stats");
}

/**
* @description A graph of user activity over the last 2 days. A user is seen as active if they logged in or received XP within the last 30 minutes.
* @returns {Promise<GeneralActivityType>}
*/
function generalActivity(): Promise<GeneralActivityType> {
return channelApi("/general/activity");
}

/**
* @description An object describing the user in detail.
* @param {string} user The username or user ID to look up.
* @returns {Promise<UserInfoType>}
*/
function userInfo(user: string): Promise<UserInfoType> {
return channelApi("/users/" + user.toLowerCase()).then((x) => x.user);
}

/**
* @description An object describing the user in detail.
* @param {string} user The username or user ID to look up.
* @returns {Promise<UserRecordsType>}
*/
function userRecords(user: string): Promise<UserRecordsType> {
return channelApi("/users/" + user.toLowerCase() + "/records");
}

/**
* @description An object describing the user found, or undefined if none found.
* @param {string} query The Discord ID (snowflake) to look up.
* @returns {Promise<UserSearchType>}
*/
function userSearch(query: string): Promise<UserSearchType | undefined> {
return channelApi("/users/search/" + query).then((x) => x.user ?? undefined);
}

const general = {
stats: generalStats,
activity: generalActivity,
};

const users = {
info: userInfo,
records: userRecords,
search: userSearch,
};

export const TetraChannel = {
general,
users,
cache,
};
1 change: 0 additions & 1 deletion src/util/types.ts

This file was deleted.

37 changes: 37 additions & 0 deletions src/util/types/general.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export type GeneralStatsType = {
/** The amount of users on the server, including anonymous accounts. */
usercount: number;
/** The amount of users created a second (through the last minute). */
usercount_delta: number;
/** The amount of anonymous accounts on the server. */
anoncount: number;
/** The total amount of accounts ever created (including pruned anons etc.). */
totalaccounts: number;
/** The amount of ranked (visible in TETRA LEAGUE leaderboard) accounts on the server. */
rankedcount: number;

/** The amount of replays stored on the server. */
replaycount: number;

/** The amount of games played across all users, including both off- and online modes. */
gamesplayed: number;
/** The amount of games played a second (through the last minute). */
gamesplayed_delta: number;

/** The amount of games played across all users, including both off- and online modes, excluding games that were not completed (e.g. retries) */
gamesfinished: number;
/** The amount of seconds spent playing across all users, including both off- and online modes. */
gametime: number;

/** The amount of keys pressed across all users, including both off- and online modes. */
inputs: number;
/** The amount of pieces placed across all users, including both off- and online modes. */
piecesplaced: number;
};

export type GeneralActivityType = {
/** An array of plot points, newest points first. */
activity: number[];
};

export type RoleType = "anon" | "user" | "bot" | "halfmod" | "mod" | "admin" | "sysop" | "banned";
8 changes: 8 additions & 0 deletions src/util/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export type APIResponse = any;

export * from "./General";
export * from "./League";
export * from "./User";
export * from "./Leaderboard";
export * from "./Record";
export * from "./News";
34 changes: 34 additions & 0 deletions src/util/types/leaderboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { LeagueInfosType, RoleType } from ".";

export type Base_Leaderboard_UserInfoType = {
/** The user's internal ID. */
_id: string;
/** The user's username. */
username: string;
/** The user's role */
role: RoleType;
/** The user's XP in points. */
xp: number;
/** The user's ISO 3166-1 country code, or null if hidden/unknown. Some vanity flags exist. */
country?: string;
/** Whether this user is currently supporting TETR.IO <3 */
supporter: boolean;
/** Whether this user is a verified account. */
verified: boolean;
};

export type TL_Leaderboard_UserInfoType = Base_Leaderboard_UserInfoType & {
/** This user's current TETRA LEAGUE standing: */
league: LeagueInfosType;
};

export type XP_Leaderboard_UserInfoType = Base_Leaderboard_UserInfoType & {
/** When the user account was created. If not set, this account was created before join dates were recorded. */
ts?: string;
/** The amount of online games played by this user. If the user has chosen to hide this statistic, it will be -1. */
gamesplayed: number;
/** The amount of online games won by this user. If the user has chosen to hide this statistic, it will be -1. */
gameswon: number;
/** The amount of seconds this user spent playing, both on- and offline. If the user has chosen to hide this statistic, it will be -1. */
gametime: number;
};
68 changes: 68 additions & 0 deletions src/util/types/league.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
export type MiddleRanks =
| "D+"
| "C-"
| "C"
| "C+"
| "B-"
| "B"
| "B+"
| "A-"
| "A"
| "A+"
| "S-"
| "S"
| "S+"
| "SS"
| "U";
export type AllRanks = MiddleRanks | "D" | "X" | "Z";

export type LeagueInfosType = {
/** The amount of TETRA LEAGUE games played by this user. */
gamesplayed: number;
/** The amount of TETRA LEAGUE games won by this user. */
gameswon: number;

/** This user's TR (Tetra Rating), or -1 if less than 10 games were played. */
rating: number;
/** This user's letter rank. Z is unranked. */
rank: AllRanks;
/** This user's highest achieved rank this season. */
bestrank: MiddleRanks | "D" | "X";

/** This user's Glicko-2 rating. */
glicko?: number;
/** This user's Glicko-2 Rating Deviation. If over 100, this user is unranked. */
rd?: number;

/** This user's average APM (attack per minute) over the last 10 games. */
apm?: number;
/** This user's average PPS (pieces per second) over the last 10 games. */
pps?: number;
/** This user's average VS (versus score) over the last 10 games. */
vs?: number;
/** Whether this user's RD is rising (has not played in the last week). */
decaying: boolean;
};

export type LeagueInfosFullType = LeagueInfosType & {
/** This user's position in global leaderboards, or -1 if not applicable. */
standing: number;
/** This user's position in local leaderboards, or -1 if not applicable. */
standing_local: number;

/** The next rank this user can achieve, if they win more games, or null if unranked (or the best rank). */
next_rank?: MiddleRanks | null;
/** The previous rank this user can achieve, if they lose more games, or null if unranked (or the worst rank). */
prev_rank?: MiddleRanks | null;

/** The position of the best player in the user's current rank, surpass them to go up a rank. -1 if unranked (or the best rank). */
next_at: number;
/** The position of the worst player in the user's current rank, dip below them to go down a rank. -1 if unranked (or the worst rank). */
prev_at: number;

/** This user's percentile position (0 is best, 1 is worst). */
percentile: number;

/** This user's percentile rank, or Z if not applicable. */
percentile_rank: AllRanks;
};
14 changes: 14 additions & 0 deletions src/util/types/news.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { NewsRecordsType, streamID } from ".";

export type NewsType = {
/** The item's internal ID. */
_id: string;
/** The item's stream. */
stream: streamID;
/** The item's type. */
type: string;
/** The item's records. */
data: NewsRecordsType;
/** The item's creation date. */
ts: string;
};
Loading

0 comments on commit 12007bb

Please sign in to comment.