Explore rewriting Auth server in Go

This commit is contained in:
Artem Titoulenko 2021-11-10 13:46:52 -05:00
parent f2ab2ced48
commit 27aea95084
4 changed files with 170 additions and 0 deletions

3
go.mod Normal file
View file

@ -0,0 +1,3 @@
module aim-oscar
go 1.16

122
main.go Normal file
View file

@ -0,0 +1,122 @@
package main
import (
"bytes"
"context"
"encoding/binary"
"fmt"
"io"
"log"
"net"
"os"
"os/signal"
"syscall"
)
const (
SRV_HOST = ""
SRV_PORT = "5190"
SRV_ADDRESS = SRV_HOST + ":" + SRV_PORT
)
type Session struct {
Conn net.Conn
GreetedClient bool
}
func NewSession(conn net.Conn) *Session {
return &Session{
Conn: conn,
GreetedClient: false,
}
}
func (s *Session) Send(bytes []byte) {
fmt.Printf("-> %v\n%s\n\n", s.Conn.RemoteAddr(), prettyBytes(bytes))
s.Conn.Write(bytes)
}
func main() {
listener, err := net.Listen("tcp", SRV_ADDRESS)
if err != nil {
fmt.Println("Error listening: ", err.Error())
os.Exit(1)
}
defer listener.Close()
exitChan := make(chan os.Signal, 1)
signal.Notify(exitChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM, syscall.SIGABRT)
go func() {
<-exitChan
fmt.Println("Shutting down")
os.Exit(1)
}()
fmt.Println("OSCAR listening on " + SRV_ADDRESS)
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting connection: ", err.Error())
os.Exit(1)
}
ctx := context.WithValue(context.Background(), "session", NewSession(conn))
log.Printf("Connection from %v", conn.RemoteAddr())
go handleTCPConnection(ctx, conn)
}
}
func handleTCPConnection(ctx context.Context, conn net.Conn) {
defer (func() {
recover()
conn.Close()
log.Printf("Closed connection to %v", conn.RemoteAddr())
})()
buf := make([]byte, 1024)
for {
session := ctx.Value("session").(*Session)
if !session.GreetedClient {
// send a hello
hello := []byte{0x2a, 1, 0, 0, 0, 4, 0, 0, 0, 1}
session.Send(hello)
session.GreetedClient = true
}
n, err := conn.Read(buf)
if err != nil && err != io.EOF {
log.Println("Read Error: ", err.Error())
return
}
if n == 0 {
return
}
fmt.Printf("%v ->\n%s\n\n", conn.RemoteAddr(), prettyBytes(buf[:n]))
handleMessage(ctx, buf[:n])
}
}
func handleMessage(ctx context.Context, buf []byte) {
messageBuf := bytes.NewBuffer(buf)
start, err := messageBuf.ReadByte()
panicIfError(err)
if start != 0x2a {
log.Println("FLAP message missing leading 0x2a")
return
}
// Start parsing FLAP header
channel := mustReadNBytes(messageBuf, 1)[0]
log.Println("Message for channel: ", channel)
datagramSeqNum := mustReadNBytes(messageBuf, 2)
log.Println("Datagram Sequence Number: ", binary.BigEndian.Uint16(datagramSeqNum))
dataLength := mustReadNBytes(messageBuf, 2)
log.Println("Data Length: ", binary.BigEndian.Uint16(dataLength))
}

View file

@ -5,6 +5,7 @@
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"dev:tsc": "tsc --watch", "dev:tsc": "tsc --watch",
"dev:nodemon:auth-go": "nodemon --watch ./ -e go --delay 200ms --exec 'go run *.go || exit 1' --signal SIGTERM",
"dev:nodemon:auth": "nodemon --watch ./dist --delay 200ms dist/src/main-auth.js", "dev:nodemon:auth": "nodemon --watch ./dist --delay 200ms dist/src/main-auth.js",
"dev:nodemon:chat": "nodemon --watch ./dist --delay 200ms dist/src/main-chat.js", "dev:nodemon:chat": "nodemon --watch ./dist --delay 200ms dist/src/main-chat.js",
"start": "tsc && node ./dist/index.js" "start": "tsc && node ./dist/index.js"

44
util.go Normal file
View file

@ -0,0 +1,44 @@
package main
import (
"bytes"
"encoding/hex"
"fmt"
"io"
)
func prettyBytes(bytes []byte) string {
res := ""
hexStr := hex.EncodeToString(bytes)
for i := 0; i < len(hexStr); i++ {
if i > 0 && i%16 == 0 {
res += "\n"
} else if i > 0 && i%2 == 0 {
res += " "
}
res += string(hexStr[i])
}
return res
}
func printBytes(bytes []byte) {
fmt.Printf("%s\n", prettyBytes(bytes))
}
func panicIfError(err error) {
if err != nil {
panic(err)
}
}
func readNBytes(buf *bytes.Buffer, n int) ([]byte, error) {
res := make([]byte, n)
_, err := io.ReadFull(buf, res)
return res, err
}
func mustReadNBytes(buf *bytes.Buffer, n int) []byte {
res, err := readNBytes(buf, n)
panicIfError(err)
return res
}