master
george 3 years ago
commit 178a583e76

@ -0,0 +1,36 @@
package main
import (
"fmt"
"os"
testclient "testclient/internal"
)
func main() {
if err := testclient.InitHttpClient(); err != nil {
fmt.Fprintln(os.Stderr, "error initialising http client", err.Error())
os.Exit(1)
}
if err := testclient.Initialise(); err != nil {
fmt.Fprintln(os.Stderr, "Error setting up tester:", err.Error())
os.Exit(1)
}
testclient.Register()
testclient.WsConnect()
if testclient.LoadMessages {
testclient.LoadDefaultMessages()
}
fmt.Println("username:", testclient.Username)
for {
select {
case <-testclient.Done:
fmt.Println("websocket connection closed")
return
case l := <-testclient.Line:
testclient.SendMessage(l)
}
}
}

@ -0,0 +1,5 @@
module testclient
go 1.18
require github.com/gorilla/websocket v1.5.0

@ -0,0 +1,2 @@
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=

@ -0,0 +1,151 @@
package testclient
import (
"bufio"
"flag"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"os"
"time"
)
var chatAddress = "localhost:8000"
var loginAddress = "localhost:8001"
var rate = 1000
var wordPerMessage = 3
var refresh = 240
var listen bool
var autoSend bool
var stdinSend bool
var LoadMessages bool
var debug bool
var serverName string
var test bool
var wordsSource = "https://gist.githubusercontent.com/deekayen/4148741/raw/98d35708fa344717d8eee15d11987de6c8e26d7d/1-1000.txt"
var wordsList []string
var rng *rand.Rand
var Username string
var token string
var session string
var Done chan (struct{})
var Line chan string
func debugPrint(args ...any) {
if debug {
fmt.Print("DEBUG: ")
fmt.Println(args...)
fmt.Println() // spacer
}
}
func Initialise() error {
parseArgs()
if test {
listen, autoSend, LoadMessages, debug = true, true, true, true
}
if list, err := buildWordsList(wordsSource); err != nil {
return err
} else {
wordsList = list
}
rng = rand.New(rand.NewSource(time.Now().Unix()))
generateUsername()
if stdinSend {
go sendFromStdin()
}
go manageToken()
return nil
}
func generateUsername() {
Username = wordsList[rng.Intn(len(wordsList))] + "_" + wordsList[rng.Intn(len(wordsList))]
}
func parseArgs() {
flag.StringVar(&chatAddress, "chataddr", chatAddress, "address for chat server")
flag.StringVar(&loginAddress, "loginaddr", loginAddress, "address for login server")
flag.StringVar(&serverName, "server", serverName, "server name (blank for main)")
flag.IntVar(&rate, "rate", rate, "time in ms between messages")
flag.IntVar(&wordPerMessage, "wpm", wordPerMessage, "words per message")
flag.BoolVar(&listen, "listen", listen, "listen and echo every message received")
flag.BoolVar(&autoSend, "autosend", autoSend, "auto generate and send messages of length and rate specified")
flag.BoolVar(&LoadMessages, "load", LoadMessages, "load most recent messages when connecting to chat")
flag.BoolVar(&debug, "debug", debug, "print additional debug messages e.g. http responses, auth token")
flag.IntVar(&refresh, "refresh", refresh, "auth token refresh rate in seconds")
flag.BoolVar(&stdinSend, "send", stdinSend, "send messages from CLI")
flag.BoolVar(&test, "test", test, "test all functionality (implies -listen, -autosend, -load, -debug)")
flag.Parse()
}
func createMessage() (message string) {
for i := 0; i < wordPerMessage; i++ {
message += wordsList[rng.Intn(len(wordsList))] + " "
}
return
}
func buildWordsList(url string) (wordsList []string, err error) {
res, err := http.Get(url)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
return
}
wordsList = make([]string, 0)
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Fprintln(os.Stderr, "error reading response body:", err)
}
var word []byte
for _, char := range body {
if char == '\r' {
continue
}
if char == '\n' {
wordsList = append(wordsList, string(word))
word = make([]byte, 0)
} else {
word = append(word, char)
}
}
return
}
func sendFromStdin() {
defer func() {
fmt.Println("stopped reading from stdin")
}()
Line = make(chan string)
reader := bufio.NewReader(os.Stdin)
for {
l, _, err := reader.ReadLine()
if err != nil {
fmt.Println(err.Error())
return
}
Line <- string(l)
}
}
func manageToken() {
ticker := time.NewTicker(time.Second * time.Duration(refresh))
for {
<-ticker.C
refreshToken()
}
}

