ddmaster 2.6.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/bin.ts +44 -0
- package/{index.js → src/index.ts} +1 -2
- package/{serverlist.js → src/serverlist.ts} +19 -26
- package/src/types.ts +43 -0
- package/tsconfig.json +43 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ddmaster",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Позволяет опрашивать мастер-сервер дднета",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"author": "0374flop",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"type": "commonjs",
|
|
16
|
-
"
|
|
17
|
-
|
|
16
|
+
"bin": "./bin.js",
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^25.2.3"
|
|
18
19
|
}
|
|
19
20
|
}
|
package/src/bin.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const ddmaster = require('./index.js');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const [command, ...args] = process.argv.slice(2);
|
|
7
|
+
|
|
8
|
+
if (command === "find") {
|
|
9
|
+
ddmaster.findDDNetPlayerByName(args.join(" ")).then(async (servers: import('./types').DDNetServer[]) => {
|
|
10
|
+
if (servers.length === 0) {
|
|
11
|
+
console.log("Player not found on any server.");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log(`Count of servers: ${servers.length}`);
|
|
16
|
+
console.log((await ddmaster.getDDNetServers(servers)).join("\n"));
|
|
17
|
+
}).catch((err: Error) => {
|
|
18
|
+
console.error('Error:', err);
|
|
19
|
+
});
|
|
20
|
+
} else if (command === "list") {
|
|
21
|
+
ddmaster.getDDNetServers().then((servers: string[]) => {
|
|
22
|
+
console.log(servers.join("\n"));
|
|
23
|
+
}).catch((err: Error) => {
|
|
24
|
+
console.error('Error:', err);
|
|
25
|
+
});
|
|
26
|
+
} else if (command === "raw") {
|
|
27
|
+
ddmaster.getrawDDNetServers().then((servers: import('./types').DDNetServer[]) => {
|
|
28
|
+
console.log(JSON.stringify(servers, null, 2));
|
|
29
|
+
}).catch((err: Error) => {
|
|
30
|
+
console.error('Error:', err);
|
|
31
|
+
});
|
|
32
|
+
} else if (command === "info") {
|
|
33
|
+
ddmaster.getinfoserver(args[0]).then((server: import('./types').DDNetServer) => {
|
|
34
|
+
console.log(JSON.stringify(server, null, 2));
|
|
35
|
+
}).catch((err: Error) => {
|
|
36
|
+
console.error('Error:', err);
|
|
37
|
+
});
|
|
38
|
+
} else {
|
|
39
|
+
console.log("Usage:");
|
|
40
|
+
console.log(" find <playerName> - Найти сервера с игроком");
|
|
41
|
+
console.log(" list - Получить список всех серверов");
|
|
42
|
+
console.log(" raw - Получить сырые данные серверов");
|
|
43
|
+
console.log(" info <address> - Получить информацию о сервере по адресу");
|
|
44
|
+
}
|
|
@@ -3,34 +3,29 @@
|
|
|
3
3
|
|
|
4
4
|
"use strict";
|
|
5
5
|
|
|
6
|
-
const DebugLoger = require('loger0374');
|
|
7
|
-
const loger = new DebugLoger('ddmaster', false, true, null, true);
|
|
8
|
-
|
|
9
6
|
if (typeof fetch === 'undefined') {
|
|
10
7
|
try {
|
|
11
8
|
require.resolve('node-fetch');
|
|
12
|
-
loger.log('Using node-fetch polyfill');
|
|
13
9
|
} catch (e) {
|
|
14
10
|
throw new Error('Node.js <18, npm install node-fetch');
|
|
15
11
|
}
|
|
16
12
|
|
|
17
13
|
const nodeFetch = require('node-fetch');
|
|
18
14
|
global.fetch = nodeFetch.default || nodeFetch;
|
|
19
|
-
loger.log('Polyfilled fetch with node-fetch');
|
|
20
15
|
}
|
|
21
16
|
|
|
22
17
|
/**
|
|
23
18
|
* Делает запрос на мастер сервер ДДНета.
|
|
24
19
|
* @returns Сервера ДДНета но в сыром виде.
|
|
25
20
|
*/
|
|
26
|
-
async function getrawDDNetServers() {
|
|
21
|
+
async function getrawDDNetServers(): Promise<{ servers: import('./types').DDNetServer[] } | null> {
|
|
27
22
|
try {
|
|
28
23
|
const response = await fetch('https://master1.ddnet.org/ddnet/15/servers.json');
|
|
29
24
|
if (!response.ok) throw new Error(`Ошибка при запросе: ${response.status}`);
|
|
30
25
|
const data = await response.json();
|
|
31
26
|
return data;
|
|
32
27
|
} catch (error) {
|
|
33
|
-
|
|
28
|
+
console.error(error);
|
|
34
29
|
return null;
|
|
35
30
|
}
|
|
36
31
|
}
|
|
@@ -40,10 +35,9 @@ async function getrawDDNetServers() {
|
|
|
40
35
|
* @param {string} addr - берёт примерно такое "tw-0.7+udp://152.89.254.27:8310"
|
|
41
36
|
* @returns {string|null} 152.89.254.27:8310 возвращает чистый адрес (если addr не валидный то null)
|
|
42
37
|
*/
|
|
43
|
-
function convertudptw(addr) {
|
|
38
|
+
function convertudptw(addr: string) {
|
|
44
39
|
if (typeof addr !== 'string') return null;
|
|
45
40
|
const match = addr.match(/(\d{1,3}(\.\d{1,3}){3}:\d+)/);
|
|
46
|
-
loger.log('convertudptw', addr, '->', match ? match[1] : null);
|
|
47
41
|
return match ? match[1] : null;
|
|
48
42
|
}
|
|
49
43
|
|
|
@@ -54,16 +48,15 @@ function convertudptw(addr) {
|
|
|
54
48
|
*/
|
|
55
49
|
async function getDDNetServers(data = null) {
|
|
56
50
|
try {
|
|
57
|
-
const servers = data || (await getrawDDNetServers())
|
|
51
|
+
const servers = data || (await getrawDDNetServers())?.servers;
|
|
58
52
|
if (!servers) {
|
|
59
|
-
loger.error('Нет серверов в данных');
|
|
60
53
|
return [];
|
|
61
54
|
}
|
|
62
55
|
|
|
63
|
-
const ipv4WithPorts = [];
|
|
56
|
+
const ipv4WithPorts: string[] = [];
|
|
64
57
|
|
|
65
58
|
for (const server of servers) {
|
|
66
|
-
server.addresses.forEach(addr => {
|
|
59
|
+
server.addresses.forEach((addr: string) => {
|
|
67
60
|
const converted = convertudptw(addr);
|
|
68
61
|
if (converted == null) return;
|
|
69
62
|
ipv4WithPorts.push(converted);
|
|
@@ -71,7 +64,7 @@ async function getDDNetServers(data = null) {
|
|
|
71
64
|
}
|
|
72
65
|
return [...new Set(ipv4WithPorts)];
|
|
73
66
|
} catch (err) {
|
|
74
|
-
|
|
67
|
+
console.error(err);
|
|
75
68
|
return [];
|
|
76
69
|
}
|
|
77
70
|
}
|
|
@@ -86,7 +79,7 @@ async function getDDNetServers(data = null) {
|
|
|
86
79
|
* @returns {Promise<Array>} Массив серверов (как в getrawDDNetServers().servers),
|
|
87
80
|
* на которых найден игрок.
|
|
88
81
|
*/
|
|
89
|
-
async function findDDNetPlayerByName(playerName, data = null) {
|
|
82
|
+
async function findDDNetPlayerByName(playerName: string, data = null) {
|
|
90
83
|
if (typeof playerName !== 'string') {
|
|
91
84
|
throw new TypeError('playerName должен быть строкой');
|
|
92
85
|
}
|
|
@@ -94,7 +87,6 @@ async function findDDNetPlayerByName(playerName, data = null) {
|
|
|
94
87
|
try {
|
|
95
88
|
const raw = data || await getrawDDNetServers();
|
|
96
89
|
if (!raw || !Array.isArray(raw.servers)) {
|
|
97
|
-
loger.error('Некорректные данные серверов');
|
|
98
90
|
return [];
|
|
99
91
|
}
|
|
100
92
|
|
|
@@ -104,36 +96,37 @@ async function findDDNetPlayerByName(playerName, data = null) {
|
|
|
104
96
|
const info = server.info;
|
|
105
97
|
if (!info || !Array.isArray(info.clients)) continue;
|
|
106
98
|
|
|
107
|
-
const hasPlayer = info.clients.some(client => client.name === playerName);
|
|
99
|
+
const hasPlayer = info.clients.some((client: import('./types').ServerClient) => client.name === playerName);
|
|
108
100
|
if (hasPlayer) {
|
|
109
101
|
resultServers.push(server);
|
|
110
102
|
}
|
|
111
103
|
}
|
|
112
104
|
return resultServers;
|
|
113
105
|
} catch (err) {
|
|
114
|
-
|
|
106
|
+
console.error(err);
|
|
115
107
|
return [];
|
|
116
108
|
}
|
|
117
109
|
}
|
|
118
110
|
|
|
119
|
-
function filterbycommunity(servers, community) {
|
|
111
|
+
function filterbycommunity(servers: import('./types').DDNetServer[], community: string) {
|
|
120
112
|
return servers.filter(server => server.community === community);
|
|
121
113
|
}
|
|
122
114
|
|
|
123
|
-
function filterbylocation(servers, location) {
|
|
115
|
+
function filterbylocation(servers: import('./types').DDNetServer[], location: string) {
|
|
124
116
|
return servers.filter(server => server.location?.toLowerCase() === location?.toLowerCase());
|
|
125
117
|
}
|
|
126
118
|
|
|
127
|
-
function filterbylocationincludes(servers, location) {
|
|
119
|
+
function filterbylocationincludes(servers: import('./types').DDNetServer[], location: string) {
|
|
128
120
|
return servers.filter(server => server.location?.toLowerCase().includes(location?.toLowerCase()));
|
|
129
121
|
}
|
|
130
122
|
|
|
131
|
-
async function getinfoserver(address) {
|
|
123
|
+
async function getinfoserver(address: string) {
|
|
132
124
|
const servers = await getrawDDNetServers();
|
|
133
|
-
const server = servers
|
|
134
|
-
|
|
135
|
-
|
|
125
|
+
const server = servers?.servers.find((server: import('./types').DDNetServer) => {
|
|
126
|
+
if (server.addresses) return false;
|
|
127
|
+
return convertudptw(server.addresses[0]) === address;
|
|
128
|
+
});
|
|
136
129
|
return server;
|
|
137
130
|
}
|
|
138
131
|
|
|
139
|
-
module.exports = { getDDNetServers, getrawDDNetServers, convertudptw, findDDNetPlayerByName, filterbycommunity, filterbylocation, filterbylocationincludes,
|
|
132
|
+
module.exports = { getDDNetServers, getrawDDNetServers, convertudptw, findDDNetPlayerByName, filterbycommunity, filterbylocation, filterbylocationincludes, getinfoserver };
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface DDNetServer {
|
|
2
|
+
addresses: string[];
|
|
3
|
+
community: string;
|
|
4
|
+
location: string;
|
|
5
|
+
info: ServerInfo;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ServerInfo {
|
|
9
|
+
max_clients: number;
|
|
10
|
+
max_players: number;
|
|
11
|
+
passworded: boolean;
|
|
12
|
+
game_type: string;
|
|
13
|
+
flag: number;
|
|
14
|
+
name: string;
|
|
15
|
+
map: ServerMap;
|
|
16
|
+
version: string;
|
|
17
|
+
client_score_kind: string;
|
|
18
|
+
requires_login: boolean;
|
|
19
|
+
clients: ServerClient[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ServerMap {
|
|
23
|
+
name: string;
|
|
24
|
+
sha256: string;
|
|
25
|
+
size: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ServerClient {
|
|
29
|
+
name: string;
|
|
30
|
+
clan: string;
|
|
31
|
+
country: number;
|
|
32
|
+
score: number;
|
|
33
|
+
is_player: boolean;
|
|
34
|
+
skin: ClientSkin;
|
|
35
|
+
afk: boolean;
|
|
36
|
+
team: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ClientSkin {
|
|
40
|
+
name: string;
|
|
41
|
+
color_body?: number;
|
|
42
|
+
color_feet?: number;
|
|
43
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
// File Layout
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"outDir": "./lib",
|
|
7
|
+
|
|
8
|
+
// Environment Settings
|
|
9
|
+
// See also https://aka.ms/tsconfig/module
|
|
10
|
+
"module": "nodenext",
|
|
11
|
+
"target": "esnext",
|
|
12
|
+
"types": ["node"],
|
|
13
|
+
// For nodejs:
|
|
14
|
+
// "lib": ["esnext"],
|
|
15
|
+
// "types": ["node"],
|
|
16
|
+
// and npm install -D @types/node
|
|
17
|
+
|
|
18
|
+
// Other Outputs
|
|
19
|
+
"sourceMap": false,
|
|
20
|
+
"declaration": true,
|
|
21
|
+
"declarationMap": false,
|
|
22
|
+
|
|
23
|
+
// Stricter Typechecking Options
|
|
24
|
+
"noUncheckedIndexedAccess": true,
|
|
25
|
+
"exactOptionalPropertyTypes": true,
|
|
26
|
+
|
|
27
|
+
// Style Options
|
|
28
|
+
// "noImplicitReturns": true,
|
|
29
|
+
// "noImplicitOverride": true,
|
|
30
|
+
// "noUnusedLocals": true,
|
|
31
|
+
// "noUnusedParameters": true,
|
|
32
|
+
// "noFallthroughCasesInSwitch": true,
|
|
33
|
+
// "noPropertyAccessFromIndexSignature": true,
|
|
34
|
+
|
|
35
|
+
// Recommended Options
|
|
36
|
+
"strict": true,
|
|
37
|
+
"verbatimModuleSyntax": true,
|
|
38
|
+
"isolatedModules": true,
|
|
39
|
+
"noUncheckedSideEffectImports": true,
|
|
40
|
+
"moduleDetection": "force",
|
|
41
|
+
"skipLibCheck": true,
|
|
42
|
+
}
|
|
43
|
+
}
|