-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite and update the code for the modern world.
- Loading branch information
Showing
23 changed files
with
653 additions
and
465 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package main | ||
|
||
import ( | ||
_ "github.com/icedream/icecon/internal/ui/windows" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"strings" | ||
|
||
"github.com/alecthomas/kingpin/v2" | ||
"github.com/icedream/icecon/internal/rcon" | ||
"github.com/icedream/icecon/internal/ui" | ||
|
||
_ "github.com/icedream/icecon/internal/ui/console" | ||
) | ||
|
||
var ( | ||
flagCommand = kingpin.Flag("command", | ||
"Run a one-off command and then exit."). | ||
Short('c').String() | ||
argAddress = kingpin.Arg("address", | ||
"Server IP/hostname and port, written as \"server:port\".") | ||
argPassword = kingpin.Arg("password", "The RCON password.") | ||
|
||
password string | ||
) | ||
|
||
func usage() { | ||
kingpin.Usage() | ||
} | ||
|
||
var ( | ||
hasGraphicalUI = ui.HasGraphicalUI() | ||
flagGui *bool | ||
) | ||
|
||
func init() { | ||
// only provide -gui/-g flag if there is a graphical user interface available | ||
if hasGraphicalUI { | ||
flagGui = kingpin. | ||
Flag("gui", "Run as GUI (runs automatically as GUI if no arguments given, ignored if command flag used)"). | ||
Short('g').Bool() | ||
} | ||
} | ||
|
||
func main() { | ||
fmt.Println("IceCon - Icedream's RCON Client") | ||
fmt.Println("\t\u00A9 2016-2024 Carl Kittelberger/Icedream") | ||
fmt.Println() | ||
|
||
argAddressTCP := argAddress.TCP() | ||
argPasswordStr := argPassword.String() | ||
|
||
kingpin.Parse() | ||
|
||
// If no arguments, fall back to running the shell | ||
wantGui := (*argAddressTCP == nil && *flagCommand == "") || *flagGui | ||
|
||
// Command-line shell doesn't support starting up without arguments | ||
// but graphical Windows UI does | ||
if !(hasGraphicalUI && wantGui) { | ||
argAddress = argAddress.Required() | ||
argPassword = argPassword.Required() | ||
kingpin.Parse() | ||
} | ||
|
||
// Initialize socket | ||
rconClient := rcon.NewRconClient() | ||
rconClient.InitSocket() | ||
defer rconClient.Release() | ||
|
||
// Set target address if given | ||
if *argAddressTCP != nil { | ||
rconClient.SetSocketAddr((*argAddressTCP).String()) | ||
} | ||
|
||
// Get password | ||
password = *argPasswordStr | ||
|
||
// Run one-off command? | ||
if *flagCommand != "" { | ||
// Send | ||
err := rconClient.Send(*flagCommand) | ||
if err != nil { | ||
log.Fatal(err) | ||
return | ||
} | ||
|
||
// Receive | ||
msg, err := rconClient.Receive() | ||
if err != nil { | ||
log.Fatal(err) | ||
return | ||
} | ||
switch strings.ToLower(msg.Name) { | ||
case "print": | ||
fmt.Println(string(msg.Data)) | ||
} | ||
return | ||
} | ||
|
||
// Which UI should be run? | ||
log.Println("Starting user interface.") | ||
if err := ui.Run(rconClient, wantGui); err != nil { | ||
log.Fatal("User interface failed:", err) | ||
return | ||
} | ||
log.Println("Done.") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package main | ||
|
||
//go:generate go run -mod=mod github.com/josephspurrier/goversioninfo/cmd/goversioninfo -manifest "../../rsrc/app.manifest" -icon "../../rsrc/app.ico" -o "rsrc_windows_386.syso" | ||
//go:generate go run -mod=mod github.com/josephspurrier/goversioninfo/cmd/goversioninfo -manifest "../../rsrc/app.manifest" -icon "../../rsrc/app.ico" -o "rsrc_windows_amd64.syso" -64 |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,20 @@ | ||
module github.com/icedream/icecon | ||
|
||
go 1.12 | ||
go 1.22 | ||
|
||
require ( | ||
github.com/alecthomas/kingpin/v2 v2.4.0 | ||
github.com/icedream/go-q3net v0.1.0 | ||
github.com/icedream/ui2walk v0.0.0-20160513005918-6f3bcb07a270 | ||
github.com/josephspurrier/goversioninfo v1.4.0 | ||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794 | ||
) | ||
|
||
require ( | ||
github.com/akavel/rsrc v0.10.2 // indirect | ||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect | ||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect | ||
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect | ||
golang.org/x/sys v0.12.0 // indirect | ||
gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package rcon | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"fmt" | ||
"net" | ||
"strings" | ||
|
||
quake "github.com/icedream/go-q3net" | ||
) | ||
|
||
type Client struct { | ||
address *net.UDPAddr | ||
addressStr string | ||
password string | ||
|
||
socket *net.UDPConn | ||
socketBuffer []byte | ||
} | ||
|
||
func NewRconClient() *Client { | ||
socketBuffer := make([]byte, 64*1024) | ||
return &Client{ | ||
socketBuffer: socketBuffer, | ||
} | ||
} | ||
|
||
func (c *Client) SetSocketAddr(addr string) (err error) { | ||
newAddr, err := net.ResolveUDPAddr("udp", addr) | ||
if err != nil { | ||
return | ||
} | ||
|
||
c.address, c.addressStr = newAddr, addr | ||
|
||
return | ||
} | ||
|
||
func (c *Client) SetPassword(pw string) { | ||
c.password = pw | ||
} | ||
|
||
func (c *Client) Address() *net.UDPAddr { | ||
return c.address | ||
} | ||
|
||
func (c *Client) AddressString() string { | ||
return c.addressStr | ||
} | ||
|
||
func (c *Client) Password() string { | ||
return c.password | ||
} | ||
|
||
func (c *Client) InitSocket() (err error) { | ||
c.socket, err = net.ListenUDP("udp", nil) | ||
if err != nil { | ||
return | ||
} | ||
|
||
return | ||
} | ||
|
||
func (c *Client) udpReceiveAndUnmarshal() (msg *quake.Message, err error) { | ||
length, _, err := c.socket.ReadFromUDP(c.socketBuffer) | ||
if err != nil { | ||
return | ||
} | ||
|
||
msg, err = quake.UnmarshalMessage(c.socketBuffer[0:length]) | ||
if err != nil { | ||
return | ||
} | ||
return | ||
} | ||
|
||
func (c *Client) Receive() (msg *quake.Message, err error) { | ||
msg, err = c.udpReceiveAndUnmarshal() | ||
if err != nil { | ||
return | ||
} | ||
if !strings.EqualFold(msg.Name, "print") { | ||
err = errors.New("rcon: Unexpected response from server: " + msg.Name) | ||
} | ||
return | ||
} | ||
|
||
func (c *Client) Send(input string) (err error) { | ||
buf := new(bytes.Buffer) | ||
msg := &quake.Message{ | ||
Header: quake.OOBHeader, | ||
Name: "rcon", | ||
Data: []byte(fmt.Sprintf("%s %s", c.password, input)), | ||
} | ||
if err = msg.Marshal(buf); err != nil { | ||
return | ||
} | ||
if _, err = c.socket.WriteToUDP(buf.Bytes(), c.address); err != nil { | ||
return | ||
} | ||
return | ||
} | ||
|
||
func (c *Client) Release() { | ||
if c.socket != nil { | ||
c.socket.Close() | ||
c.socket = nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package ui | ||
|
||
import ( | ||
"bufio" | ||
"log" | ||
"os" | ||
"strings" | ||
|
||
"github.com/icedream/icecon/internal/rcon" | ||
"github.com/icedream/icecon/internal/ui" | ||
) | ||
|
||
func init() { | ||
ui.RegisterUserInterface(ui.UserInterfaceProvider{ | ||
New: NewConsoleUserInterface, | ||
}) | ||
} | ||
|
||
type consoleUserInterface struct { | ||
rcon *rcon.Client | ||
bufferedStdin *bufio.Reader | ||
} | ||
|
||
func NewConsoleUserInterface(rconClient *rcon.Client) (ui.UserInterface, error) { | ||
return &consoleUserInterface{ | ||
rcon: rconClient, | ||
bufferedStdin: bufio.NewReader(os.Stdin), | ||
}, nil | ||
} | ||
|
||
func (ui *consoleUserInterface) readLineFromInput() (input string, err error) { | ||
for { | ||
if line, hasMoreInLine, err := ui.bufferedStdin.ReadLine(); err != nil { | ||
return input, err | ||
} else { | ||
input += string(line) | ||
if !hasMoreInLine { | ||
break | ||
} | ||
} | ||
} | ||
return | ||
} | ||
|
||
func (ui *consoleUserInterface) Run() error { | ||
for { | ||
input, err := ui.readLineFromInput() | ||
if err != nil { | ||
log.Fatal(err) | ||
continue | ||
} | ||
|
||
// "quit" => exit shell | ||
if strings.EqualFold(strings.TrimSpace(input), "quit") { | ||
break | ||
} | ||
|
||
err = ui.rcon.Send(input) | ||
if err != nil { | ||
log.Println(err) | ||
continue | ||
} | ||
msg, err := ui.rcon.Receive() | ||
if err != nil { | ||
log.Println(err) | ||
continue | ||
} | ||
switch strings.ToLower(msg.Name) { | ||
case "print": | ||
log.Println(string(msg.Data)) | ||
} | ||
} | ||
return nil | ||
} |
Oops, something went wrong.