package main import ( "encoding/json" "fmt" "io" "net/http" "os" "strconv" "time" ) type Response struct { Message string } type Request struct { User string Data string } type Message struct { User string Data string Timestamp int64 } func parseRequest(w http.ResponseWriter, r *http.Request) (Request, error) { var resp Request body, _ := io.ReadAll(r.Body) err := json.Unmarshal(body, &resp) if err != nil { _ = badRequest(w) return resp, err } return resp, nil } func jsonResponse(w http.ResponseWriter, resp Response) error { data, err := json.Marshal(resp) if err != nil { return err } _, err = w.Write(data) return err } func methodNotAllowedResponse(w http.ResponseWriter) error { w.WriteHeader(http.StatusMethodNotAllowed) return jsonResponse(w, Response{ Message: "К серверу разрешены обращения только по методу POST", }) } func badRequest(w http.ResponseWriter) error { w.WriteHeader(http.StatusBadRequest) return jsonResponse(w, Response{ Message: "Не удалось обработать запрос", }) } func serverError(w http.ResponseWriter) error { w.WriteHeader(http.StatusInternalServerError) return jsonResponse(w, Response{ Message: "Произошла внутренняя ошибка", }) } func index(w http.ResponseWriter, r *http.Request) { _, _ = fmt.Fprintf(w, "Hello there") } func register(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { _ = methodNotAllowedResponse(w) return } req, err := parseRequest(w, r) if err != nil { return } userRegistered, err := db.checkUserRegistered(req.User) if err != nil { _ = serverError(w) return } // TODO(andrew): Добавить проверку действительности ключа if false { w.WriteHeader(http.StatusBadRequest) _ = jsonResponse(w, Response{ Message: "Указанный ключ не является действительным", }) return } if userRegistered { w.WriteHeader(http.StatusBadRequest) _ = jsonResponse(w, Response{ Message: "Пользователь с таким именем уже зарегистрирован", }) return } err = db.registerUser(req.User, req.Data) if err != nil { w.WriteHeader(http.StatusInternalServerError) _ = jsonResponse(w, Response{ Message: fmt.Sprintf("%s", err), }) return } _ = jsonResponse(w, Response{ Message: "Пользователь успешно зарегистрирован", }) } func sendMessage(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { _ = methodNotAllowedResponse(w) return } req, err := parseRequest(w, r) if err != nil { return } // TODO(andrew): Добавить аутентификацию if false { w.WriteHeader(http.StatusForbidden) _ = jsonResponse(w, Response{ Message: "Запрос не прошёл аутентификацию", }) return } msg := Message{ User: req.User, Data: req.Data, Timestamp: time.Now().Unix(), } err = db.saveMessage(msg) if err != nil { w.WriteHeader(http.StatusInternalServerError) _ = jsonResponse(w, Response{ Message: fmt.Sprintf("%s", err), }) return } _ = jsonResponse(w, Response{ Message: "Сообщение успешно сохранено", }) } func pollMessages(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { _ = methodNotAllowedResponse(w) return } req, err := parseRequest(w, r) if err != nil { return } // TODO(andrew): Добавить аутентификацию if false { w.WriteHeader(http.StatusForbidden) _ = jsonResponse(w, Response{ Message: "Запрос не прошёл аутентификацию", }) return } timestamp, err := strconv.ParseInt(req.Data, 10, 64) if err != nil { w.WriteHeader(http.StatusBadRequest) _ = jsonResponse(w, Response{ Message: "Указана неверная временная отметка", }) return } messages, err := db.getMessagesSince(timestamp) if err != nil { _ = serverError(w) return } data, _ := json.Marshal(messages) _ = jsonResponse(w, Response{ Message: string(data), }) } var db SQLConnection func main() { err := db.init("chat.sqlite3") if err != nil { fmt.Println(err) os.Exit(1) } http.HandleFunc("/", index) http.HandleFunc("/api/register", register) http.HandleFunc("/api/sendMessage", sendMessage) http.HandleFunc("/api/pollMessages", pollMessages) err = http.ListenAndServe("localhost:8080", nil) if err != nil { fmt.Println(err) os.Exit(1) } }