356 lines
11 KiB
JavaScript
356 lines
11 KiB
JavaScript
/**
|
|
* EU-Utility External API Test Client (JavaScript/Node.js)
|
|
* =========================================================
|
|
*
|
|
* Example JavaScript client for testing EU-Utility external API.
|
|
* Supports REST API and webhook integrations.
|
|
*
|
|
* Usage:
|
|
* node api_client_test.js --help
|
|
* node api_client_test.js health
|
|
* node api_client_test.js status
|
|
* node api_client_test.js notify "Test Title" "Test Message"
|
|
* node api_client_test.js search "ArMatrix"
|
|
* node api_client_test.js webhook --url <discord_webhook_url>
|
|
*/
|
|
|
|
const http = require('http');
|
|
const https = require('https');
|
|
const { URL } = require('url');
|
|
|
|
class EUUtilityClient {
|
|
constructor(host = '127.0.0.1', port = 8080, apiKey = null) {
|
|
this.host = host;
|
|
this.port = port;
|
|
this.apiKey = apiKey;
|
|
this.baseUrl = `http://${host}:${port}`;
|
|
}
|
|
|
|
_request(method, endpoint, data = null) {
|
|
return new Promise((resolve, reject) => {
|
|
const url = new URL(endpoint, this.baseUrl);
|
|
const options = {
|
|
method: method,
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
}
|
|
};
|
|
|
|
if (this.apiKey) {
|
|
options.headers['X-API-Key'] = this.apiKey;
|
|
}
|
|
|
|
const req = http.request(url, options, (res) => {
|
|
let responseData = '';
|
|
res.on('data', (chunk) => {
|
|
responseData += chunk;
|
|
});
|
|
res.on('end', () => {
|
|
try {
|
|
const data = responseData ? JSON.parse(responseData) : null;
|
|
resolve({
|
|
status: res.statusCode,
|
|
data: data
|
|
});
|
|
} catch (e) {
|
|
resolve({
|
|
status: res.statusCode,
|
|
data: responseData
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
req.on('error', (error) => {
|
|
reject(error);
|
|
});
|
|
|
|
if (data) {
|
|
req.write(JSON.stringify(data));
|
|
}
|
|
req.end();
|
|
});
|
|
}
|
|
|
|
async healthCheck() {
|
|
return this._request('GET', '/health');
|
|
}
|
|
|
|
async getStatus() {
|
|
return this._request('GET', '/api/v1/status');
|
|
}
|
|
|
|
async sendNotification(title, message, type = 'info') {
|
|
return this._request('POST', '/api/v1/notify', {
|
|
title: title,
|
|
message: message,
|
|
type: type
|
|
});
|
|
}
|
|
|
|
async searchNexus(query, entityType = 'items') {
|
|
return this._request('GET', `/api/v1/search?q=${encodeURIComponent(query)}&type=${entityType}`);
|
|
}
|
|
|
|
async recordLoot(value, mob, items = []) {
|
|
return this._request('POST', '/api/v1/loot', {
|
|
value: value,
|
|
mob: mob,
|
|
items: items,
|
|
timestamp: Date.now()
|
|
});
|
|
}
|
|
|
|
async getLootSession() {
|
|
return this._request('GET', '/api/v1/loot/session');
|
|
}
|
|
}
|
|
|
|
async function sendDiscordWebhook(webhookUrl, content, embeds = null) {
|
|
return new Promise((resolve, reject) => {
|
|
const payload = { content: content };
|
|
if (embeds) {
|
|
payload.embeds = embeds;
|
|
}
|
|
|
|
const url = new URL(webhookUrl);
|
|
const options = {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
}
|
|
};
|
|
|
|
const req = https.request(url, options, (res) => {
|
|
resolve(res.statusCode >= 200 && res.statusCode < 300);
|
|
});
|
|
|
|
req.on('error', (error) => {
|
|
reject(error);
|
|
});
|
|
|
|
req.write(JSON.stringify(payload));
|
|
req.end();
|
|
});
|
|
}
|
|
|
|
function validateWebhookPayload(payload) {
|
|
if (typeof payload !== 'object' || payload === null) {
|
|
return { valid: false, error: 'Payload must be an object' };
|
|
}
|
|
|
|
if (!payload.content && !payload.embeds) {
|
|
return { valid: false, error: 'Payload must contain content or embeds' };
|
|
}
|
|
|
|
if (payload.content && payload.content.length > 2000) {
|
|
return { valid: false, error: 'Content exceeds 2000 character limit' };
|
|
}
|
|
|
|
if (payload.embeds) {
|
|
if (!Array.isArray(payload.embeds)) {
|
|
return { valid: false, error: 'Embeds must be an array' };
|
|
}
|
|
if (payload.embeds.length > 10) {
|
|
return { valid: false, error: 'Maximum 10 embeds allowed' };
|
|
}
|
|
}
|
|
|
|
return { valid: true, error: null };
|
|
}
|
|
|
|
async function testAllEndpoints(client) {
|
|
console.log('Testing EU-Utility External API...');
|
|
console.log('=' .repeat(50));
|
|
|
|
const tests = [
|
|
['Health Check', () => client.healthCheck()],
|
|
['Get Status', () => client.getStatus()],
|
|
['Send Notification', () => client.sendNotification('Test', 'Hello from JS client')],
|
|
['Search Nexus', () => client.searchNexus('ArMatrix')],
|
|
['Record Loot', () => client.recordLoot(50.25, 'Atrox Young', ['Animal Oil'])],
|
|
['Get Loot Session', () => client.getLootSession()],
|
|
];
|
|
|
|
for (const [name, testFunc] of tests) {
|
|
try {
|
|
console.log(`\n${name}...`);
|
|
const result = await testFunc();
|
|
const status = result.status >= 200 && result.status < 300 ? '✅' : '❌';
|
|
console.log(`${status} Status: ${result.status}`);
|
|
console.log(` Response:`, result.data);
|
|
} catch (error) {
|
|
console.log(`❌ Error: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
console.log('\n' + '='.repeat(50));
|
|
console.log('Tests completed');
|
|
}
|
|
|
|
// CLI handling
|
|
function printHelp() {
|
|
console.log(`
|
|
EU-Utility External API Test Client (JavaScript)
|
|
|
|
Usage:
|
|
node api_client_test.js [options] <command>
|
|
|
|
Options:
|
|
--host <host> API host (default: 127.0.0.1)
|
|
--port <port> API port (default: 8080)
|
|
--api-key <key> API key for authentication
|
|
|
|
Commands:
|
|
health Check API health
|
|
status Get EU-Utility status
|
|
notify <title> <msg> Send notification
|
|
search <query> Search Nexus
|
|
loot <value> <mob> Record loot
|
|
global <value> <mob> Record global
|
|
webhook --url <url> Send Discord webhook
|
|
test Test all endpoints
|
|
validate <payload> Validate webhook payload
|
|
|
|
Examples:
|
|
node api_client_test.js health
|
|
node api_client_test.js notify "Test" "Hello World"
|
|
node api_client_test.js search "ArMatrix"
|
|
node api_client_test.js webhook --url https://discord.com/api/webhooks/...
|
|
`);
|
|
}
|
|
|
|
async function main() {
|
|
const args = process.argv.slice(2);
|
|
|
|
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
printHelp();
|
|
return;
|
|
}
|
|
|
|
// Parse options
|
|
let host = '127.0.0.1';
|
|
let port = 8080;
|
|
let apiKey = null;
|
|
|
|
const hostIndex = args.indexOf('--host');
|
|
if (hostIndex !== -1) {
|
|
host = args[hostIndex + 1];
|
|
args.splice(hostIndex, 2);
|
|
}
|
|
|
|
const portIndex = args.indexOf('--port');
|
|
if (portIndex !== -1) {
|
|
port = parseInt(args[portIndex + 1]);
|
|
args.splice(portIndex, 2);
|
|
}
|
|
|
|
const keyIndex = args.indexOf('--api-key');
|
|
if (keyIndex !== -1) {
|
|
apiKey = args[keyIndex + 1];
|
|
args.splice(keyIndex, 2);
|
|
}
|
|
|
|
const command = args[0];
|
|
const client = new EUUtilityClient(host, port, apiKey);
|
|
|
|
try {
|
|
switch (command) {
|
|
case 'health': {
|
|
const result = await client.healthCheck();
|
|
console.log(JSON.stringify(result, null, 2));
|
|
break;
|
|
}
|
|
|
|
case 'status': {
|
|
const result = await client.getStatus();
|
|
console.log(JSON.stringify(result, null, 2));
|
|
break;
|
|
}
|
|
|
|
case 'notify': {
|
|
if (args.length < 3) {
|
|
console.error('Usage: notify <title> <message>');
|
|
process.exit(1);
|
|
}
|
|
const result = await client.sendNotification(args[1], args[2]);
|
|
console.log(JSON.stringify(result, null, 2));
|
|
break;
|
|
}
|
|
|
|
case 'search': {
|
|
if (args.length < 2) {
|
|
console.error('Usage: search <query>');
|
|
process.exit(1);
|
|
}
|
|
const result = await client.searchNexus(args[1]);
|
|
console.log(JSON.stringify(result, null, 2));
|
|
break;
|
|
}
|
|
|
|
case 'loot': {
|
|
if (args.length < 3) {
|
|
console.error('Usage: loot <value> <mob>');
|
|
process.exit(1);
|
|
}
|
|
const result = await client.recordLoot(parseFloat(args[1]), args[2]);
|
|
console.log(JSON.stringify(result, null, 2));
|
|
break;
|
|
}
|
|
|
|
case 'global': {
|
|
if (args.length < 3) {
|
|
console.error('Usage: global <value> <mob>');
|
|
process.exit(1);
|
|
}
|
|
const result = await client.recordLoot(parseFloat(args[1]), args[2]);
|
|
console.log(JSON.stringify(result, null, 2));
|
|
break;
|
|
}
|
|
|
|
case 'webhook': {
|
|
const urlIndex = args.indexOf('--url');
|
|
if (urlIndex === -1 || !args[urlIndex + 1]) {
|
|
console.error('Usage: webhook --url <webhook_url>');
|
|
process.exit(1);
|
|
}
|
|
const contentIndex = args.indexOf('--content');
|
|
const content = contentIndex !== -1 ? args[contentIndex + 1] : 'Test from EU-Utility';
|
|
|
|
const success = await sendDiscordWebhook(args[urlIndex + 1], content);
|
|
console.log(success ? '✅ Sent' : '❌ Failed');
|
|
break;
|
|
}
|
|
|
|
case 'test': {
|
|
await testAllEndpoints(client);
|
|
break;
|
|
}
|
|
|
|
case 'validate': {
|
|
if (args.length < 2) {
|
|
console.error('Usage: validate <json_payload>');
|
|
process.exit(1);
|
|
}
|
|
try {
|
|
const payload = JSON.parse(args[1]);
|
|
const validation = validateWebhookPayload(payload);
|
|
console.log(validation.valid ? '✅ Valid' : `❌ ${validation.error}`);
|
|
} catch (e) {
|
|
console.error(`❌ Invalid JSON: ${e.message}`);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
console.error(`Unknown command: ${command}`);
|
|
printHelp();
|
|
process.exit(1);
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error: ${error.message}`);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main(); |