@ -0,0 +1,200 @@
package testclient
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"os"
"time"
"github.com/gorilla/websocket"
)
type TokenObj struct {
Token string `json:"session"`
}
type SessionObj struct {
Session string `json:"session"`
}
var client *http.Client
var conn *websocket.Conn
func InitHttpClient() (err error) {
jar, err := cookiejar.New(nil)
if err != nil {
fmt.Fprintln(os.Stderr, "error initialising cookie jar", err.Error())
return err
}
client = &http.Client{
Jar: jar,
}
return
}
func Register() error {
postBody := []byte(`{"username":"` + Username + `","password":"Password1!"}`)
req, err := http.NewRequest("POST", "http://"+loginAddress+"/register", bytes.NewBuffer(postBody))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
return err
}
res, err := client.Do(req)
if err != nil {
fmt.Fprintln(os.Stderr, "could not reach login server", err.Error())
os.Exit(1)
}
if res.StatusCode != http.StatusCreated {
fmt.Fprintln(os.Stderr, "Status code", res.StatusCode, "received")
os.Exit(1)
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Fprintln(os.Stderr, "error reading register body:", err)
os.Exit(1)
}
debugPrint("sent ", string(postBody), "received", res.StatusCode, "from", req.URL, "with response body", string(body))
type TokenObj struct {
Token string `json:"token"`
}
var tokenObj TokenObj
if err := json.Unmarshal(body, &tokenObj); err != nil {
fmt.Fprintln(os.Stderr, "error unmarshalling token:", err.Error())
return err
}
token = tokenObj.Token
debugPrint("initial token set to", token)
return nil
}
func WsConnect() {
u := url.URL{Scheme: "ws", Host: chatAddress, Path: "/connect", RawQuery: "name=" + serverName}
var err error
header := http.Header{}
header.Set("Token", token)
conn, _, err = websocket.DefaultDialer.Dial(u.String(), header)
if err != nil {
fmt.Fprintln(os.Stderr, "error connecting to ws: ", err.Error())
return
}
Done = make(chan struct{})
debugPrint("connected to websocket server", serverName, "(blank for root) at", u.String())
go func() {
defer conn.Close()
for {
_, mess, err := conn.ReadMessage()
if err != nil {
fmt.Println(err)
Done <- struct{}{}
return
}
if listen {
fmt.Println(string(mess))
}
}
}()
if autoSend {
go func() {
t := time.NewTicker(time.Millisecond * time.Duration(rate))
for {
<-t.C
SendMessage(createMessage())
}
}()
}
}
func SendMessage(message string) {
mess := []byte(`{"text":"` + message + `","user":"` + token + `"}`)
req, err := http.NewRequest("POST", "http://"+chatAddress+"/send?name="+serverName, bytes.NewBuffer(mess))
if err != nil {
fmt.Fprintln(os.Stderr, "creating post request error:", err.Error())
os.Exit(1)
}
req.Header.Set("Token", token)
res, err := client.Do(req)
if err != nil {
fmt.Fprintln(os.Stderr, "sending post request error:", err.Error())
}
if res.StatusCode != http.StatusOK {
fmt.Fprintln(os.Stderr, "received", res.StatusCode, "when sending message")
}
debugPrint("sent", message, "received", res.StatusCode)
}
func LoadDefaultMessages() {
req, err := http.NewRequest("GET", "http://"+chatAddress+"/messages?name="+serverName, nil)
if err != nil {
fmt.Fprintln(os.Stderr, "creating get request error:", err.Error())
os.Exit(1)
}
req.Header.Set("Token", token)
res, err := client.Do(req)
if err != nil {
fmt.Fprintln(os.Stderr, "sending get request error:", err.Error())
return
}
if res.StatusCode != http.StatusOK {
fmt.Fprintln(os.Stderr, "received", res.StatusCode, "when loading message")
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Fprintln(os.Stderr, "error reading response body:", err)
}
debugPrint("load messages: status", res.StatusCode, "body:", string(body))
}
func refreshToken() {
req, err := http.NewRequest("GET", "http://"+loginAddress+"/auth", nil)
if err != nil {
fmt.Fprintln(os.Stderr, "creating get request error:", err.Error())
os.Exit(1)
}
res, err := client.Do(req)
if err != nil {
fmt.Fprintln(os.Stderr, "could not reach login server", err.Error())
os.Exit(1)
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Fprintln(os.Stderr, "error reading auth response body:", err)
}
if res.StatusCode != http.StatusOK {
fmt.Fprintln(os.Stderr, "/auth received status code", res.StatusCode, "with body", string(body))
}
type TokenObj struct {
Token string `json:"token"`
}
var tokenObj TokenObj
if err := json.Unmarshal(body, &tokenObj); err != nil {
fmt.Fprintln(os.Stderr, "error unmarshalling token:", err.Error())
return
}
token = tokenObj.Token
debugPrint("refreshing token to", token)
}
Loading…
Cancel
Save