ddnet
Version:
A typescript npm package for interacting with data from ddnet.org
168 lines • 4.97 kB
JavaScript
import axios from 'axios';
import { _Schema_info } from '../../schemas/other/info.js';
import { DDNetError } from '../../util.js';
import { CacheManager } from './CacheManager.js';
import { Community } from './Community.js';
/**
* Represents servers info.
*/
export class Info {
//#region Cache
/**
* Info responses cache. (12h default TTL)
*/
static cache = new CacheManager('info-cache', 12 * 60 * 60 * 1000); // 12h ttl
/**
* Sets the TTL (Time-To-Live) for objects in cache.
*/
static setTTL = this.cache.setTTL;
/**
* Clears the {@link Info.cache}.
*/
static clearCache = this.cache.clearCache;
//#endregion
//#region Declarations
/**
* Raw info data.
*/
#rawData; // Marked private with vanilla JS syntax for better logging.
/**
* List of major communities.
*/
communities;
/**
* Community icons directory.
*/
communityIconsDownloadUrl;
/**
* Game news.
*/
news;
/**
* Maps directory.
*/
mapDownloadUrl;
/**
* Latest game version.
*/
version;
/**
* Other parsed data.
*
* @remarks
* I think this is mostly used in the client. Still I parsed the data and added it here.
*/
other;
//#endregion
/**
* Create a new instance of {@link Info} from API data.
* Not intended to be used, use {@link new Info.new} instead.
*/
constructor(
/**
* The raw info data.
*/
rawData) {
this.populate(rawData);
}
/**
* Fetch, parse and construct a new {@link Info} instance.
*/
static async new(
/**
* Wether to bypass the info data cache.
*/
bypassCache = false) {
const response = await this.makeRequest(bypassCache);
if (response instanceof DDNetError)
throw response;
const parsed = this.parseObject(response.data);
if (!parsed.success)
throw parsed.error;
return new this(parsed.data);
}
/**
* Parse an object using the {@link _Schema_info raw data zod schema}.
*/
static parseObject(
/**
* The object to be parsed.
*/
data) {
const parsed = _Schema_info.safeParse(data);
if (parsed.success)
return { success: true, data: parsed.data };
return { success: false, error: new DDNetError(parsed.error.message, parsed.error) };
}
/**
* Fetch the info data from the API.
*/
static async makeRequest(
/**
* Wether to bypass the cache.
*/
force = false) {
const url = 'https://info.ddnet.org/info';
if (!force) {
if (await this.cache.has(url)) {
const data = await this.cache.get(url);
if (data)
return { data, fromCache: true };
}
}
const response = await axios.get(url).catch((err) => new DDNetError(err.cause?.message, err));
if (response instanceof DDNetError)
return response;
const data = response.data;
if (typeof data === 'string')
return new DDNetError(`Invalid response!`, data);
await this.cache.set(url, data);
return { data, fromCache: false };
}
/**
* Populate the object with the raw info data.
*/
populate(
/**
* The raw info data.
*/
rawData) {
this.#rawData = rawData;
this.communities = this.#rawData.communities.map(c => {
if (c.id === 'ddnet' || c.id === 'kog') {
c.icon.servers = c.id === 'ddnet' ? this.#rawData.servers : this.#rawData['servers-kog'];
}
return new Community(c);
});
this.communityIconsDownloadUrl = this.#rawData['community-icons-download-url'];
this.news = this.#rawData.news;
this.mapDownloadUrl = this.#rawData['map-download-url'];
this.version = this.#rawData.version;
this.other = {
location: this.#rawData.location,
stunServersIpv6: this.#rawData['stun-servers-ipv6'],
stunServersIpv4: this.#rawData['stun-servers-ipv4'],
warnPngliteIncompatibleImages: this.#rawData['warn-pnglite-incompatible-images']
};
return this;
}
/**
* Refresh the info data.
*/
async refresh() {
const data = await Info.makeRequest(true);
if (data instanceof DDNetError)
throw new DDNetError(`Failed to refresh info`, data);
const parsed = Info.parseObject(data.data);
if (!parsed.success)
throw new DDNetError(`Failed to refresh info`, parsed.error);
return this.populate(parsed.data);
}
/**
* Get all server addresses from all communities.
*/
getAllServerAddresses() {
return this.communities.flatMap(c => c.getAllServerAddresses());
}
}
//# sourceMappingURL=Info.js.map