init
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…
Reference in New Issue