Ответы пользователя по тегу Go
  • Как исправить проблему docker: Error response from daemon: oci runtime error: container_linux.go?

    @ghostiam
    На Go писатель, серверов пинатель.
    Возможно права не передались при добавлении файла в контейнер, попробуйте добавить после добавления файлов:
    RUN chmod +x ./service

    Но я не совсем понимаю, зачем в данном случае нужен образ golang:1.11, если ./service уже является скомпилированным бинарным файлом.
    Если это так, то можно облегчить образ, использовав scratch или alpine как базовый образ:
    FROM alpine
    
    ADD ./service /
    RUN chmod +x /service
    
    EXPOSE 8000
    ENTRYPOINT ["./service"]
    Ответ написан
  • Как сбилдить golang проект, который использует CGO?

    @ghostiam
    На Go писатель, серверов пинатель.
    Если есть докер, стоит попробовать проект xgo ( https://github.com/karalabe/xgo )

    Сам использую чтоб компилировать проекты с cgo на macos для linux x64/arm
    Ответ написан
    6 комментариев
  • Можно ли написать более лаконичный код?

    @ghostiam
    На Go писатель, серверов пинатель.
    Нормально, но нет предела совершенству)

    Пропущенна проверка на ошибки после `err = json.Unmarshal(raw, &packet)`
    так же, код можно упростить, если вложить структуру `RawDataSensorsItems` в `ResultRow`
    Получим:
    type ResultRow struct {
      StreamId int    `json:"stream_id"`
      DateTime string `json:"date_time"`
      RawDataSensorsItems
    }
    
    type RawDataSensorsItems struct {
      AKey    string `json:"a_key"`
      BKey    int    `json:"b_key"`
      SensorA *int    `json:"sensor_a"`
      SensorB *int    `json:"sensor_b"`
      SensorC *int    `json:"sensor_c"`
      SensorD *int    `json:"sensor_d"`
      SensorE *int    `json:"sensor_e"`
      SensorF *int    `json:"sensor_f"`
    }


    Из за чего упроститься код внутри цикла:
    result = append(
            result,
            ResultRow{
                    StreamId: row.StreamId,
                    DateTime: row.DateTime,
                    RawDataSensorsItems: rowS,
            })
    )


    так же, можно использовать не простой `for j := range row.Sensors` по индексам, а сразу со значениями `for _, rowS := range row.Sensors` (игнорируем с помощью `_` индекс, а в `rowS` сразу записываем значение из массива)
    Если так переписать, то получим:
    for _, row := range packet {
        for _, rowS := range row.Sensors {
            result = append(
                    result,
                    ResultRow{
                            StreamId: row.StreamId,
                            DateTime: row.DateTime,
                            RawDataSensorsItems: rowS,
                    })
        }
    }


    Полный код
    package main
    
    import (
    	"encoding/json"
    	"io/ioutil"
    )
    
    func main() {
    	raw, err := ioutil.ReadFile("./data/raw.json")
    	PanicIfErr(err)
    
    	var packet DataPacket
    	var result ResultPacket
    
    	err = json.Unmarshal(raw, &packet)
    	PanicIfErr(err)
    
    	for _, row := range packet {
    		for _, rowS := range row.Sensors {
    			result = append(
    				result,
    				ResultRow{
    					StreamId:            row.StreamId,
    					DateTime:            row.DateTime,
    					RawDataSensorsItems: rowS,
    				})
    		}
    	}
    
    	content, err := json.Marshal(result)
    	PanicIfErr(err)
    
    	err = ioutil.WriteFile("./data/output.json", content, 0644)
    	PanicIfErr(err)
    }
    
    func PanicIfErr(err error) {
    	if err != nil {
    		panic(err)
    	}
    }
    
    type ResultPacket []ResultRow
    
    type ResultRow struct {
    	StreamId int    `json:"stream_id"`
    	DateTime string `json:"date_time"`
    	RawDataSensorsItems
    }
    
    type RawDataSensorsItems struct {
    	AKey    string `json:"a_key"`
    	BKey    int    `json:"b_key"`
    	SensorA *int   `json:"sensor_a"`
    	SensorB *int   `json:"sensor_b"`
    	SensorC *int   `json:"sensor_c"`
    	SensorD *int   `json:"sensor_d"`
    	SensorE *int   `json:"sensor_e"`
    	SensorF *int   `json:"sensor_f"`
    }
    
    type RawDataRow struct {
    	StreamId int                   `json:"stream_id"`
    	DateTime string                `json:"date_time"`
    	Sensors  []RawDataSensorsItems `json:"sensors"`
    }
    
    type DataPacket []RawDataRow
    Ответ написан
    3 комментария
  • Есть ли в GO filter map reduce some every?

    @ghostiam
    На Go писатель, серверов пинатель.
    В го нет "магии" и есть статическая типизация.
    Всю "магию" нужно писать в лоб.
    Переписал ваш пример на го, но это будет работать если тип у поля value всегда будет int, но если там будут разные типы, придётся использовать interface, что не очень хорошо.
    Го не подойдёт, если данные не типизированы(появится морока с конвертацией, а так же снизится производительность, в сравнении с типизированным подходом).

    https://play.golang.org/p/eGfphNwZqRR
    Код
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	type KV struct {
    		Name  string
    		Value int
    	}
    
    	data := []KV{
    		{
    			Name:  "width",
    			Value: 100,
    		},
    		{
    			Name:  "height",
    			Value: 300,
    		},
    	}
    
    	result := make(map[string]int)
    
    	// reduce
    	for _, v := range data {
    		result[v.Name] = v.Value
    	}
    
    	fmt.Printf("%#v", result) // map[string]int{"width":100, "height":300}
    }


    Пример с интерфейсом и разными типами:
    https://play.golang.org/p/OXUVv58YZoa
    Код
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	type KV struct {
    		Name  string
    		Value interface{}
    	}
    
    	data := []KV{
    		{
    			Name:  "width",
    			Value: 100,
    		},
    		{
    			Name:  "height",
    			Value: 300,
    		},
    		{
    			Name:  "image",
    			Value: "cat.jpg",
    		},
    	}
    
    	result := make(map[string]interface{})
    
    	for _, v := range data {
    		result[v.Name] = v.Value
    	}
    
    	fmt.Printf("%#v", result) // map[string]interface {}{"width":100, "height":300, "image":"cat.jpg"}
    }
    Ответ написан
    Комментировать
  • Как динамически выделить array [var]type?

    @ghostiam
    На Go писатель, серверов пинатель.
    Слайсы используют те же массивы под капотом.

    Используя:
    length := 7
    slice := make([]int, length)

    выделяется слайс, да, но он ровно той длины которая была задана, прямо как массив. https://play.golang.org/p/vAQqLI-msfi
    Ответ написан
    Комментировать
  • Как в golang с помощью tgbotapi переслать отправителю его же сообщение?

    @ghostiam
    На Go писатель, серверов пинатель.
    Старый ответ

    как и с сообщениями, у созданных объектов есть свойство ReplyToMessageID в которое нужно записать ID сообщения из update.Message.MessageID
    audioUpload := tgbotapi.NewAudioUpload(update.Message.Chat.ID, ...)
    audioUpload.ReplyMarkup = update.Message.MessageID
    _, err := bot.Send(audioUpload)


    Если возникает вопрос, как вообще отправить файл, то нужно передать структуру tgbotapi.FileBytes или tgbotapi.FileReader вторым параметром в функцию и заполнить её.
    Для примера, отправляем файл с диска:
    file, err := os.Open("audio.mp3")
    		if err != nil {
    			panic(err)
    		}
    		defer file.Close()
    
    		audioUpload := tgbotapi.NewAudioUpload(update.Message.Chat.ID, tgbotapi.FileReader{
    			Name:   "audio.mp3",
    			Reader: file,
    			Size:   -1, // If Size is -1, it will read the entire Reader into memory to calculate a Size.
    		})
    		audioUpload.ReplyToMessageID = update.Message.MessageID
    		_, err := bot.Send(audioUpload)
    		if err != nil {
    			panic(err)
    		}



    UPD: После общения в ЛС, оказалось, что вопрос заключался в создании Echo бота, который мог бы пересылать не только текст, но и картинки, аудио и прочее.

    В данном примере реализована отправка только текста и картинок. Чтобы добавить обработку других типов сообщений, нужно добавить новый `case` в `switch` в функции `OnMessage`:
    Код
    package main
    
    import (
    	"log"
    
    	"github.com/davecgh/go-spew/spew"
    	"github.com/go-telegram-bot-api/telegram-bot-api"
    )
    
    func main() {
    	// подключаемся к боту с помощью токена
    	bot, err := tgbotapi.NewBotAPI("ТОКЕН")
    	if err != nil {
    		log.Panic(err)
    	}
    
    	bot.Debug = true
    	log.Printf("Authorized on account %s", bot.Self.UserName)
    
    	// инициализируем канал, куда будут прилетать обновления от API
    	u := tgbotapi.NewUpdate(0)
    	u.Timeout = 60
    
    	updates, err := bot.GetUpdatesChan(u)
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	// читаем обновления из канала
    	for update := range updates {
    		switch {
    		case update.Message != nil: // Если было прислано сообщение, то обрабатываем, так как могут приходить не только сообщения.
    			OnMessage(bot, update.Message)
    		}
    	}
    }
    
    func OnMessage(bot *tgbotapi.BotAPI, message *tgbotapi.Message) {
    	// Пользователь, который написал боту
    	userName := message.From.UserName
    
    	// ID чата/диалога.
    	// Может быть идентификатором как чата с пользователем
    	// (тогда он равен UserID) так и публичного чата/канала
    	chatID := message.Chat.ID
    
    	log.Printf("[%s] %d", userName, chatID)
    
    	spew.Dump(message) // выводим то что пришло (Для отладки!!!)
    
    	var msg tgbotapi.Chattable
    	switch {
    	case message.Text != "": // Текстовое ли сообщение?
    		msg = tgbotapi.NewMessage(chatID, message.Text)
    
    	case message.Photo != nil: // Это фото?
    		photoArray := *message.Photo
    		photoLastIndex := len(photoArray) - 1
    		photo := photoArray[photoLastIndex] // Получаем последний элемент массива (самую большую картинку)
    		msg = tgbotapi.NewPhotoShare(chatID, photo.FileID)
    
    	default:                                                 // Если не одно условие не сработало
    		msg = tgbotapi.NewMessage(chatID, "Не реализовано") // Отправляется на тот тип сообщения, который ещё не реализован выше ^
    	}
    
    	// и отправляем его
    	_, err := bot.Send(msg)
    	if err != nil {
    		log.Println(err)
    	}
    }
    Ответ написан
    3 комментария
  • Как передать в параметры запроса вложенный массив?

    @ghostiam
    На Go писатель, серверов пинатель.
    client := http.DefaultClient
    
    	form := url.Values{
    		"LoginForm[username]": []string{"user"},
    		"LoginForm[password]": []string{"pass"},
    	}
    
    	response, err := client.Post("http://httpbin.org/post", "application/x-www-form-urlencoded", strings.NewReader(form.Encode()))
    	if err != nil {
    		panic(err)
    	}
    	defer response.Body.Close()
    
    	b, err := ioutil.ReadAll(response.Body)
    	if err != nil {
    		panic(err)
    	}
    
    	println(string(b))
    Ответ написан
    4 комментария
  • Как ускорить http сервер на golang?

    @ghostiam
    На Go писатель, серверов пинатель.
    Что делает сервер? Точно ли упираетесь в скорость http сервера?
    Обычно, http сервер не является бутылочным горлышком.
    Ответ написан
  • Как правильно именовать файлы, имена которых состоят из нескольких слов?

    @ghostiam
    На Go писатель, серверов пинатель.
    Если посмотреть на существующие проекты на го, то каждый использует что хочет, так как нет стандарта наименования.
    Например:
    Имена через нижнее подчёркивание: GORM
    Имена написанные вместе: Docker(Moby)
    директории (1) (2)
    файлы
    Ответ написан
    Комментировать
  • Почему ничего не выводит?

    @ghostiam
    На Go писатель, серверов пинатель.
    Строка: json.Unmarshal(byteString,&simpleResp)
    возвращает ошибку:
    json: cannot unmarshal array into Go struct field Response.Data of type main.sampleArray
    Ответ написан
    5 комментариев
  • Как отправить изображение чтобы оно открылось в браузере, а не скачивалось?

    @ghostiam
    На Go писатель, серверов пинатель.
    content-type: image/png (jpeg or gif)

    (Ответ в комментариях)
    Ответ написан
    5 комментариев
  • Если ли аналог плагина hapi-swagger для Go?

    @ghostiam
    На Go писатель, серверов пинатель.
    https://github.com/go-swagger/go-swagger

    Генерирует документацию по комментариям в коде, также, автоматически генерирует json ответы по имени структуры.
    Документация по генератору: https://goswagger.io/use/spec.html
    Ответ написан
    Комментировать
  • Пример архитектуры хорошего Golang веб-приложения?

    @ghostiam
    На Go писатель, серверов пинатель.
    Мне нравится подход Clean architecture
    Вот есть неплохая модификация:
    Статья
    Код

    Но самое главное, для хорошей масштабируемости и слабой зависимости компонентов, это:
    - не использовать глобальные переменные/синглтоны.
    - не передавать объекты через функции/методы/и т.п., где нужна только одна переменная из этого объекта.
    - использовать интерфейсы и чистые модели(без логики).
    Ответ написан
    Комментировать
  • Можно ли получить информацию, что в БД появилось запись?

    @ghostiam
    На Go писатель, серверов пинатель.
    Почему бы просто не слать уведомление через WebSocket после добавления в бд записи? Не придётся опрашивать просто так в бд.
    Псевдокод:
    func onMessage(message Message) {
        db.Save(message)
        chat.Notification(message)
    }
    Ответ написан
    Комментировать
  • Запрос к SphinxSearch на Go?

    @ghostiam
    На Go писатель, серверов пинатель.
    Сфинкс не работает с prepare statements, сам столкнулся с этой проблемой. Как решение, экранировать символы самостоятельно.

    Вот как сделано экранирование в апи сфинкса для пхп
    https://github.com/sphinxsearch/sphinx/blob/6adceb...
    Ответ написан
    Комментировать
  • Как в Gorm на golang использовать jsonb(PostgreSQL)?

    @ghostiam
    На Go писатель, серверов пинатель.
    Для автосоздания поля с необходимым типом данных, нужно поставить тег описывающий тип:
    `gorm:"type:jsonb(PostgreSQL);"`


    Если нужен тип данных JSONB в самом го, можно глянуть тут:
    Gorm JSONB
    Ответ написан
    Комментировать