serverWeatherApi.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. package main
  2. import (
  3. "database/sql"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "log"
  9. "net/http"
  10. "strings"
  11. _ "github.com/lib/pq"
  12. )
  13. // Переменная для работы с базой данных
  14. var DB *sql.DB
  15. // Константы для работы со сторонним погодным API
  16. const currentWeather = "https://api.open-meteo.com/v1/forecast?latitude="
  17. const geoResponse = "http://api.openweathermap.org/geo/1.0/direct?q="
  18. const lonWeather = "&longitude="
  19. const endResp = "&timezone=auto&daily=temperature_2m_max"
  20. const apiKey = "&limit=5&appid=f7047650c6b759c44bb67724cbb2ccad"
  21. // Структура для чтения данных json, переданных на наш сервер, через переменную city
  22. type bodyRequest struct {
  23. CityName string `json:"city"`
  24. }
  25. // Структура для чтения гео данных json, переданных через API стороннего сервиса
  26. type Geo struct {
  27. Country string `json:"country"`
  28. State string `json:"state,omitempty"`
  29. Name string `json:"name"`
  30. Lat float64 `json:"lat"`
  31. Lon float64 `json:"lon"`
  32. }
  33. // Переменные для работы с погодными данными нашего сервиса
  34. var jsonWeaherStr string
  35. var jsonAnswer string
  36. var jsonStr string
  37. var latStr string
  38. var lonStr string
  39. var city string
  40. var Day1 float64
  41. var Day2 float64
  42. var Day3 float64
  43. var Lat float64
  44. var Lon float64
  45. // Структура для чтения погодных данных json, переданных через API стороннего сервиса
  46. type WeatherJson struct {
  47. TimezoneAbbreviation string `json:"timezone_abbreviation"`
  48. GenerationtimeMs float64 `json:"generationtime_ms"`
  49. UtcOffsetSeconds int `json:"utc_offset_seconds"`
  50. DailyUnits struct {
  51. Longitude float64 `json:"longitude"`
  52. Elevation float64 `json:"elevation"`
  53. Latitude float64 `json:"latitude"`
  54. Timezone string `json:"timezone"`
  55. Time string `json:"time"`
  56. Temperature2MMax string `json:"temperature_2m_max"`
  57. } `json:"daily_units"`
  58. Daily struct {
  59. Time []string `json:"time"`
  60. Temperature2MMax []float64 `json:"temperature_2m_max"`
  61. } `json:"daily"`
  62. }
  63. func main() {
  64. // Данные для авторизации в БД безопаснее хранить в ENV в переменной KEY
  65. connStr := "user=postgres password=sql999 dbname=weather sslmode=disable"
  66. var err error
  67. // PostgreSQL подключение к БД
  68. DB, err = sql.Open("postgres", connStr)
  69. if err != nil {
  70. fmt.Println(err.Error())
  71. }
  72. defer DB.Close()
  73. // Соединение с сервером
  74. http.HandleFunc("/", SayCity) // Устанавливаем роутер
  75. err = http.ListenAndServe(":8080", nil) // Устанавливаем порт веб-сервера
  76. if err != nil {
  77. log.Fatal("ListenAndServe: ", err)
  78. }
  79. }
  80. // Функция-обработчик запросов для нашего сервера
  81. func SayCity(w http.ResponseWriter, r *http.Request) {
  82. defer r.Body.Close()
  83. if r.Method != "POST" {
  84. fmt.Fprintf(w, "Привет, перед тобой сервис Погоды. Чтобы все заработало - нужно отправить запрос методом Post c переменной city!")
  85. return
  86. }
  87. for {
  88. bytes, err := io.ReadAll(r.Body)
  89. if err != nil {
  90. fmt.Fprintf(w, "500")
  91. return
  92. }
  93. var cityReq bodyRequest
  94. err = json.Unmarshal(bytes, &cityReq)
  95. if err != nil {
  96. fmt.Fprint(w, err.Error())
  97. return
  98. }
  99. city = cityReq.CityName
  100. MakeRequest(city)
  101. data := []byte(jsonStr)
  102. u := make([]Geo, 0)
  103. err2 := json.Unmarshal(data, &u)
  104. if err2 != nil {
  105. fmt.Fprintf(w, "We can not get json Geo")
  106. }
  107. for _, info := range u {
  108. if strings.Compare(city, info.Name) == 0 {
  109. Lat = info.Lat
  110. Lon = info.Lon
  111. latStr = fmt.Sprintf("%f", Lat)
  112. lonStr = fmt.Sprintf("%f", Lon)
  113. WeatherRequest()
  114. Day1Str := fmt.Sprintf("%f", Day1)
  115. Day2Str := fmt.Sprintf("%f", Day2)
  116. Day3Str := fmt.Sprintf("%f", Day3)
  117. jsonAnswer = "city: " + city + " lat: " + latStr + " lon: " + lonStr + " today: " + Day1Str + " tomorrow: " + Day2Str + " after_tomorrow: " + Day3Str
  118. jsonServer, _ := json.Marshal(jsonAnswer)
  119. w.Write(jsonServer)
  120. // Добавляем название города, широту и долготу в БД Postgresql
  121. _, err3 := DB.Exec("INSERT into weather (city, lat, lon) values ($1, $2, $3)", city, Lat, Lon)
  122. if err3 != nil {
  123. fmt.Fprint(w, err.Error())
  124. return
  125. } else {
  126. log.Printf("добавлен город: %s, %f, %f\n", city, Lat, Lon)
  127. }
  128. break
  129. }
  130. }
  131. }
  132. }
  133. // Функция получает географические координаты места по названию
  134. func MakeRequest(city string) {
  135. resp, err := http.Get(geoResponse + city + apiKey)
  136. if err != nil {
  137. fmt.Println(err.Error())
  138. return
  139. }
  140. body, err := ioutil.ReadAll(resp.Body)
  141. if err != nil {
  142. fmt.Println(err.Error())
  143. return
  144. }
  145. jsonStr = string(body)
  146. defer resp.Body.Close()
  147. }
  148. // Функция получает данные погоды по координатам
  149. func WeatherRequest() {
  150. var ResGet = currentWeather + latStr + lonWeather + lonStr + endResp
  151. resp, err := http.Get(ResGet)
  152. if err != nil {
  153. fmt.Println(err.Error())
  154. return
  155. }
  156. body, err := ioutil.ReadAll(resp.Body)
  157. if err != nil {
  158. fmt.Println(err.Error())
  159. return
  160. }
  161. jsonWeaherStr = string(body)
  162. defer resp.Body.Close()
  163. dataWeather := []byte(jsonWeaherStr)
  164. var u2 WeatherJson
  165. err2 := json.Unmarshal(dataWeather, &u2)
  166. if err2 != nil {
  167. fmt.Println(err.Error())
  168. return
  169. }
  170. Day1 = u2.Daily.Temperature2MMax[0]
  171. Day2 = u2.Daily.Temperature2MMax[1]
  172. Day3 = u2.Daily.Temperature2MMax[2]
  173. }