Можем ли мы сохранить животных с помощью Golang?

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Статья, главным образом, состоит из двух частей: описания проблемы и описания ее решения. Если сама проблема вас не интересует, первый раздел можно пропустить без ущерба для себя либо животных. Или вообще можно всю статью пропустить.

Идентифицируем проблему

В начале вас ждет небольшое, но важное вступление. Оно поможет увидеть как я докопался до сути проблемы и затем, перешел к ее решению.

Я разработчик и я предпочитаю проводить время со своим компьютером. Но все же иногда мне нужно выходить из дома, вы знаете, делать все те вещи, что делают другие люди. И вот однажды, возвращаясь домой со своей сумкой продуктов я увидел некоторую картину: группа людей с плакатами на которых написано “Save animals”. Как я уже говорил, я разработчик и прекрасно понимаю английский. Они, очевидно, хотели сохранить животных. И раз столько людей собрались вместе - это очень серьезная проблема, подумал я.

У меня нет фото с стого протеста, но есть одно фото с протеста против использования javascript на бэкэнде.
У меня нет фото с стого протеста, но есть одно фото с протеста против использования javascript на бэкэнде.

Эти люди не знали кто только что прошел мимо них. Я разработчик - один из тех людей которые делают мир лучше. И я намерен решить их проблему.

Не могу удержаться от проэктирования своего кода на стену. Но вот IDE хочу поменять, может что-то от JetBrains попробую.
Не могу удержаться от проэктирования своего кода на стену. Но вот IDE хочу поменять, может что-то от JetBrains попробую.

отя было кое-что, что воспрепятствовало мне тут же приступить к самому решению. Этим фактором было непонимание данной проблемы. Я ведь с детства интересовался компьютерами, а животные меня не слишком привлекали. Но это не беда, ведь у нас есть 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 существенно ускорил разработку данного решения. Поэтому хочу побудить вас оказать этому проекту свою поддержку. С благодарностью принимаются дельные мысли, идеи, пул-реквесты.

Источник: https://habr.com/ru/articles/753966/


Интересные статьи

Интересные статьи

Пожалуй, сейчас уже нет ни одного специалиста по тестированию, который бы не задумывался над вопросом автоматизации тестирования. Великое множество фреймворков, языков, специальных инструментов автома...
Все секреты малиновой строки «Я ищу…» на Wildberries и ответы на вопросы селлеров по SEO-продвижению, то, что вы всегда хотели узнать — мы расскажем в этом материале.Почти 3 года мы, Наталья Петрова и...
"Существуют три вида лжи: - ложь- наглая ложь- пропаганда статистика- источник цитаты в интернете"Марк Твен (ну или не он)В данной статье на рассмотрим, как можно быстро доказать следующие утверждения...
Со времен первой версии Deno стал модным словом для разработчиков Javascript/TypeScript/Node. Давайте погрузимся в эту технологию, создав защищенный с помощью JWT REST AP...
Когда мы создаем программное обеспечение, мы хотим создавать «-способности»: понятность, ремонтопригодность, расширяемость и - в тренде сейчас - декомпозицию (чтобы мы могли разложить мон...