diff --git a/code/__DEFINES/{yogs_defines}/telecomms.dm b/code/__DEFINES/{yogs_defines}/telecomms.dm new file mode 100644 index 000000000000..91c522dd149e --- /dev/null +++ b/code/__DEFINES/{yogs_defines}/telecomms.dm @@ -0,0 +1,2 @@ +#define SERVER_LOG_STORAGE_MAX 400 // Number of chat logs the telecomms servers will store before they start deleting the older ones. +#define TELECOMMS_SCAN_RANGE 25 // The range at which the telecomms computers can scan for telecomm servers. \ No newline at end of file diff --git a/code/game/machinery/telecomms/computers/logbrowser.dm b/code/game/machinery/telecomms/computers/logbrowser.dm index 94ebf9bbff2a..892ec7c5195d 100644 --- a/code/game/machinery/telecomms/computers/logbrowser.dm +++ b/code/game/machinery/telecomms/computers/logbrowser.dm @@ -1,215 +1,117 @@ - +#define MONITOR_MAINMENU 0 +#define MONITOR_SERVERLOGS 1 /obj/machinery/computer/telecomms/server name = "telecommunications server monitoring console" icon_screen = "comm_logs" - desc = "Has full access to all details and record of the telecommunications network it's monitoring." + desc = "A computer dedicated to monitoring telecommuncation server logs." - var/screen = 0 // the screen number: - var/list/servers = list() // the servers located by the computer + var/screen_state = MONITOR_MAINMENU // the screen state + var/list/cached_server_list = list() // The servers located by the computer var/obj/machinery/telecomms/server/SelectedServer var/network = "NULL" // the network to probe - var/temp = "" // temporary feedback messages - var/universal_translate = 0 // set to 1 if it can translate nonhuman speech + var/universal_translate = FALSE // set to TRUE if it can translate nonhuman speech req_access = list(ACCESS_TCOMSAT) circuit = /obj/item/circuitboard/computer/comm_server + tgui_id = "LogBrowser" -/obj/machinery/computer/telecomms/server/ui_interact(mob/user) - . = ..() - var/dat = "Telecommunication Server Monitor
Telecommunications Server Monitor
" - - switch(screen) - - - // --- Main Menu --- - - if(0) - dat += "
[temp]
" - dat += "
Current Network: [network]
" - if(servers.len) - dat += "
Detected Telecommunication Servers:" - dat += "
\[Flush Buffer\]" - - else - dat += "
No servers detected. Scan for servers: \[Scan\]" - - - // --- Viewing Server --- - - if(1) - dat += "
[temp]
" - dat += "
\[Main Menu\] \[Refresh\]
" - dat += "
Current Network: [network]" - dat += "
Selected Server: [SelectedServer.id]" - - if(SelectedServer.totaltraffic >= 1024) - dat += "
Total recorded traffic: [round(SelectedServer.totaltraffic / 1024)] Terrabytes

" - else - dat += "
Total recorded traffic: [SelectedServer.totaltraffic] Gigabytes

" - - dat += "Stored Logs:
    " - - var/i = 0 - for(var/datum/comm_log_entry/C in SelectedServer.log_entries) - i++ - - - // If the log is a speech file - if(C.input_type == "Speech File") - dat += "
  1. [C.name] \[X\]
    " - - // -- Determine race of orator -- - - var/mobtype = C.parameters["mobtype"] - var/race // The actual race of the mob - - if(ispath(mobtype, /mob/living/carbon/human) || ispath(mobtype, /mob/living/brain)) - race = "Humanoid" - - // NT knows a lot about slimes, but not aliens. Can identify slimes - else if(ispath(mobtype, /mob/living/simple_animal/slime)) - race = "Slime" - - else if(ispath(mobtype, /mob/living/carbon/monkey)) - race = "Monkey" - - // sometimes M gets deleted prematurely for AIs... just check the job - else if(ispath(mobtype, /mob/living/silicon) || C.parameters["job"] == "AI") - race = "Artificial Life" - - else if(isobj(mobtype)) - race = "Machinery" - - else if(ispath(mobtype, /mob/living/simple_animal)) - race = "Domestic Animal" - - else - race = "Unidentifiable" - - dat += "Data type: [C.input_type]
    " - dat += "Source: [C.parameters["name"]] (Job: [C.parameters["job"]])
    " - dat += "Class: [race]
    " - var/message = C.parameters["message"] - var/language = C.parameters["language"] - - // based on [/atom/movable/proc/lang_treat] - if (universal_translate || user.has_language(language)) - message = "\"[message]\"" - else if (!user.has_language(language)) - var/datum/language/D = GLOB.language_datum_instances[language] - message = "\"[D.scramble(message)]\"" - else if (language) - message = "(unintelligible)" - - dat += "Contents: [message]
    " - dat += "

  2. " - - else if(C.input_type == "Execution Error") - dat += "
  3. [C.name] \[X\]
    " - dat += "Error: \"[C.parameters["message"]]\"
    " - dat += "

  4. " - - else - dat += "
  5. [C.name] \[X\]
    " - dat += "Data type: [C.input_type]
    " - dat += "Contents: (unintelligible)
    " - dat += "

  6. " - +/obj/machinery/computer/telecomms/server/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user,src,ui) + if(!ui) + ui = new(user,src,"LogBrowser") + ui.open() - dat += "
