Показ дописів із міткою Go. Показати всі дописи
Показ дописів із міткою Go. Показати всі дописи

середа, 23 листопада 2016 р.

Добавляем поддержку HTTPS для микросервиса 7dtd.moon

При написании предыдущей заметки Программное формирования изображения на Go, мне понадобилось вставить пример формируемого изображения. Можно конечно это было сделать статическими картинками, но я решил использовать реальный пример работы. Так вот при это я столкнулся с проблемой что Blogger ругался на то что я вставляю картинки которые доступны по http а не по https на котором он работает по умолчании.
Сертификат будем использовать свободный, который выдает Let’s Encrypt, для получения самого сертификата воспользуемся утилитой СertBot. Данный процесс хорошо расписан на этих ресурсах и повторять его тут не имеет смысла.
И так приступим...
Первое это мы добавляем переменные которые будут указывать сам сертификат и закрытый ключ, и запускаем https сервер в отдельном потоке - гороутине (goroutine)
...
  log.Printf("Loading Certificates %s/%s/{privkey.pem,fullchain.pem}\n", *cert, *host)
  keyPath := filepath.Join(*cert, *host, "privkey.pem")
  certPath := filepath.Join(*cert, *host, "fullchain.pem")
...
/*** HTTPS ***/
  log.Println("Listening on https port: ", int(*port)+363)
  go func() {
    if err := http.ListenAndServeTLS(":"+strconv.Itoa(int(*port)+363), certPath, keyPath, nil); err != nil {
      log.Fatal("HTTPS Listen and Serve: ", err)
      os.Exit(1)
    }
  }()
...
Вот и все, теперь у нас есть два веб-сервера, один на порту 26980 (http) и второй на порту 27343 (https)

понеділок, 21 листопада 2016 р.

Программное формирования изображения на Go

Понадобилось мне при разработке мода на 7 Days to Die программно формировать изображение круга в зависимости от количества дней в игре. Так как я давно порывался посмотреть на Go, решил я использовать его для данной задачи. Да и подходит он для такого микро-сервиса в самый раз.
Сделать веб сервер на Go просто :) для этого используем стандартную библиотеку "net/http"
func main() {
  flag.Parse()
  log.Println("Starting tiny webserver for 7DTD moon texture...")
  log.Println("Document root path: ", *root)
  http.HandleFunc("/moon", moonHandler)
  log.Println("Listening on port: ", *port)
  if err := http.ListenAndServe(":"+strconv.Itoa(*port), nil); err != nil {
    log.Fatal("ERROR Listen and Serve: ", err)
  }
}
Дальше, формируем изображение круга с использование библиотеки "image/draw",
func moonHandler(w http.ResponseWriter, r *http.Request) {
  d := getDay(r)
  /*** Create colored image ***/
  dst := image.NewRGBA(image.Rect(0, 0, cXY.X+cR+1, cXY.Y+cR+1))
  draw.Draw(dst, dst.Bounds(), &circle{cXY, cR}, image.ZP, draw.Src)
  writeImg(w, dst)
}
и отдаем ее как картинку "image/png"
func writeImg(w http.ResponseWriter, img image.Image) {
  buffer := new(bytes.Buffer)
  if err := png.Encode(buffer, img); err != nil {
    log.Println("Unable to encode image: ", err)
    http.Error(w, err.Error(), http.StatusNotFound)
    return
  }

  w.Header().Set("Content-Type", "image/png")
  w.Header().Set("Content-Length", strconv.Itoa(len(buffer.Bytes())))

  if _, err := w.Write(buffer.Bytes()); err != nil {
    log.Println("Unable to write image: ", err)
    http.Error(w, err.Error(), http.StatusNotFound)
    return
  }
}
А теперь самое интересное, как же сделать эту картинку :)
Для этого описываем структуру:
type circle struct {
  P image.Point
  R int
}
И определяем методы которые описываю данную структуру в разрезе "image.Image"
func (c *circle) ColorModel() color.Model {
  return color.AlphaModel
}
func (c *circle) Bounds() image.Rectangle {
  return image.Rect(c.P.X-c.R, c.P.Y-c.R, c.P.X+c.R, c.P.Y+c.R)
}
func (c *circle) At(x, y int) color.Color {
  xx, yy, rr := float64(x-c.P.X), float64(y-c.P.Y), float64(c.R)
  if xx*xx+yy*yy < rr*rr {
    return color.Alpha{255}
  }
  return color.Alpha{0}
}
Все это прекрасно работает, но мне нужно было получить картинку с определенной прозрачностью, по этому пришлось немного изменить код функции "At" и структуры "circle". Добавляем поля для цвета и типа изображения (сплошная заливка или градиентная)
type circle struct {
  P image.Point
  R int
  C color.NRGBA
  S bool
}
... и теперь сама процедура отрисовки круга:
func (c *circle) At(x, y int) color.Color {
  xx, yy, rr := float64(x-c.P.X), float64(y-c.P.Y), float64(c.R)
  if xx*xx+yy*yy < rr*rr {
    xr := math.Abs(float64(c.P.X - x))
    yr := math.Abs(float64(c.P.Y - y))
    ar := uint8((1 - math.Sqrt(xr*xr+yr*yr)/float64(c.R)) * float64(c.C.A))
    if c.S {
      ar = c.C.A
    }
    return color.NRGBA{c.C.R, c.C.G, c.C.B, ar}
  }
  return color.Alpha{0}
}
В итоге, мы можем получить два вида кружкок :) задав параметры при обращении к веб серверу.
Градиентная заливка для 7 дня Сплошная заливка для 7 дня Градиентная заливка для 5-6 дня Сплошная заливка для 5-6 дня


Конечный результат как это все выглядит в игре :)