Можем ли мы сохранить животных с помощью Golang?
- суббота, 12 августа 2023 г. в 00:00:12
Статья, главным образом, состоит из двух частей: описания проблемы и описания ее решения. Если сама проблема вас не интересует, первый раздел можно пропустить без ущерба для себя либо животных. Или вообще можно всю статью пропустить.
В начале вас ждет небольшое, но важное вступление. Оно поможет увидеть как я докопался до сути проблемы и затем, перешел к ее решению.
Я разработчик и я предпочитаю проводить время со своим компьютером. Но все же иногда мне нужно выходить из дома, вы знаете, делать все те вещи, что делают другие люди. И вот однажды, возвращаясь домой со своей сумкой продуктов я увидел некоторую картину: группа людей с плакатами на которых написано “Save animals”. Как я уже говорил, я разработчик и прекрасно понимаю английский. Они, очевидно, хотели сохранить животных. И раз столько людей собрались вместе - это очень серьезная проблема, подумал я.
Эти люди не знали кто только что прошел мимо них. Я разработчик - один из тех людей которые делают мир лучше. И я намерен решить их проблему.
Хотя было кое-что, что воспрепятствовало мне тут же приступить к самому решению. Этим фактором было непонимание данной проблемы. Я ведь с детства интересовался компьютерами, а животные меня не слишком привлекали. Но это не беда, ведь у нас есть ChatGPT. Всего-то нужно задать ему правильный вопрос. И вот полученный ответ, понятный мне как инженеру:
Если подойти к этому вопросу чисто с технической стороны, я бы предположил что термин “животные” может относиться к набору данных или категорий в компьютерной системе. В этом контексте, “сохранить животных” может означать сохранение и защиту информации или данных внутри приложения или базы данных.
ChatGPT
Правда ChatGPT замечательная вещь? Немного помучал его вопросами, и он выдал нужный мне ответ. Теперь все стало понятно: этим людям нужно решение, которое позволит им сохранять изображения котов, собак или других животных.
Ну что же, проблема идентифицирована и мы наконец-то можем приступить к ее решению.
Давайте определимся с требованиями к нашему приложению. Наш сервис сохранения животных будет доступен по HTTP. Он будет принимать POST запрос с одним или несколькими файлами изображений животных. Также мы будем использовать путь нашего URL для целей категоризации изображений животных.
В итоге, моя инфраструктура будет выглядеть наподобие той что на диаграмме ниже.
Первое чем было решено заняться - это процессинг файлов. Естественно, я имею вполне нормальное желание сделать все быстро. Всю работу связанную с файлам я скину на небольшой сервис под названием Capyfile, код которого можно найти на GitHub. Ему нужно вскормить небольшой конфигурационный файл, которых скажет что я хочу делать с загружаемыми файлам. Мой конфиг выглядит так:
{
"version": "1.0",
"name": "upload",
"processors": [
{
"name": "animal",
"operations": [
{
"name": "file_size_validate",
"params": {
"maxFileSize": {
"sourceType": "http_header",
"source": "X-Capyfile-FileSizeValidate-MaxFileSize"
}
}
},
{
"name": "file_type_validate",
"params": {
"allowedMimeTypes": {
"sourceType": "http_header",
"source": "X-Capyfile-FileTypeValidate-AllowedMimeTypes"
}
}
},
{
"name": "metadata_cleanup"
},
{
"name": "image_convert",
"params": {
"toMimeType": {
"sourceType": "value",
"source": "image/jpeg"
},
"quality": {
"sourceType": "value",
"source": "high"
}
}
},
{
"name": "s3_upload",
"params": {
"accessKeyId": {
"sourceType": "secret",
"source": "aws_access_key_id"
},
"secretAccessKey": {
"sourceType": "secret",
"source": "aws_secret_access_key"
},
"endpoint": {
"sourceType": "env_var",
"source": "AWS_ENDPOINT"
},
"region": {
"sourceType": "env_var",
"source": "AWS_REGION"
},
"bucket": {
"sourceType": "http_header",
"source": "X-Capyfile-S3Upload-Bucket"
}
}
}
]
}
]
}
Из него ясно, что я хочу сделать с каждым загруженным файлом:
Проверить размер файла
Проверить MIME-тип файла
Очистить метаданные файла
Конвертировать файл в JPEG формат
Сохранить файл в совместимое с S3 хранилище
Некоторые из необходимых параметров будут пробрасываться из приложения которое я напишу далее. Другие же параметры будут получены из окружения Docker контейнера.
Теперь финальная часть - написание приложения, которое будет содержит некую бизнес-логику удовлетворяющую моим требованиям. По большей части, оно будет проксировать запросы, попутно обогащая их нужными параметрами. Эти параметры будут говорить Capyfile как проверять файлы и где эти файлы сохранять.
package main
import (
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"strings"
)
const (
Byte = 1 << (iota * 10)
KiByte
MiByte
GiByte
TiByte
PiByte
EiByte
)
func main() {
http.HandleFunc("/", capyfileProxyHandler)
http.ListenAndServe(":8080", nil)
}
func capyfileProxyHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
path := strings.Split(
strings.TrimLeft(r.URL.Path, "/"),
"/")
if len(path) != 1 {
w.WriteHeader(http.StatusNotFound)
return
}
animal := path[0]
if animal == "seagull" {
w.WriteHeader(http.StatusForbidden)
return
}
if animal == "capybara" {
r.Header.Set(
"X-Capyfile-FileSizeValidate-MaxFileSize",
strconv.Itoa(100*MiByte))
r.Header.Set(
"X-Capyfile-FileTypeValidate-AllowedMimeTypes",
`["image/jpeg", "image/png", "image/gif", "image/bmp", "image/webp", "image/heic", "image/heif"]`)
} else {
r.Header.Set(
"X-Capyfile-FileSizeValidate-MaxFileSize",
strconv.Itoa(1*MiByte))
r.Header.Set(
"X-Capyfile-FileTypeValidate-AllowedMimeTypes",
`["image/jpeg", "image/png"]`)
}
// We assume that all the necessary buckets are already created
// or can be created on the fly.
r.Header.Set("X-Capyfile-S3Upload-Bucket", animal)
r.URL.Path = "/upload/animal"
proxy := httputil.NewSingleHostReverseProxy(&url.URL{
Scheme: "http",
Host: "localhost:8024",
})
proxy.ServeHTTP(w, r)
}
Первым делом, мы запустим Capyfile сервер:
docker run --rm \
--name capyfile_server \
--mount type=bind,source=./service-definition.json,target=/etc/capyfile/service-definition.json \
--env CAPYFILE_SERVICE_DEFINITION_FILE=/etc/capyfile/service-definition.json \
--env AWS_ENDPOINT=s3.amazonaws.com \
--env AWS_REGION=us-west-1 \
--secret aws_access_key_id \
--secret aws_secret_access_key \
-p 8024:8024 \
capyfile/capysvr:latest
Затем запускаем наше приложение:
go run animal_saver.go
Теперь все готово для сохранения животных в S3 хранилище.
Здесь вы могли увидеть как легко я решил проблему сохранения животных.
Также вы не могли не заметить, что Capyfile существенно ускорил разработку данного решения. Поэтому хочу побудить вас оказать этому проекту свою поддержку. С благодарностью принимаются дельные мысли, идеи, пул-реквесты.