From 05535e7c39daa7d37963dbe0b71c08c49e122fe1 Mon Sep 17 00:00:00 2001 From: Jens van de Wiel <85284773+JensvandeWiel@users.noreply.github.com> Date: Wed, 1 Nov 2023 22:10:28 +0100 Subject: [PATCH] Added rcon panel (#51) * Update README.md (#31) * added workflows * Update pull_request.yml (#38) * Update pull_request.yml * Update pull_request.yml * Add steamcmdpath config variable (#41) * added steamCMDPath config var for install * enhanced return val check steamCMD can return non null return value without failing * added better server state control * added support for spaces in server path wouldn't install to correct path because i had spaces in my username e.g.: C://Users/jens van de wiel the above would result in a error * initial version * added event when server exits outside of app * added confirmation modal for force stop * Update Server.tsx * Update README.md (#44) * Update README.md (#45) * Added button to open server files next to profile name (#47) * Revert "Added button to open server files next to profile name (#47)" This reverts commit a85bc582aea46d0910b8272f45b7cae7f3bebb39. * Revert "Update README.md (#45)" This reverts commit 088830315f89d9f11931eea6f7cba43e073d5b78. * Revert "Update README.md (#44)" This reverts commit 6aa9a0176420e0d2f3bf312849152a3e9f64340e. * Revert "added better server state control" This reverts commit 7b65ab8798a6a8d3a36be3e578e97b8bb9224697. * Revert "Add steamcmdpath config variable (#41)" This reverts commit 4ef591f96f93e06c8f7d2e4f4ca35d6901c4cee9. * Revert "Update pull_request.yml (#38)" This reverts commit 604eaba7c35ad584091cfd6fb5cf8c3c1f4a5353. * Revert "added workflows" This reverts commit 8ba0994f78b69507e60eb5e63a0bcfa5dcd35523. * Revert "Update README.md (#31)" This reverts commit ba504bfc9c7403c68185d44035a70770c2e73c8a. * added parsing for servermap * re-ordered server tabs * added onServerStart event * tab refactoring * added basic console layout * inherit serverstatus from parent * added basic terminal * added rcon console * refactored to do it the react way ;) * cleaned code * refacored it more into the react way * use one definition type * fix spacing --------- Co-authored-by: pepijn <68758035+ItsMePepijn@users.noreply.github.com> Co-authored-by: Ivan Oonincx <103519966+Ivan0348@users.noreply.github.com> --- frontend/src/pages/Server.tsx | 19 ++-- frontend/src/pages/server/Administration.tsx | 9 ++ frontend/src/pages/server/Console.tsx | 98 ++++++++++++++++++++ frontend/src/pages/server/General.tsx | 6 +- frontend/src/pages/server/Settings.tsx | 9 -- frontend/tailwind.config.cjs | 6 +- go.mod | 1 + go.sum | 2 + helpers/rcon.go | 22 +++++ server/helpers.go | 10 +- server/server.go | 1 + 11 files changed, 163 insertions(+), 20 deletions(-) create mode 100644 frontend/src/pages/server/Administration.tsx create mode 100644 frontend/src/pages/server/Console.tsx delete mode 100644 frontend/src/pages/server/Settings.tsx create mode 100644 helpers/rcon.go diff --git a/frontend/src/pages/Server.tsx b/frontend/src/pages/Server.tsx index 88d4fb2..36e84aa 100644 --- a/frontend/src/pages/Server.tsx +++ b/frontend/src/pages/Server.tsx @@ -12,7 +12,7 @@ import { TabList, Tabs, Tooltip } from "@mui/joy"; -import {Settings} from "./server/Settings"; +import {Administration} from "./server/Administration"; import {General} from "./server/General"; import {useEffect, useState} from "react"; import {server} from "../../wailsjs/go/models"; @@ -27,6 +27,7 @@ import {InstallUpdater} from "./InstallUpdater"; import {useAlert} from "../components/AlertProvider"; import {BrowserOpenURL, EventsOff, EventsOn} from "../../wailsjs/runtime"; import {IconAlertCircleFilled, IconExternalLink} from "@tabler/icons-react"; +import {Console} from "./server/Console"; type Props = { @@ -73,6 +74,13 @@ export const Server = ({id, className}: Props) => { EventsOn("onServerExit", () => setServerStatus(false)) return () => EventsOff("onServerExit") }, []); + + useEffect(() => { + if (serv.id >= 0) { + refreshServerStatus() + } + }, [serv]); + //endregion function onServerStartButtonClicked() { @@ -137,14 +145,13 @@ export const Server = ({id, className}: Props) => { + Console General - Settings - Mods - Plugins - Modifiers + Administration + - + ) : ( setIsInstalled(true)}/>)} ); diff --git a/frontend/src/pages/server/Administration.tsx b/frontend/src/pages/server/Administration.tsx new file mode 100644 index 0000000..9e014d4 --- /dev/null +++ b/frontend/src/pages/server/Administration.tsx @@ -0,0 +1,9 @@ +import {TabPanel} from "@mui/joy"; + +export function Administration() { + return ( + + + + ); +} \ No newline at end of file diff --git a/frontend/src/pages/server/Console.tsx b/frontend/src/pages/server/Console.tsx new file mode 100644 index 0000000..1ff5027 --- /dev/null +++ b/frontend/src/pages/server/Console.tsx @@ -0,0 +1,98 @@ +import { Button, Input, TabPanel } from "@mui/joy"; +import React, { useEffect, useRef, useState } from "react"; +import { server } from "../../../wailsjs/go/models"; +import { SendRconCommand } from "../../../wailsjs/go/helpers/HelpersController"; + +type Message = { + text: string; + sender: string; +}; + +type Props = { + setServ: React.Dispatch>; + serv: server.Server; + serverStatus: boolean; +}; + +export function Console({ setServ, serv, serverStatus }: Props) { + const [input, setInput] = useState(""); + const [messages, setMessages] = useState([]); + + const terminalRef = useRef(null); + + const writeToConsole = (text: string, sender: string = "user") => { + const newMessage: Message = { text, sender }; + setMessages((prevMessages) => [...prevMessages, newMessage]); + }; + + const doRconCommand = (text: string) => { + SendRconCommand(text, serv.ipAddress, serv.rconPort, serv.adminPassword) + .then((resp) => writeToConsole(resp, "server")) + .catch((err) => writeToConsole("error sending command: " + err, "server")); + }; + + useEffect(() => { + if (terminalRef.current) { + terminalRef.current.scrollTop = terminalRef.current.scrollHeight; + } + }, [messages]); + + if (serverStatus) { + return ( + + + {messages.map((message, index) => ( + + {message.sender === "server" ? ( + {message.text} + ) : ( + + [{message.sender}]{" "} + $ {message.text} + + )} + + ))} + + setInput(e.target.value)} + startDecorator={$} + endDecorator={ + { + writeToConsole(input); + setInput(""); + doRconCommand(input); + }} + className={"m-1"} + > + Send + + } + onKeyPress={(e) => { + if (e.key === "Enter") { + writeToConsole(input, "user"); + doRconCommand(input); + setInput(""); + } + }} + > + + ); + } else { + return ( + + + Server is not running + + + ); + } +} diff --git a/frontend/src/pages/server/General.tsx b/frontend/src/pages/server/General.tsx index 7e41562..7a4e045 100644 --- a/frontend/src/pages/server/General.tsx +++ b/frontend/src/pages/server/General.tsx @@ -42,7 +42,7 @@ export function General({serv, setServ}: Props) { }, []); return ( - + {/* Server Name and Passwords */} @@ -80,7 +80,7 @@ export function General({serv, setServ}: Props) { IP Address: { const newValue = value; setServ( @@ -93,7 +93,7 @@ export function General({serv, setServ}: Props) { ) }} > - 0.0.0.0 - All + {/*0.0.0.0 - All*/} {interfaceElements} Ports: diff --git a/frontend/src/pages/server/Settings.tsx b/frontend/src/pages/server/Settings.tsx deleted file mode 100644 index d254c94..0000000 --- a/frontend/src/pages/server/Settings.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import {TabPanel} from "@mui/joy"; - -export function Settings() { - return ( - - - - ); -} \ No newline at end of file diff --git a/frontend/tailwind.config.cjs b/frontend/tailwind.config.cjs index 75fd2b7..d1b9227 100644 --- a/frontend/tailwind.config.cjs +++ b/frontend/tailwind.config.cjs @@ -4,7 +4,11 @@ module.exports = { "./src/**/*.{js,jsx,ts,tsx}", ], theme: { - extend: {}, + extend: { + fontFamily: { + 'jetbrains': ['JetBrains Mono', 'monospace'], + }, + }, }, plugins: [], diff --git a/go.mod b/go.mod index da94d64..ba02ec5 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.18 require ( github.com/adrg/xdg v0.4.0 + github.com/gorcon/rcon v1.3.4 github.com/jensvandewiel/gosteamcmd v0.1.2 github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19 github.com/sethvargo/go-password v0.2.0 diff --git a/go.sum b/go.sum index b4ee6bf..8450af4 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorcon/rcon v1.3.4 h1:TExNhWI2mJlqpCg49vajUgznvEZbEzQWKujY1Sy+/AY= +github.com/gorcon/rcon v1.3.4/go.mod h1:46+oSXgPwlRAkcAPStkNnIL1dlcxJweKVNWshy3hDJI= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= github.com/jensvandewiel/gosteamcmd v0.1.2 h1:NHichoj0v3GvSVN2Fn36dSOLosHAytpaKnLnDHTMQPI= diff --git a/helpers/rcon.go b/helpers/rcon.go new file mode 100644 index 0000000..25ba707 --- /dev/null +++ b/helpers/rcon.go @@ -0,0 +1,22 @@ +package helpers + +import ( + "fmt" + "github.com/gorcon/rcon" + "strconv" +) + +func (c *HelpersController) SendRconCommand(command string, ip string, port int, password string) (string, error) { + conn, err := rcon.Dial(ip+":"+strconv.Itoa(port), password) + if err != nil { + return "", fmt.Errorf("failed connectting to rcon server: %v", err) + } + defer conn.Close() + + response, err := conn.Execute(command) + if err != nil { + return "", fmt.Errorf("failed executing rcon command: %v", err) + } + + return response, nil +} diff --git a/server/helpers.go b/server/helpers.go index 0383fa0..94b4539 100644 --- a/server/helpers.go +++ b/server/helpers.go @@ -84,7 +84,9 @@ func CheckIfServerCorrect(server Server) error { return fmt.Errorf("Checks failed: Server.AdminPassword is too short.") } - if server.IpAddress != "0.0.0.0" { + if server.IpAddress == "" { + return fmt.Errorf("Check failed: Ip address is empty") + } else { interfaces, err := helpers.GetNetworkInterfaces() if err != nil { @@ -109,6 +111,12 @@ func CheckIfServerCorrect(server Server) error { } } + if server.ServerMap == "" { + return fmt.Errorf("server.serverMap is empty") + } else if server.ServerMap != "TheIsland_WP" { + return fmt.Errorf("server.serverMap has invalid value: %v", server.ServerMap) + } + return nil } diff --git a/server/server.go b/server/server.go index 1edf473..859d98e 100644 --- a/server/server.go +++ b/server/server.go @@ -74,6 +74,7 @@ func (s *Server) Start() error { if err != nil { return fmt.Errorf("error starting server: %v", err) } + runtime.EventsEmit(s.ctx, "onServerStart", s.Id) go func() { _ = s.Command.Wait()
Server is not running