summaryrefslogtreecommitdiff
path: root/http-client
diff options
context:
space:
mode:
authorAndrew <saintruler@gmail.com>2021-04-28 18:09:00 +0400
committerAndrew <saintruler@gmail.com>2021-04-28 18:09:00 +0400
commit7d6270f64b1dc00d91230b5c793bc49991f0fcf8 (patch)
treeee41d9e909968d56a83a09cf83fbb6e5ff6dbb1c /http-client
parent355dab5bdc924202b1d877b18ae31f04154a4aee (diff)
Added http client and tryAuth view to server.
Diffstat (limited to 'http-client')
-rw-r--r--http-client/client.go106
-rw-r--r--http-client/go.mod5
-rw-r--r--http-client/main.go155
3 files changed, 266 insertions, 0 deletions
diff --git a/http-client/client.go b/http-client/client.go
new file mode 100644
index 0000000..ee3e044
--- /dev/null
+++ b/http-client/client.go
@@ -0,0 +1,106 @@
+package main
+
+import (
+ "bytes"
+ "crypto/sha256"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "fyne.io/fyne/v2/data/binding"
+ "io"
+ "net/http"
+ "sync"
+ "time"
+)
+
+const (
+ URL = "http://localhost:8080/api"
+ Register = "register"
+ SendMessage = "sendMessage"
+ PollMessages = "pollMessages"
+ GetUserKey = "getUserKey"
+ TryAuth = "tryAuth"
+)
+
+const TimestampFormat = "2006-01-02T15-01-05.999"
+
+var storage struct {
+ sync.RWMutex
+ messages []Message
+ data []string
+ binding binding.ExternalStringList
+}
+
+type Request struct {
+ User string
+ Data string
+}
+
+type Response struct {
+ Message string
+}
+
+type Message struct {
+ User string
+ Data string
+ Timestamp string
+}
+
+func (msg *Message) toString() string {
+ return fmt.Sprintf("%s: %s", msg.User, msg.Data)
+}
+
+func signData(data []byte) string {
+ data64 := base64.StdEncoding.EncodeToString(data)
+ h := sha256.Sum256([]byte(data64))
+ signature := fmt.Sprintf("%x", h)
+ return fmt.Sprintf("%s.%s", data64, signature)
+}
+
+func makeRequest(request Request, apiMethod string) (*http.Response, error) {
+ req, _ := json.Marshal(request)
+ signedRequest := signData(req)
+ reader := bytes.NewReader([]byte(signedRequest))
+ return http.Post(URL+"/"+apiMethod, "application/json", reader)
+}
+
+func sendMessage(user UserData, message string) {
+ // TODO(andrew): Добавить отображение ошибки в интерфейс
+ _, _ = makeRequest(Request{
+ User: user.Username,
+ Data: message,
+ }, SendMessage)
+}
+
+func runClient(user UserData) {
+ lastPoll := time.Now().UnixNano()
+ for {
+ httpResp, _ := makeRequest(Request{
+ User: user.Username,
+ Data: fmt.Sprint(lastPoll),
+ }, PollMessages)
+ lastPoll = time.Now().UnixNano()
+
+ if httpResp.StatusCode == http.StatusOK {
+ body, _ := io.ReadAll(httpResp.Body)
+ var resp Response
+ _ = json.Unmarshal(body, &resp)
+ var messages []Message
+ _ = json.Unmarshal([]byte(resp.Message), &messages)
+
+ storage.Lock()
+ for _, msg := range messages {
+ fmt.Printf("Polled new message from %s: %s (%s)\n", msg.User, msg.Data, msg.Timestamp)
+ _ = storage.binding.Append(msg.toString())
+ storage.messages = append(storage.messages, msg)
+ }
+ storage.Unlock()
+ } else {
+ fmt.Println(httpResp.StatusCode)
+ ae, _ := io.ReadAll(httpResp.Body)
+ fmt.Println(string(ae))
+ }
+
+ time.Sleep(100 * time.Millisecond)
+ }
+}
diff --git a/http-client/go.mod b/http-client/go.mod
new file mode 100644
index 0000000..a62b9f0
--- /dev/null
+++ b/http-client/go.mod
@@ -0,0 +1,5 @@
+module vasthecat.ru/coursework/http-client
+
+go 1.16
+
+require fyne.io/fyne/v2 v2.0.2
diff --git a/http-client/main.go b/http-client/main.go
new file mode 100644
index 0000000..14419e5
--- /dev/null
+++ b/http-client/main.go
@@ -0,0 +1,155 @@
+package main
+
+import (
+ "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"
+)
+
+type UserData struct {
+ Username string
+}
+
+func chatLayout(window fyne.Window, user UserData, c chan string) {
+ window.SetTitle("Сообщения")
+ storage.binding = binding.BindStringList(&storage.data)
+ go runClient(user)
+
+ list := widget.NewListWithData(storage.binding,
+ 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() {
+ go sendMessage(user, entry.Text)
+ entry.SetText("")
+
+ storage.RLock()
+ lastIdx := storage.binding.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 loginLayout(window fyne.Window, c chan string) {
+ window.SetTitle("Войти в чат")
+
+ label := canvas.NewText("Chat", color.White)
+ label.TextSize = 40
+
+ loginLabel := widget.NewLabel("Логин: ")
+ loginEntry := widget.NewEntry()
+
+ 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...)
+ }
+
+ _ = closer.Close()
+ }, window)
+ })
+
+ 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)
+}
+
+func registerLayout(window fyne.Window, c chan string) {
+ window.SetTitle("Регистрация")
+
+ label := canvas.NewText("Chat", color.White)
+ label.TextSize = 40
+
+ loginLabel := widget.NewLabel("Логин: ")
+ loginEntry := widget.NewEntry()
+
+ generateKeys := widget.NewButton("Сгенерировать ключи подписи", func() {
+
+ })
+
+ registerButton := widget.NewButton("Зарегистрироваться", func() {
+
+ })
+
+ 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 main() {
+ myApp := app.New()
+ window := myApp.NewWindow("")
+ channel := make(chan string)
+
+ startLayout(window, channel)
+ window.ShowAndRun()
+}