summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorAndrew <saintruler@gmail.com>2021-04-27 21:41:44 +0400
committerAndrew <saintruler@gmail.com>2021-04-27 21:41:44 +0400
commitf3088f22e319b7183f9ad29d582574d3a06666ed (patch)
tree89e2f076d83d50f050964c3e92ffd0093bac197f /client
parent1fb7ca2bd298cbe340f7790cc40a808b1a4ab245 (diff)
Added GUI to client. renamed Message to Request. Added PING request type to sender server.
Diffstat (limited to 'client')
-rw-r--r--client/client.go161
-rw-r--r--client/go.mod2
-rw-r--r--client/main.go267
-rw-r--r--client/utils.go19
4 files changed, 311 insertions, 138 deletions
diff --git a/client/client.go b/client/client.go
new file mode 100644
index 0000000..033be8f
--- /dev/null
+++ b/client/client.go
@@ -0,0 +1,161 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "fyne.io/fyne/v2/data/binding"
+ "log"
+ "net"
+ "sync"
+)
+
+var storage struct {
+ sync.RWMutex
+ messages []Request
+ stringData []string
+ data binding.ExternalStringList
+}
+
+type UserData struct {
+ Username string
+}
+
+type Client struct {
+ senderConn net.Listener
+ receiverConn net.Listener
+}
+
+func readResponse(conn net.Conn) (Response, error) {
+ var response Response
+ var err error
+
+ buf := make([]byte, 4096)
+ _, err = conn.Read(buf)
+ if err != nil {
+ return response, err
+ }
+
+ size := fromBytes(buf[:4])
+ rawResponse := buf[4 : size+4]
+ return parseResponse(rawResponse)
+}
+
+func sender(conn net.Conn, wg *sync.WaitGroup, user UserData, c chan string) {
+ var err error
+
+ authMsg, _ := json.Marshal(Request{
+ Type: AUTHENTICATE,
+ Data: AUTHENTICATE,
+ User: user.Username,
+ })
+ _ = sendMessage(conn, authMsg)
+
+ for {
+ line := <-c
+ channelLock.Unlock()
+
+ request, _ := json.Marshal(Request{
+ Type: MESSAGE,
+ Data: line,
+ User: user.Username,
+ })
+ err = sendMessage(conn, request)
+ if err != nil {
+ fmt.Printf("Error in sender: %s", err)
+ break
+ }
+
+ response, _ := readResponse(conn)
+ _ = fmt.Sprintf("%s", response)
+ }
+
+ exitMsg, _ := json.Marshal(Request{
+ Type: EXIT,
+ Data: EXIT,
+ User: user.Username,
+ })
+ _ = sendMessage(conn, exitMsg)
+ fmt.Println("Closed connection")
+ wg.Done()
+}
+
+func receiver(conn net.Conn, wg *sync.WaitGroup, user UserData) {
+ var err error
+
+ req := Request{
+ Type: AUTHENTICATE,
+ Data: AUTHENTICATE,
+ User: user.Username,
+ }
+ err = sendMessage(conn, []byte(req.serialize()))
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ _, err = readResponse(conn)
+ if err != nil {
+ return
+ }
+
+ for {
+ response, err := readResponse(conn)
+ if err != nil {
+ break
+ }
+
+ if response.Status == PING {
+ req := Request{
+ Type: PING,
+ Data: SUCCESS,
+ User: user.Username,
+ }
+
+ _ = sendMessage(conn, []byte(req.serialize()))
+ continue
+ }
+
+ message, err := parseRequest([]byte(response.Data))
+ if err == nil {
+ storage.Lock()
+ //storage.messages = append(storage.messages, message)
+ _ = storage.data.Append(message.toString())
+ storage.Unlock()
+ } else {
+ fmt.Println(err)
+ }
+
+ req := Request{
+ Type: MESSAGE,
+ Data: SUCCESS,
+ User: user.Username,
+ }
+ _ = sendMessage(conn, []byte(req.serialize()))
+ }
+ wg.Done()
+}
+
+func runClient(user UserData, c chan string) {
+ var wg sync.WaitGroup
+
+ senderConn, err := net.Dial("tcp", "localhost:8080")
+ handleError(err)
+ defer senderConn.Close()
+ wg.Add(1)
+
+ receiverConn, err := net.Dial("tcp", "localhost:8081")
+ handleError(err)
+ defer receiverConn.Close()
+ wg.Add(1)
+
+ go sender(senderConn, &wg, user, c)
+ go receiver(receiverConn, &wg, user)
+
+ wg.Wait()
+}
+
+func handleError(err error) {
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/client/go.mod b/client/go.mod
index ffafd1f..168a27a 100644
--- a/client/go.mod
+++ b/client/go.mod
@@ -1,3 +1,5 @@
module vasthecat.ru/coursework-client
go 1.16
+
+require fyne.io/fyne/v2 v2.0.2
diff --git a/client/main.go b/client/main.go
index f90a018..bf11f7a 100644
--- a/client/main.go
+++ b/client/main.go
@@ -1,156 +1,159 @@
package main
import (
- "bufio"
- "encoding/json"
- "fmt"
- "log"
- "net"
- "os"
+ "fyne.io/fyne/v2"
+ "fyne.io/fyne/v2/app"
+ "fyne.io/fyne/v2/canvas"
+ "fyne.io/fyne/v2/container"
+ "fyne.io/fyne/v2/data/binding"
+ "fyne.io/fyne/v2/dialog"
+ "fyne.io/fyne/v2/layout"
+ "fyne.io/fyne/v2/widget"
+ "image/color"
"sync"
)
-var storage struct {
- sync.Mutex
- messages []Message
-}
+func chatLayout(window fyne.Window, user UserData, c chan string) {
+ window.SetTitle("Сообщения")
-func parseBuffer(previous []byte, new []byte) ([]Response, []byte) {
- buf := append(previous, new...)
- bufSize := uint32(len(buf))
- var responses []Response
- var idx uint32 = 0
- for {
- if idx+4 >= bufSize {
- break
- }
- size := fromBytes(buf[idx : idx+4])
- if size == 0 {
- return responses, make([]byte, 0)
- }
- if idx+4+size >= bufSize {
- break
- } else {
- resp, err := parseResponse(buf[idx+4 : idx+4+size])
- if err == nil {
- responses = append(responses, resp)
- }
- idx += 4 + size
- }
- }
- return responses, buf[idx:]
+ storage.Lock()
+ storage.data = binding.BindStringList(&storage.stringData)
+ storage.Unlock()
+ go runClient(user, c)
+
+ list := widget.NewListWithData(storage.data,
+ func() fyne.CanvasObject {
+ return widget.NewLabel("template")
+ },
+ func(i binding.DataItem, o fyne.CanvasObject) {
+ o.(*widget.Label).Bind(i.(binding.String))
+ })
+
+ entry := widget.NewEntry()
+ submit := widget.NewButton("Отправить", func() {
+ channelLock.Lock()
+ c <- entry.Text
+ entry.SetText("")
+
+ storage.RLock()
+ lastIdx := storage.data.Length() - 1
+ list.Select(lastIdx)
+ list.Unselect(lastIdx)
+ storage.RUnlock()
+ })
+
+ window.SetContent(container.NewBorder(
+ nil,
+ container.NewBorder(nil, nil, nil, submit, entry),
+ nil, nil,
+ list,
+ ))
}
-func readResponse(conn net.Conn) (Response, error) {
- var response Response
- var err error
+func loginLayout(window fyne.Window, c chan string) {
+ window.SetTitle("Войти в чат")
- buf := make([]byte, 4096)
- _, err = conn.Read(buf)
- if err != nil {
- return response, err
- }
+ label := canvas.NewText("Chat", color.White)
+ label.TextSize = 40
- size := fromBytes(buf[:4])
- rawResponse := buf[4 : size+4]
- return parseResponse(rawResponse)
-}
+ loginLabel := widget.NewLabel("Логин: ")
+ loginEntry := widget.NewEntry()
-func main() {
- var wg sync.WaitGroup
- conn, err := net.Dial("tcp", "localhost:8080")
- handleError(err)
- defer conn.Close()
- wg.Add(1)
- go func(conn net.Conn) {
- authMsg, _ := json.Marshal(Message{
- Type: AUTHENTICATE,
- Data: "auth",
- User: "andrew",
- })
- _ = sendMessage(conn, authMsg)
- reader := bufio.NewReader(os.Stdin)
-
- for i := 0; i < 1000; i += 1 {
- //fmt.Printf("Sending %d request\n", i)
- line, _, _ := reader.ReadLine()
- request, _ := json.Marshal(Message{
- Type: MESSAGE,
- //Data: fmt.Sprintf("Hello, %d", i),
- Data: string(line),
- User: "andrew",
- })
- err = sendMessage(conn, request)
- if err != nil {
- break
+ chooseKey := widget.NewButton("Выбрать ключ для подписи", func() {
+ dialog.ShowFileOpen(func(closer fyne.URIReadCloser, err error) {
+ if closer == nil {
+ return
+ }
+ bufSize := 4096
+ data := make([]byte, 0)
+ buf := make([]byte, bufSize)
+ n := bufSize
+
+ for n >= bufSize {
+ n, _ = closer.Read(buf)
+ data = append(data, buf...)
}
- response, _ := readResponse(conn)
- _ = fmt.Sprintf("%s", response)
- }
+ closer.Close()
+ }, window)
+ })
- exitMsg, _ := json.Marshal(Message{
- Type: MESSAGE,
- Data: "exit",
- User: "andrew",
- })
- _ = sendMessage(conn, exitMsg)
- fmt.Println("Closed connection")
- wg.Done()
- }(conn)
-
- receiver, err := net.Dial("tcp", "localhost:8081")
- handleError(err)
- defer receiver.Close()
- wg.Add(1)
- go func(conn net.Conn) {
- req := Message{
- Type: AUTHENTICATE,
- Data: AUTHENTICATE,
- User: "andrew",
- }
- err = sendMessage(conn, []byte(req.serialize()))
- if err != nil {
- fmt.Println(err)
- return
+ loginButton := widget.NewButton("Войти", func() {
+ var user = UserData{
+ Username: loginEntry.Text,
}
+ chatLayout(window, user, c)
+ })
+
+ back := widget.NewButton("Назад", func() {
+ startLayout(window, c)
+ })
+
+ mainContainer := container.NewCenter(container.NewVBox(
+ container.NewCenter(label), layout.NewSpacer(),
+ container.NewBorder(nil, nil, loginLabel, nil, loginEntry),
+ chooseKey,
+ loginButton,
+ back,
+ ))
+ window.SetContent(mainContainer)
+}
- _, err := readResponse(conn)
- if err != nil {
- return
- }
+func registerLayout(window fyne.Window, c chan string) {
+ window.SetTitle("Регистрация")
- for {
- response, err := readResponse(conn)
- if err != nil {
- break
- }
+ label := canvas.NewText("Chat", color.White)
+ label.TextSize = 40
- message, err := parseMessage([]byte(response.Data))
- if err == nil {
- storage.Lock()
- storage.messages = append(storage.messages, message)
- fmt.Printf("Got message: \"%s\"\n", message.Data)
- storage.Unlock()
- } else {
- fmt.Println(err)
- }
+ loginLabel := widget.NewLabel("Логин: ")
+ loginEntry := widget.NewEntry()
- req := Message{
- Type: MESSAGE,
- Data: SUCCESS,
- User: "andrew",
- }
- _ = sendMessage(conn, []byte(req.serialize()))
- }
- wg.Done()
- }(receiver)
+ generateKeys := widget.NewButton("Сгенерировать ключи подписи", func() {
+
+ })
+
+ registerButton := widget.NewButton("Зарегистрироваться", func() {
- wg.Wait()
+ })
+
+ back := widget.NewButton("Назад", func() {
+ startLayout(window, c)
+ })
+
+ window.SetContent(container.NewCenter(container.NewVBox(
+ container.NewCenter(label), layout.NewSpacer(),
+ container.NewBorder(nil, nil, loginLabel, nil, loginEntry),
+ generateKeys,
+ registerButton,
+ back,
+ )))
+}
+
+func startLayout(window fyne.Window, c chan string) {
+ window.SetTitle("Chat")
+
+ label := canvas.NewText("Chat", color.White)
+ label.TextSize = 40
+ login := widget.NewButton("Войти", func() {
+ loginLayout(window, c)
+ })
+ signup := widget.NewButton("Зарегистрироваться", func() {
+ registerLayout(window, c)
+ })
+
+ mainContainer := container.NewCenter(container.NewVBox(
+ container.NewCenter(label), layout.NewSpacer(), login, signup))
+ window.SetContent(mainContainer)
}
-func handleError(err error) {
- if err != nil {
- log.Fatal(err)
- }
+//var channel chan string
+var channelLock sync.Mutex
+
+func main() {
+ myApp := app.New()
+ window := myApp.NewWindow("")
+ channel := make(chan string)
+
+ startLayout(window, channel)
+ window.ShowAndRun()
}
diff --git a/client/utils.go b/client/utils.go
index 4dc64b7..685a3a9 100644
--- a/client/utils.go
+++ b/client/utils.go
@@ -2,31 +2,38 @@ package main
import (
"encoding/json"
+ "fmt"
"net"
)
const (
MESSAGE = "message"
AUTHENTICATE = "authenticate"
- RENAME = "rename"
+ EXIT = "exit"
+ REGISTER = "register"
)
const (
SUCCESS = "success"
FAILURE = "failure"
+ PING = "ping"
)
-type Message struct {
+type Request struct {
Type string
Data string
User string
}
-func (msg *Message) serialize() string {
- data, _ := json.Marshal(msg)
+func (req *Request) serialize() string {
+ data, _ := json.Marshal(req)
return string(data)
}
+func (req *Request) toString() string {
+ return fmt.Sprintf("%s: %s", req.User, req.Data)
+}
+
type Response struct {
Status string
Data string
@@ -62,8 +69,8 @@ func sendMessage(conn net.Conn, message []byte) error {
return nil
}
-func parseMessage(data []byte) (Message, error) {
- var m Message
+func parseRequest(data []byte) (Request, error) {
+ var m Request
err := json.Unmarshal(data, &m)
return m, err
}