aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auth.go6
-rw-r--r--auth_sqlite3.go30
-rw-r--r--chat.go2
-rw-r--r--client_conn.go8
-rw-r--r--cmd/mt-multiserver-proxy/proxy.go3
-rw-r--r--config.go13
-rw-r--r--connect.go2
-rw-r--r--gen_textures.go5
-rw-r--r--hop.go7
-rw-r--r--listen.go6
-rw-r--r--log.go2
-rw-r--r--perms.go5
-rw-r--r--players.go7
-rw-r--r--plugin_chatcmd.go8
-rw-r--r--proxy.go11
-rw-r--r--run.go12
-rw-r--r--server_conn.go5
17 files changed, 95 insertions, 37 deletions
diff --git a/auth.go b/auth.go
index 3334ebf..4feec77 100644
--- a/auth.go
+++ b/auth.go
@@ -5,7 +5,7 @@ import (
"time"
)
-var authIface AuthBackend
+var authIface authBackend
var ErrAuthBackendExists = errors.New("auth backend already set")
type user struct {
@@ -15,7 +15,7 @@ type user struct {
timestamp time.Time
}
-type AuthBackend interface {
+type authBackend interface {
Exists(name string) bool
Passwd(name string) (salt, verifier []byte, err error)
SetPasswd(name string, salt, verifier []byte) error
@@ -24,7 +24,7 @@ type AuthBackend interface {
Export() ([]user, error)
}
-func SetAuthBackend(ab AuthBackend) error {
+func setAuthBackend(ab authBackend) error {
if authIface != nil {
return ErrAuthBackendExists
}
diff --git a/auth_sqlite3.go b/auth_sqlite3.go
index 8574768..4ad9724 100644
--- a/auth_sqlite3.go
+++ b/auth_sqlite3.go
@@ -9,11 +9,12 @@ import (
_ "github.com/mattn/go-sqlite3"
)
-type AuthSQLite3 struct {
+type authSQLite3 struct {
db *sql.DB
}
-func (a AuthSQLite3) Exists(name string) bool {
+// Exists reports whether a user is registered.
+func (a authSQLite3) Exists(name string) bool {
if err := a.init(); err != nil {
return false
}
@@ -24,7 +25,8 @@ func (a AuthSQLite3) Exists(name string) bool {
return err == nil
}
-func (a AuthSQLite3) Passwd(name string) (salt, verifier []byte, err error) {
+// Passwd returns the SRP salt and verifier of a user or an error.
+func (a authSQLite3) Passwd(name string) (salt, verifier []byte, err error) {
if err = a.init(); err != nil {
return
}
@@ -35,7 +37,9 @@ func (a AuthSQLite3) Passwd(name string) (salt, verifier []byte, err error) {
return
}
-func (a AuthSQLite3) SetPasswd(name string, salt, verifier []byte) error {
+// SetPasswd creates a password entry if necessary
+// and sets the password of a user.
+func (a authSQLite3) SetPasswd(name string, salt, verifier []byte) error {
if err := a.init(); err != nil {
return err
}
@@ -50,7 +54,9 @@ func (a AuthSQLite3) SetPasswd(name string, salt, verifier []byte) error {
return nil
}
-func (a AuthSQLite3) Timestamp(name string) (time.Time, error) {
+// Timestamp returns the last time an authentication entry was accessed
+// or an error.
+func (a authSQLite3) Timestamp(name string) (time.Time, error) {
if err := a.init(); err != nil {
return time.Time{}, err
}
@@ -65,7 +71,9 @@ func (a AuthSQLite3) Timestamp(name string) (time.Time, error) {
return time.Parse("2006-01-02 15:04:05", tstr)
}
-func (a AuthSQLite3) Import(in []user) {
+// Import clears the database and and refills it with the passed
+// users.
+func (a authSQLite3) Import(in []user) {
if err := a.init(); err != nil {
return
}
@@ -78,7 +86,9 @@ func (a AuthSQLite3) Import(in []user) {
}
}
-func (a AuthSQLite3) Export() ([]user, error) {
+// Export returns data that can be processed by Import
+// or an error.
+func (a authSQLite3) Export() ([]user, error) {
if err := a.init(); err != nil {
return nil, err
}
@@ -119,11 +129,11 @@ func (a AuthSQLite3) Export() ([]user, error) {
return out, nil
}
-func (a AuthSQLite3) updateTimestamp(name string) {
+func (a authSQLite3) updateTimestamp(name string) {
a.db.Exec(`UPDATE user SET timestamp = datetime("now") WHERE name = ?;`, name)
}
-func (a *AuthSQLite3) init() error {
+func (a *authSQLite3) init() error {
executable, err := os.Executable()
if err != nil {
return err
@@ -148,6 +158,6 @@ func (a *AuthSQLite3) init() error {
return nil
}
-func (a AuthSQLite3) close() error {
+func (a authSQLite3) close() error {
return a.db.Close()
}
diff --git a/chat.go b/chat.go
index e355b2a..cf75594 100644
--- a/chat.go
+++ b/chat.go
@@ -8,6 +8,7 @@ import (
"github.com/anon55555/mt"
)
+// SendChatMsg sends a chat message to the ClientConn.
func (cc *ClientConn) SendChatMsg(msg ...string) {
cc.SendCmd(&mt.ToCltChatMsg{
Type: mt.SysMsg,
@@ -16,6 +17,7 @@ func (cc *ClientConn) SendChatMsg(msg ...string) {
})
}
+// Colorize returns the minetest-colorized version of the input.
func Colorize(text, color string) string {
return string(0x1b) + "(c@" + color + ")" + text + string(0x1b) + "(c@#FFF)"
}
diff --git a/client_conn.go b/client_conn.go
index f21d48c..343b323 100644
--- a/client_conn.go
+++ b/client_conn.go
@@ -23,6 +23,7 @@ const (
csSudo
)
+// A ClientConn is a connection to a minetest client.
type ClientConn struct {
mt.Peer
srv *ServerConn
@@ -60,6 +61,7 @@ type ClientConn struct {
modChs map[string]struct{}
}
+// Name returns the player name of the ClientConn.
func (cc *ClientConn) Name() string { return cc.name }
func (cc *ClientConn) server() *ServerConn {
@@ -69,6 +71,8 @@ func (cc *ClientConn) server() *ServerConn {
return cc.srv
}
+// ServerName returns the name of the current upstream server
+// of the ClientConn. It is empty if there is no upstream connection.
func (cc *ClientConn) ServerName() string {
srv := cc.server()
if srv != nil {
@@ -92,8 +96,12 @@ func (cc *ClientConn) setState(state clientState) {
cc.cstate = state
}
+// Init returns a channel that is closed
+// when the ClientConn enters the csActive state.
func (cc *ClientConn) Init() <-chan struct{} { return cc.initCh }
+// Log logs an interaction with the ClientConn.
+// dir indicates the direction of the interaction.
func (cc *ClientConn) Log(dir string, v ...interface{}) {
if cc.Name() != "" {
format := "{%s, %s} %s {←|⇶}"
diff --git a/cmd/mt-multiserver-proxy/proxy.go b/cmd/mt-multiserver-proxy/proxy.go
index 0d735be..f706643 100644
--- a/cmd/mt-multiserver-proxy/proxy.go
+++ b/cmd/mt-multiserver-proxy/proxy.go
@@ -1,3 +1,6 @@
+/*
+mt-multiserver-proxy starts the reverse proxy.
+*/
package main
import "github.com/HimbeerserverDE/mt-multiserver-proxy"
diff --git a/config.go b/config.go
index 3e5ab11..4fc8874 100644
--- a/config.go
+++ b/config.go
@@ -8,12 +8,6 @@ import (
"sync"
)
-const latestSerializeVer = 28
-const latestProtoVer = 39
-const maxPlayerNameLen = 20
-const playerNameChars = "^[a-zA-Z0-9-_]+$"
-const bytesPerMediaBunch = 5000
-
const defaultCmdPrefix = ">"
const defaultSendInterval = 0.09
const defaultUserLimit = 10
@@ -23,6 +17,8 @@ const defaultBindAddr = ":40000"
var config Config
var configMu sync.RWMutex
+// A Config contains information from the configuration file
+// that affects the way the proxy works.
type Config struct {
NoPlugins bool
CmdPrefix string
@@ -48,6 +44,8 @@ type Config struct {
UserGroups map[string]string
}
+// Conf returns a copy of the Config used by the proxy.
+// Any modifications will not affect the original Config.
func Conf() Config {
configMu.RLock()
defer configMu.RUnlock()
@@ -55,6 +53,9 @@ func Conf() Config {
return config
}
+// LoadConfig attempts to parse the configuration file.
+// It leaves the config unchanged if there is an error
+// and returns the error.
func LoadConfig() error {
configMu.Lock()
defer configMu.Unlock()
diff --git a/connect.go b/connect.go
index 4aa7a5d..7dfe277 100644
--- a/connect.go
+++ b/connect.go
@@ -6,7 +6,7 @@ import (
"github.com/anon55555/mt"
)
-func Connect(conn net.Conn, name string, cc *ClientConn) *ServerConn {
+func connect(conn net.Conn, name string, cc *ClientConn) *ServerConn {
cc.mu.RLock()
if cc.srv != nil {
cc.Log("<->", "already connected to server")
diff --git a/gen_textures.go b/gen_textures.go
index f2a9517..9838d10 100644
--- a/gen_textures.go
+++ b/gen_textures.go
@@ -1,7 +1,7 @@
//go:build ignore
-// This program generates default_textures.go. It can be invoked
-// by running go generate
+// gen_textures generates default_textures.go. It can be invoked
+// by running go generate.
package main
import (
@@ -23,6 +23,7 @@ func main() {
}
defer f.Close()
+ f.WriteString("// Code generated by gen_textures.go. DO NOT EDIT.\n")
f.WriteString("package proxy\n")
f.WriteString("\n")
f.WriteString("var defaultTextures = []mediaFile{\n")
diff --git a/hop.go b/hop.go
index b54277e..c065e16 100644
--- a/hop.go
+++ b/hop.go
@@ -8,6 +8,9 @@ import (
"github.com/anon55555/mt"
)
+// Hop connects the ClientConn to the specified upstream server.
+// At the moment the ClientConn is NOT fixed if an error occurs
+// so the player may have to reconnect.
func (cc *ClientConn) Hop(serverName string) error {
cc.hopMu.Lock()
defer cc.hopMu.Unlock()
@@ -32,7 +35,7 @@ func (cc *ClientConn) Hop(serverName string) error {
return fmt.Errorf("inexistent server")
}
- // This needs to be done before the serverConn is closed
+ // This needs to be done before the ServerConn is closed
// so the clientConn isn't closed by the packet handler
cc.server().mu.Lock()
cc.server().clt = nil
@@ -144,7 +147,7 @@ func (cc *ClientConn) Hop(serverName string) error {
return err
}
- Connect(conn, serverName, cc)
+ connect(conn, serverName, cc)
for ch := range cc.modChs {
cc.server().SendCmd(&mt.ToSrvJoinModChan{Channel: ch})
diff --git a/listen.go b/listen.go
index 72fa838..a1349d8 100644
--- a/listen.go
+++ b/listen.go
@@ -32,7 +32,7 @@ type listener struct {
clts map[*ClientConn]struct{}
}
-func Listen(pc net.PacketConn) *listener {
+func listen(pc net.PacketConn) *listener {
l := &listener{
Listener: mt.Listen(pc),
clts: make(map[*ClientConn]struct{}),
@@ -49,7 +49,7 @@ func Listen(pc net.PacketConn) *listener {
return l
}
-func (l *listener) Clts() map[*ClientConn]struct{} {
+func (l *listener) clients() map[*ClientConn]struct{} {
clts := make(map[*ClientConn]struct{})
l.mu.RLock()
@@ -62,7 +62,7 @@ func (l *listener) Clts() map[*ClientConn]struct{} {
return clts
}
-func (l *listener) Accept() (*ClientConn, error) {
+func (l *listener) accept() (*ClientConn, error) {
p, err := l.Listener.Accept()
if err != nil {
return nil, err
diff --git a/log.go b/log.go
index 2e16a73..bf8d68a 100644
--- a/log.go
+++ b/log.go
@@ -10,6 +10,8 @@ type LogWriter struct {
f *os.File
}
+// Write writes the input data to os.Stderr and the log file.
+// It returns the number of bytes written and an error.
func (lw *LogWriter) Write(p []byte) (n int, err error) {
n, err = os.Stderr.Write(p)
if err != nil {
diff --git a/perms.go b/perms.go
index 9190376..85091ae 100644
--- a/perms.go
+++ b/perms.go
@@ -1,7 +1,6 @@
package proxy
-import ()
-
+// Perms returns the permissions of the ClientConn.
func (cc *ClientConn) Perms() []string {
if cc.Name() == "" {
return []string{}
@@ -19,6 +18,8 @@ func (cc *ClientConn) Perms() []string {
return []string{}
}
+// HasPerms returns true if the ClientConn has all
+// of the specified permissions. Otherwise it returns false.
func (cc *ClientConn) HasPerms(want ...string) bool {
has := make(map[string]struct{})
for _, perm := range cc.Perms() {
diff --git a/players.go b/players.go
index 16db02a..18c3049 100644
--- a/players.go
+++ b/players.go
@@ -5,6 +5,8 @@ import "sync"
var players = make(map[string]struct{})
var playersMu sync.RWMutex
+// Players returns the names of all players
+// that are currently connected to the proxy.
func Players() map[string]struct{} {
playersMu.RLock()
defer playersMu.RUnlock()
@@ -17,11 +19,12 @@ func Players() map[string]struct{} {
return p
}
+// Clts returns all ClientConns currently connected to the proxy.
func Clts() map[*ClientConn]struct{} {
clts := make(map[*ClientConn]struct{})
lm := allListeners()
for l := range lm {
- for clt := range l.Clts() {
+ for clt := range l.clients() {
clts[clt] = struct{}{}
}
}
@@ -29,6 +32,8 @@ func Clts() map[*ClientConn]struct{} {
return clts
}
+// Find returns the ClientConn that has the specified player name.
+// If no ClientConn is found, nil is returned.
func Find(name string) *ClientConn {
for clt := range Clts() {
if clt.Name() == name {
diff --git a/plugin_chatcmd.go b/plugin_chatcmd.go
index 7df2365..85f2e11 100644
--- a/plugin_chatcmd.go
+++ b/plugin_chatcmd.go
@@ -2,6 +2,7 @@ package proxy
import "sync"
+// A ChatCmd holds information on how to handle a chat command.
type ChatCmd struct {
Name string
Perm string
@@ -14,6 +15,7 @@ var chatCmds map[string]ChatCmd
var chatCmdsMu sync.RWMutex
var chatCmdsOnce sync.Once
+// ChatCmds returns a map of all ChatCmds indexed by their names.
func ChatCmds() map[string]ChatCmd {
initChatCmds()
@@ -28,12 +30,14 @@ func ChatCmds() map[string]ChatCmd {
return cmds
}
+// ChatCmdExists reports if a ChatCmd exists.
func ChatCmdExists(name string) bool {
- cmds := ChatCmds()
- _, ok := cmds[name]
+ _, ok := ChatCmds()[name]
return ok
}
+// RegisterChatCmd adds a new ChatCmd. It returns true on success
+// and false if a command with the same name already exists.
func RegisterChatCmd(cmd ChatCmd) bool {
initChatCmds()
diff --git a/proxy.go b/proxy.go
new file mode 100644
index 0000000..d7a03cc
--- /dev/null
+++ b/proxy.go
@@ -0,0 +1,11 @@
+/*
+Package proxy is a minetest reverse proxy for multiple servers.
+It also provides an API for plugins.
+*/
+package proxy
+
+const latestSerializeVer = 28
+const latestProtoVer = 39
+const maxPlayerNameLen = 20
+const playerNameChars = "^[a-zA-Z0-9-_]+$"
+const bytesPerMediaBunch = 5000
diff --git a/run.go b/run.go
index cecfd44..19ab895 100644
--- a/run.go
+++ b/run.go
@@ -12,6 +12,8 @@ import (
"github.com/anon55555/mt"
)
+// Run initializes the proxy andstarts the main listener loop.
+// It blocks forever.
func Run() {
if err := LoadConfig(); err != nil {
log.Fatal("{←|⇶} ", err)
@@ -24,7 +26,7 @@ func Run() {
var err error
switch Conf().AuthBackend {
case "sqlite3":
- SetAuthBackend(AuthSQLite3{})
+ setAuthBackend(authSQLite3{})
default:
log.Fatal("{←|⇶} invalid auth backend")
}
@@ -39,7 +41,7 @@ func Run() {
log.Fatal("{←|⇶} ", err)
}
- l := Listen(pc)
+ l := listen(pc)
defer l.Close()
log.Print("{←|⇶} listen ", l.Addr())
@@ -49,7 +51,7 @@ func Run() {
signal.Notify(sig, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
<-sig
- clts := l.Clts()
+ clts := l.clients()
var wg sync.WaitGroup
wg.Add(len(clts))
@@ -75,7 +77,7 @@ func Run() {
}()
for {
- cc, err := l.Accept()
+ cc, err := l.accept()
if err != nil {
if errors.Is(err, net.ErrClosed) {
log.Print("{←|⇶} stop listening")
@@ -139,7 +141,7 @@ func Run() {
return
}
- Connect(conn, Conf().Servers[0].Name, cc)
+ connect(conn, Conf().Servers[0].Name, cc)
}()
}
diff --git a/server_conn.go b/server_conn.go
index c527dd6..5c9fa61 100644
--- a/server_conn.go
+++ b/server_conn.go
@@ -14,6 +14,7 @@ import (
"github.com/anon55555/mt/rudp"
)
+// A ServerConn is a connection to a minetest server.
type ServerConn struct {
mt.Peer
clt *ClientConn
@@ -63,8 +64,12 @@ func (sc *ServerConn) setState(state clientState) {
sc.cstate = state
}
+// Init returns a channel that is closed
+// when the ServerConn enters the csActive state.
func (sc *ServerConn) Init() <-chan struct{} { return sc.initCh }
+// Log logs an interaction with the ServerConn.
+// dir indicates the direction of the interaction.
func (sc *ServerConn) Log(dir string, v ...interface{}) {
if sc.client() != nil {
format := "%s {%s}"