@@ -363,4 +363,140 @@ router.get("/:ip", async (req, res) => {
363363 }
364364} ) ;
365365
366+ /**
367+ * @swagger
368+ * /servers/{ip}/{port}:
369+ * get:
370+ * summary: Get server by IP and port
371+ * description: Returns detailed information for a specific server by IP address and port
372+ * tags: [Servers]
373+ * parameters:
374+ * - in: path
375+ * name: ip
376+ * required: true
377+ * schema:
378+ * type: string
379+ * description: Server IP address
380+ * example: "185.107.96.59"
381+ * - in: path
382+ * name: port
383+ * required: true
384+ * schema:
385+ * type: integer
386+ * description: Server port
387+ * example: 27015
388+ * responses:
389+ * 200:
390+ * description: Successful response with server details
391+ * content:
392+ * application/json:
393+ * schema:
394+ * $ref: '#/components/schemas/Server'
395+ * 400:
396+ * description: Invalid IP address or port format
397+ * content:
398+ * application/json:
399+ * schema:
400+ * type: object
401+ * properties:
402+ * error:
403+ * type: string
404+ * example: "Invalid IP address format"
405+ * 404:
406+ * description: Server not found
407+ * content:
408+ * application/json:
409+ * schema:
410+ * type: object
411+ * properties:
412+ * error:
413+ * type: string
414+ * example: "Server not found"
415+ * 500:
416+ * description: Server error
417+ * content:
418+ * application/json:
419+ * schema:
420+ * type: object
421+ * properties:
422+ * error:
423+ * type: string
424+ * example: "Server fetch error"
425+ */
426+ router . get ( "/:ip/:port" , async ( req , res ) => {
427+ try {
428+ const { ip, port } = req . params ;
429+
430+ if ( ! isValidIP ( ip ) ) {
431+ return res . status ( 400 ) . json ( { error : "Invalid IP address format" } ) ;
432+ }
433+
434+ const portNum = parseInt ( port , 10 ) ;
435+ if ( isNaN ( portNum ) || portNum < 1 || portNum > 65535 ) {
436+ return res . status ( 400 ) . json ( { error : "Invalid port number" } ) ;
437+ }
438+
439+ const [ rows ] = await pool . query (
440+ "SELECT * FROM servers WHERE ip = ? AND port = ?" ,
441+ [ ip , portNum ]
442+ ) ;
443+
444+ if ( rows . length === 0 ) {
445+ return res . status ( 404 ) . json ( { error : "Server not found" } ) ;
446+ }
447+
448+ const server = rows [ 0 ] ;
449+ let playersList = [ ] ;
450+
451+ if ( server . players_list ) {
452+ try {
453+ playersList =
454+ typeof server . players_list === "string"
455+ ? JSON . parse ( server . players_list )
456+ : server . players_list ;
457+
458+ // Remove IP addresses from player data for privacy
459+ playersList = playersList . map ( ( player ) => {
460+ const { ip, ...playerWithoutIp } = player ;
461+ return playerWithoutIp ;
462+ } ) ;
463+ } catch ( e ) {
464+ logger . error (
465+ `Failed to parse players_list for ${ server . ip } :${ server . port } ` ,
466+ { error : e . message } ,
467+ ) ;
468+ playersList = [ ] ;
469+ }
470+ }
471+
472+ const response = {
473+ ip : server . ip ,
474+ port : server . port ,
475+ game : server . game ,
476+ hostname : server . hostname ,
477+ version : server . version ,
478+ os : server . os ,
479+ secure : server . secure ,
480+ status : server . status ,
481+ map : server . map ,
482+ player_count : server . player_count ,
483+ maxplayers : server . maxplayers ,
484+ bot_count : server . bot_count ,
485+ players_list : playersList ,
486+ region : server . region ,
487+ domain : server . domain ,
488+ api_id : server . api_id ,
489+ kzt_id : server . kzt_id ,
490+ tickrate : server . tickrate ,
491+ last_update : server . last_update ,
492+ created_at : server . created_at ,
493+ } ;
494+
495+ res . json ( response ) ;
496+ } catch ( e ) {
497+ logger . error ( `Server fetch error for ${ req . params . ip } :${ req . params . port } : ${ e . message } ` ) ;
498+ res . status ( 500 ) . json ( { error : "Server fetch error" } ) ;
499+ }
500+ } ) ;
501+
366502module . exports = router ;
0 commit comments