" - - dat += "" - - user << browse(dat, "window=comm_monitor;size=575x400") - onclose(user, "server_control") - - temp = "" - return - - -/obj/machinery/computer/telecomms/server/Topic(href, href_list) +/obj/machinery/computer/telecomms/server/ui_act(action, list/params) if(..()) return - - - add_fingerprint(usr) - usr.set_machine(src) - - if(href_list["viewserver"]) - screen = 1 - for(var/obj/machinery/telecomms/T in servers) - if(T.id == href_list["viewserver"]) - SelectedServer = T - break - - if(href_list["operation"]) - switch(href_list["operation"]) - - if("release") - servers = list() - screen = 0 - - if("mainmenu") - screen = 0 - - if("scan") - if(servers.len > 0) - temp = "- FAILED: CANNOT PROBE WHEN BUFFER FULL -" - - else - for(var/obj/machinery/telecomms/server/T in urange(25, src)) - if(T.network == network) - servers.Add(T) - - if(!servers.len) - temp = "- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -" - else - temp = "- [servers.len] SERVERS PROBED & BUFFERED -" - - screen = 0 - - if(href_list["delete"]) - - if(!src.allowed(usr) && !(obj_flags & EMAGGED)) - to_chat(usr, span_danger("ACCESS DENIED.")) + switch(action) + if("Back") + screen_state = MONITOR_MAINMENU + SelectedServer = null + return TRUE + if("ViewServer") + var/id = params["server_id"] + if(!id) + return + for(var/machine in cached_server_list) + var/obj/machinery/telecomms/server/m = machine + if(m.id == id) + SelectedServer = m + break + if(SelectedServer) + screen_state = MONITOR_SERVERLOGS + return TRUE return - - if(SelectedServer) - - var/datum/comm_log_entry/D = SelectedServer.log_entries[text2num(href_list["delete"])] - - temp = "- DELETED ENTRY: [D.name] -" - - SelectedServer.log_entries.Remove(D) - qdel(D) - - else - temp = "- FAILED: NO SELECTED MACHINE -" - - if(href_list["network"]) - - var/newnet = stripped_input(usr, "Which network do you want to view?", "Comm Monitor", network) - - if(newnet && ((usr in range(1, src)) || issilicon(usr))) - if(length(newnet) > 15) - temp = "- FAILED: NETWORK TAG STRING TOO LENGHTLY -" - - else - - network = newnet - screen = 0 - servers = list() - temp = "- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -" - - updateUsrDialog() - return - -/obj/machinery/computer/telecomms/server/attackby() - . = ..() - updateUsrDialog() + if("DeleteLog") + if(!SelectedServer) + return + var/name = params["name"] + if(!name || !istext(name) || length(name) > 1024) + return + for(var/l in SelectedServer.log_entries) + var/datum/comm_log_entry/log = l + if(log.name == name) + SelectedServer.log_entries.Remove(log) + return TRUE + return + if("SetNetwork") + var/net = params["network"] + if(!net || !istext(net) || isnotpretty(net) || length(net) > 15) + return + network = params["network"] + return TRUE + if("Scan") + if(cached_server_list.len > 0) + cached_server_list = list() + for(var/obj/machinery/telecomms/server/T in range(TELECOMMS_SCAN_RANGE, src)) + if(T.network == network) + cached_server_list.Add(T) + return TRUE + if("Refresh") + return TRUE // Welp, you asked for it + +/obj/machinery/computer/telecomms/server/proc/generate_message(datum/comm_log_entry/log, mob/user) + if(!log.parameters["message"]) + return "***" + var/lang = log.parameters["language"] + if(universal_translate || !lang) + return log.parameters["message"] + if(user.has_language(lang)) + return log.parameters["message"] + else + var/datum/language/D = GLOB.language_datum_instances[lang] + return D.scramble(log.parameters["message"]) + +/obj/machinery/computer/telecomms/server/ui_data(mob/user) + var/list/data = list() + data["screen_state"] = screen_state + data["network"] = network + if(screen_state == MONITOR_MAINMENU) + var/list/servers = list() + for(var/machine in cached_server_list) + var/obj/machinery/telecomms/server/m = machine + servers.Add(m.id) + data["servers"] = servers + if(screen_state == MONITOR_SERVERLOGS) + data["selected_name"] = SelectedServer.id + data["totaltraffic"] = SelectedServer.log_entries.len + data["define_max_storage"] = SERVER_LOG_STORAGE_MAX + data["logs"] = list() + for(var/l in SelectedServer.log_entries) + var/datum/comm_log_entry/log = l + var/list/datalog = list() + datalog["is_corrupt"] = (log.input_type == "Corrupt File") + datalog["is_error"] = (log.input_type == "Execution Error") + datalog["name"] = log.parameters["name"] || "Unknown" + datalog["job"] = log.parameters["job"] || FALSE + datalog["message"] = generate_message(log,user) + datalog["packet_id"] = log.name // since this is some MD5 thing we can actually use this to ID this packet later in ui_act() + data["logs"] += list(datalog) + + return data + +#undef MONITOR_MAINMENU +#undef MONITOR_SERVERLOGS diff --git a/code/game/machinery/telecomms/machines/server.dm b/code/game/machinery/telecomms/machines/server.dm index 33004ee04952..9a22b11a1d86 100644 --- a/code/game/machinery/telecomms/machines/server.dm +++ b/code/game/machinery/telecomms/machines/server.dm @@ -28,7 +28,7 @@ totaltraffic += traffic // add current traffic to total traffic // Delete particularly old logs - if (log_entries.len >= 400) + if (log_entries.len >= SERVER_LOG_STORAGE_MAX) log_entries.Cut(1, 2) signal.data["server"] = src; //Yogs diff --git a/tgui/packages/tgui/interfaces/LogBrowser.js b/tgui/packages/tgui/interfaces/LogBrowser.js new file mode 100644 index 000000000000..ab56c803d179 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LogBrowser.js @@ -0,0 +1,164 @@ +import { useBackend } from '../backend'; +import { Box, Button, Divider, Section, LabeledList, Icon, NoticeBox, Input, ProgressBar, Tooltip, Flex } from '../components'; +import { Window } from '../layouts'; + + +const generate_server_list = (servers, act) => { + if (!servers || servers.length === 0) + { + return ( + +
+ No Servers stored in Buffer!
+ Please scan for servers to continue. +
+ ); + } + const mapped_servers = servers.map(server => { + return ( act('ViewServer', { 'server_id': server })}> + Select Server + + )} />); + }); + return mapped_servers; +}; + +const generate_logs = (logs, act) => { + if (!logs || logs.length === 0) + { + return ( + +
+ No logs detected!
+
+ ); + } + let mapped_logs = []; + for (const [index, log] of Object.entries(logs)) { + if (log["is_error"]) + { + mapped_logs.push( + + + +
+ {log["message"]} +
+
); + } + else + { + if (log["job"]) + { + mapped_logs.push( + + + {log["packet_id"]} + + + Name: {log["name"]}
+ Job: {log["job"]}
+ Received Message: {log["message"]}
+ +
+ ); + continue; + } + mapped_logs.push( + + + {log["packet_id"]} + + Name: {log["name"]}
+ Received Message: {log["message"]}
+ +
); + } + } + return mapped_logs; +}; + +export const LogBrowser = (props, context) => { + const { act, data } = useBackend(context); + const { + screen_state, + network, + // + servers, + // + selected_name, + logs, + totaltraffic, + define_max_storage, + } = data; + + if (screen_state === 0) // MAIN MENU + { + return ( + + + + Current network: { act('SetNetwork', { "network": value }); }} /> + + + +
+ {generate_server_list(servers, act)} +
+
+
+ ); + } + else if (screen_state === 1) // SERVER LOGS + { + return ( + + + + + + + + + + + + +
+  Network:
{network}

+  Server:
{selected_name}

+ +  Total Traffic Storage: + {totaltraffic} GB + + +
+
+ {generate_logs(logs, act)} +
+
+
+ ); + } + +}; diff --git a/yogstation.dme b/yogstation.dme index 1501f965b267..8e8a9d77e75f 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -138,6 +138,7 @@ #include "code\__DEFINES\{yogs_defines}\reactions.dm" #include "code\__DEFINES\{yogs_defines}\shuttles.dm" #include "code\__DEFINES\{yogs_defines}\spacepods.dm" +#include "code\__DEFINES\{yogs_defines}\telecomms.dm" #include "code\__DEFINES\{yogs_defines}\wires.dm" #include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_logging.dm"