Skip to content

Commit

Permalink
Refactoring, cleanup, test backfilling
Browse files Browse the repository at this point in the history
  • Loading branch information
jhalter committed Jun 24, 2024
1 parent a55350d commit a2ef262
Show file tree
Hide file tree
Showing 28 changed files with 2,630 additions and 2,131 deletions.
51 changes: 35 additions & 16 deletions cmd/mobius-hotline-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,30 @@ var logLevels = map[string]slog.Level{
"error": slog.LevelError,
}

// Values swapped in by go-releaser at build time
var (
version = "dev"
commit = "none"
date = "unknown"
)

func main() {
ctx, cancel := context.WithCancel(context.Background())
ctx, _ := context.WithCancel(context.Background())

// TODO: implement graceful shutdown by closing context
// c := make(chan os.Signal, 1)
// signal.Notify(c, os.Interrupt)
// defer func() {
// signal.Stop(c)
// cancel()
// }()
// go func() {
// select {
// case <-c:
// cancel()
// case <-ctx.Done():
// }
// }()
//c := make(chan os.Signal, 1)
//signal.Notify(c, os.Interrupt)
//defer func() {
// signal.Stop(c)
// cancel()
//}()
//go func() {
// select {
// case <-c:
// cancel()
// case <-ctx.Done():
// }
//}()

netInterface := flag.String("interface", "", "IP addr of interface to listen on. Defaults to all interfaces.")
basePort := flag.Int("bind", defaultPort, "Base Hotline server port. File transfer port is base port + 1.")
Expand Down Expand Up @@ -129,7 +130,7 @@ func main() {
)

// Serve Hotline requests until program exit
log.Fatal(srv.ListenAndServe(ctx, cancel))
log.Fatal(srv.ListenAndServe(ctx))
}

type statHandler struct {
Expand Down Expand Up @@ -166,7 +167,25 @@ func defaultConfigPath() string {
return cfgPath
}

// TODO: Simplify this mess. Why is it so difficult to recursively copy a directory?
// copyFile copies a file from src to dst. If dst does not exist, it is created.
func copyFile(src, dst string) error {
sourceFile, err := os.Open(src)
if err != nil {
return err
}
defer sourceFile.Close()

destinationFile, err := os.Create(dst)
if err != nil {
return err
}
defer destinationFile.Close()

_, err = io.Copy(destinationFile, sourceFile)
return err
}

// copyDir recursively copies a directory tree, attempting to preserve permissions.
func copyDir(src, dst string) error {
entries, err := cfgTemplate.ReadDir(src)
if err != nil {
Expand Down
15 changes: 10 additions & 5 deletions hotline/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"golang.org/x/crypto/bcrypt"
"io"
"log"
"slices"
)

Expand All @@ -20,6 +19,15 @@ type Account struct {
readOffset int // Internal offset to track read progress
}

func NewAccount(login, name, password string, access accessBitmap) *Account {
return &Account{
Login: login,
Name: name,
Password: hashAndSalt([]byte(password)),
Access: access,
}
}

// Read implements io.Reader interface for Account
func (a *Account) Read(p []byte) (int, error) {
fields := []Field{
Expand Down Expand Up @@ -57,10 +65,7 @@ func (a *Account) Read(p []byte) (int, error) {

// hashAndSalt generates a password hash from a users obfuscated plaintext password
func hashAndSalt(pwd []byte) string {
hash, err := bcrypt.GenerateFromPassword(pwd, bcrypt.MinCost)
if err != nil {
log.Println(err)
}
hash, _ := bcrypt.GenerateFromPassword(pwd, bcrypt.MinCost)

return string(hash)
}
31 changes: 15 additions & 16 deletions hotline/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,23 @@ type Client struct {
Connection net.Conn
Logger *slog.Logger
Pref *ClientPrefs
Handlers map[uint16]ClientHandler
activeTasks map[uint32]*Transaction
Handlers map[[2]byte]ClientHandler
activeTasks map[[4]byte]*Transaction
}

type ClientHandler func(context.Context, *Client, *Transaction) ([]Transaction, error)

func (c *Client) HandleFunc(transactionID uint16, handler ClientHandler) {
c.Handlers[transactionID] = handler
func (c *Client) HandleFunc(tranType [2]byte, handler ClientHandler) {
c.Handlers[tranType] = handler
}

func NewClient(username string, logger *slog.Logger) *Client {
c := &Client{
Logger: logger,
activeTasks: make(map[uint32]*Transaction),
Handlers: make(map[uint16]ClientHandler),
activeTasks: make(map[[4]byte]*Transaction),
Handlers: make(map[[2]byte]ClientHandler),
Pref: &ClientPrefs{Username: username},
}
c.Pref = &ClientPrefs{Username: username}

return c
}
Expand Down Expand Up @@ -79,8 +79,8 @@ func (c *Client) Connect(address, login, passwd string) (err error) {
// Authenticate (send TranLogin 107)

err = c.Send(
*NewTransaction(
TranLogin, nil,
NewTransaction(
TranLogin, [2]byte{0, 0},
NewField(FieldUserName, []byte(c.Pref.Username)),
NewField(FieldUserIconID, c.Pref.IconBytes()),
NewField(FieldUserLogin, encodeString([]byte(login))),
Expand All @@ -102,7 +102,7 @@ const keepaliveInterval = 300 * time.Second
func (c *Client) keepalive() error {
for {
time.Sleep(keepaliveInterval)
_ = c.Send(*NewTransaction(TranKeepAlive, nil))
_ = c.Send(NewTransaction(TranKeepAlive, [2]byte{}))
}
}

Expand Down Expand Up @@ -146,7 +146,7 @@ func (c *Client) Send(t Transaction) error {

// if transaction is NOT reply, add it to the list to transactions we're expecting a response for
if t.IsReply == 0 {
c.activeTasks[binary.BigEndian.Uint32(t.ID[:])] = &t
c.activeTasks[t.ID] = &t
}

n, err := io.Copy(c.Connection, &t)
Expand All @@ -165,16 +165,15 @@ func (c *Client) Send(t Transaction) error {
func (c *Client) HandleTransaction(ctx context.Context, t *Transaction) error {
var origT Transaction
if t.IsReply == 1 {
requestID := binary.BigEndian.Uint32(t.ID[:])
origT = *c.activeTasks[requestID]
origT = *c.activeTasks[t.ID]
t.Type = origT.Type
}

if handler, ok := c.Handlers[binary.BigEndian.Uint16(t.Type[:])]; ok {
if handler, ok := c.Handlers[t.Type]; ok {
c.Logger.Debug(
"Received transaction",
"IsReply", t.IsReply,
"type", binary.BigEndian.Uint16(t.Type[:]),
"type", t.Type[:],
)
outT, err := handler(ctx, c, t)
if err != nil {
Expand All @@ -189,7 +188,7 @@ func (c *Client) HandleTransaction(ctx context.Context, t *Transaction) error {
c.Logger.Debug(
"Unimplemented transaction type",
"IsReply", t.IsReply,
"type", binary.BigEndian.Uint16(t.Type[:]),
"type", t.Type[:],
)
}

Expand Down
Loading

0 comments on commit a2ef262

Please sign in to comment.