Загрузить структуру или объект в корзину S3 с помощью GoLang?

# #amazon-web-services #go #amazon-s3

Вопрос:

Я работаю с SDK AWS S3 в GoLang, играя с загрузками и загрузками в различные корзины. Мне интересно, есть ли более простой способ загружать структуры или объекты непосредственно в корзину?

У меня есть структура, представляющая событие:

 type Event struct {
    ID               string
    ProcessID        string                 
    TxnID            string
    Inputs           map[string]interface{}                      
}
 

Что я хотел бы загрузить в корзину S3. Но код, который я нашел в документации, работает только для загрузки строк.

 func Save(client S3Client, T interface{}, key string) bool {
    svc := client.S3clientObject
    input := amp;s3.PutObjectInput{
        Body: aws.ReadSeekCloser(strings.NewReader("testing this one")),
        Bucket: aws.String(GetS3Bucket()),
        Key: aws.String(GetObjectKey(T, key)),
        Metadata: map[string]*string{
            "metadata1": aws.String("value1"),
            "metadata2": aws.String("value2"),
        },

    }

 

Это позволяет успешно загрузить базовый файл в корзину S3, который при открытии просто читается как «тестирование этого». Есть ли способ загрузить в корзину, чтобы она загружала объект, а не просто строковое значение??

Любая помощь приветствуется, так как я новичок в Go и S3.

Редактировать

Это код, который я использую для функции Get:

 func GetIt(client S3Client, T interface{}, key string) interface{} {
    svc := client.S3clientObject
    s3Key := GetObjectKey(T, key)
    resp, err := svc.GetObject(amp;s3.GetObjectInput{
        Bucket: aws.String(GetS3Bucket()),
        Key: aws.String(s3Key),
    })
    if err != nil {
        fmt.Println(err)
        return err
    }    
    result := json.NewDecoder(resp.Body).Decode(amp;T)
    fmt.Println(result) 
    return json.NewDecoder(resp.Body).Decode(amp;T)
}
 
 func main() {
    client := b.CreateS3Client()
    event := b.CreateEvent()
    GetIt(client, event, key)
}
 

Ответ №1:

Закодируйте значение в байтах и загрузите байты. Вот как закодировать значение в байтах JSON:

 func Save(client S3Client, value interface{}, key string) error {

    p, err := json.Marshal(value)
    if err != nil {
        return err
    }
    input := amp;s3.PutObjectInput{
        Body:   aws.ReadSeekCloser(bytes.NewReader(p)),
        …
    }
    …
}
 

Вызовите Сохранить значение, которое вы хотите загрузить:

 value := amp;Event{ID: "an id", …}
err := Save(…, value, …)
if err != nil {
  // handle error
}
 

Существует множество возможных вариантов, включая gob, xml и json, msgpack и т.д. Наилучший формат кодирования будет зависеть от требований вашего приложения.

Обратный процесс при получении объекта:

 func GetIt(client S3Client, T interface{}, key string) error {
    svc := client.S3clientObject
    resp, err := svc.GetObject(amp;s3.GetObjectInput{
        Bucket: aws.String(GetS3Bucket()),
        Key: aws.String(key),
    })
    if err != nil {
        return err
    }    
    return json.NewDecoder(resp.Body).Decode(T)
}
 

Вызов GetIt с указателем на целевое значение:

 var value model.Event
err := GetIt(client, amp;value, key)
if err != nil {
    // handle error
}
fmt.Println(value) // prints the decoded value.
 

Комментарии:

1. Спасибо! Есть ли шанс, что вы знаете, как сделать обратное и декодировать значения, если бы я пытался загрузить событие из корзины S3 вместо загрузки?

2. Вызов Load с указателем на целевое значение вызывает «панику: ошибка во время выполнения: недопустимый адрес памяти или разыменование указателя с нулем» ошибка

3. Строка паникующего кода расшифровывается := json. Новый декодер(отв.Тело). Декодирование(значение)

4. Сейчас я получаю сообщение об ошибке, в котором говорится, что мой ключ не существует (он существует). Не уверен, почему это так, но я предполагаю, что это что-то выходит за рамки этой ошибки

5. Я предполагаю, что это связано с тем, что я передаю значение ключа в другую функцию, называемую GetObjectKey() (я оставил это, чтобы избежать путаницы), и поскольку ввод теперь является указателем, который портит эту функцию. Есть ли способ разыменовать событиеamp;, которое я передаю в main?

Ответ №2:

Приведенный здесь пример показывает, что S3 позволяет загружать все, что реализует интерфейс ввода-вывода.Reader. В примере используется strings.NewReader синтаксис create a io.Reader , который знает, как предоставить вызывающему объекту указанную строку. Ваша задача (согласно AWS здесь) состоит в том, чтобы выяснить, как адаптировать все, что вам нужно, для хранения в an io.Reader .

Вы можете хранить байты непосредственно в кодировке JSON следующим образом

 package main

import (
    "bytes"
    "encoding/json"
)

type Event struct {
    ID               string
    ProcessID        string
    TxnID            string
    Inputs           map[string]interface{}
}

func main() {
    // To prepare the object for writing
    b, err := json.Marshal(event)
    if err != nil {
        return
    }
    // pass this reader into aws.ReadSeekCloser(...)
    reader := bytes.NewReader(b)
}
 

Комментарии:

1. Спасибо! Есть ли шанс, что вы знаете, как сделать обратное и декодировать значения, если бы я пытался загрузить событие из корзины S3 вместо загрузки?