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