package main import ( "bytes" "crypto/rsa" "crypto/sha256" "encoding/base64" "encoding/json" "errors" "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, key *rsa.PublicKey) (*http.Response, error) { signedRequest, err := signRequest(request, key) if err != nil { return nil, err } reader := bytes.NewReader([]byte(signedRequest)) return http.Post(URL+"/"+apiMethod, "application/json", reader) } func sendMessage(user UserData, message string, key *rsa.PublicKey) { // TODO(andrew): Добавить отображение ошибки в интерфейс _, _ = makeRequest(Request{ User: user.Username, Data: message, }, SendMessage, key) } func register(user UserData, serverKey string, key *rsa.PublicKey) (Response, error) { var resp Response httpResp, err := makeRequest(Request{ User: user.Username, Data: serverKey, }, Register, key) if err != nil { return resp, err } body, _ := io.ReadAll(httpResp.Body) _ = json.Unmarshal(body, &resp) if httpResp.StatusCode == http.StatusOK { return resp, nil } else { return resp, errors.New(resp.Message) } } func tryAuth(user UserData, key *rsa.PublicKey) (bool, error) { var resp Response httpResp, err := makeRequest(Request{ User: user.Username, Data: "auth", }, TryAuth, key) if err != nil { return false, err } body, _ := io.ReadAll(httpResp.Body) _ = json.Unmarshal(body, &resp) if httpResp.StatusCode == http.StatusOK { return true, nil } else { return false, errors.New(resp.Message) } } func runClient(user UserData) { lastPoll := time.Now().UnixNano() key, _ := parseKey(user.UserKey) for { httpResp, _ := makeRequest(Request{ User: user.Username, Data: fmt.Sprint(lastPoll), }, PollMessages, key) 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) } }