Ответы пользователя по тегу Go
  • Как побороть дублирование кода?

    Небольшая копипаста, это нормально для go.
    У вас тут другая страшная проблема, вы создаете мьютексы как локальные переменные. В результате они бесполезны здесь.
    Ответ написан
    9 комментариев
  • Как перейти на другую версию go?

    Зачем вам go на сервере? Деплойте туда уже собранные бинарники и нет проблем.
    Соберите бинарь аппликухи на go 1.3 и на go 1.6. Если с 1.6 не пойдет, просто запустите старый бинарь с 1.3.
    Ответ написан
    Комментировать
  • Как преобразовать структуру в JSON?

    Поля, названные с маленькой буквы считаются private, поэтому в json не попадают. Таким же образом работают имена переменных в пакете, например. Читайте основы.
    Ответ написан
    1 комментарий
  • Как отправить POST запрос с определенного IP адреса?

    Нужно создать клиента с определенным дайлером
    localAddr, err := net.ResolveIPAddr("ip", "192.168.1.2")
    if err != nil {
      panic(err)
    }
     
    localTCPAddr := net.TCPAddr{
        IP: localAddr.IP,
    }
     
    client := &http.Client{
      Transport: &http.Transport{
        Dial: (&net.Dialer{
          LocalAddr: localTCPAddr,
        }).Dial,
      },
    }


    Потом через client уже отправлять запрос
    Ответ написан
    Комментировать
  • Как правильно получить данные с бд и отобразить в шаблоне?

    нужно не .rslts.Id, а просто .Id, вы же передаете уже внутренности rslts, не нужно ее имя писать еще раз. Тем более, у вас там цикл и внутри него вы обращаетесь к одному элементу массива rslts.
    Ответ написан
    Комментировать
  • Как разбить строку?

    https://play.golang.org/p/uPJg6g2CcB
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	str := "somehash"
    
    	p1 := str[:4]
    	p2 := str[4:]
    
    	fmt.Println(p1)
    	fmt.Println(p2)
    }


    Это если у вас изначальная строка из 8 символов. Если нет, то нужно добавить еще границу p2 := str[4:8].
    Учтите, что это все на указателях работает, соответственно, при изменении данных в p1 или p2 они поменяются и в исходной строке и наоборот.
    Ответ написан
    Комментировать
  • Как решить проблему с go + mysql?

    Проверьте, что mysql запущен и действительно слушает данный порт по данному адресу. У вас просто ошибка подключения к базе.
    Ответ написан
  • Зачем в языке Go приняты отступы в 8 символов?

    Там не 8 символов, там tab. Вы можете настроить в вашем текстовом редакторе размер табуляции в нужное вам количество символов.
    Ответ написан
    Комментировать
  • Стоит ли изучать GoLang вместе с изучением алгоритмов?

    Go не подходит на роль языка "совершенно другой парадигмы". Если хотите такой язык, гляньте в сторону Haskell, Clojure, Lisp.
    Go подходит на роль языка с нестандартным ООП и нестандартной работой с многопоточностью.
    Для общего развития точно стоит его посмотреть. Прежде всего, он более низкоуровневый, чем ПХП, соответственно, вы сможете увидеть и понять некоторые вещи, о которых раньше не задумывались, которые были незаметны пользователю в ПХП, но тем не менее важны для понимания. Плюс, поработаете с компилируемым языком.
    Ответ написан
    1 комментарий
  • Как настроить ngnix + go?

    Просто делайте приложение как обычный http-сервер. Через http.ListenAndServe, например. В nginx делаете так:
    server {
        listen       80;
        server_name  MyDomain.ru;
        location / {
            proxy_pass http://127.0.0.1:9000;
            proxy_set_header  X-Real-IP         $remote_addr;
        }
    }


    X-Real-IP нужен, чтобы ваше приложение видело, какой у пользователя айпишник, ибо к приложению всегда будет обращаться nginx. "X-Real-IP" будет одним из заголовков запроса к приложению.
    Ответ написан
    5 комментариев
  • Есть ли альтернатива переопределению методов в Go?

    В go предполагается вот такой стиль:
    https://play.golang.org/p/uFA4rWeHn4
    package main
    
    import (
    	"fmt"
    )
    
    //
    // Inteface
    //
    
    type Gettable interface {
    	Get() string
    }
    
    //
    // Impl A
    //
    
    type A struct {
    }
    
    func (a *A) Get() string {
    	return "A"
    }
    
    //
    // Impl B
    //
    
    type B struct {
    }
    
    func (b *B) Get() string {
    	return "B"
    }
    
    //
    // Main
    //
    
    func main() {
    	a := A{}
    	b := B{}
    	PrintSomeStuff(&a)
    	PrintSomeStuff(&b)
    }
    
    func PrintSomeStuff(obj Gettable) {
    	fmt.Println(obj.Get())
    }
    Ответ написан
    2 комментария
  • Как отправить данные при помощи канала в определённую Go рутину?

    Грубо говоря, вот так можно
    package main
    
    import (
    	"log"
    	"net/http"
    	"sync/atomic"
    	"time"
    
    	"github.com/gorilla/websocket"
    	"github.com/julienschmidt/httprouter"
    )
    
    type Client struct {
    	c *websocket.Conn
    }
    
    func (this *Client) sendMessage(msg string) {
    	err := this.c.WriteMessage(websocket.TextMessage, []byte(msg))
    	if err != nil {
    		log.Println("write:", err)
    	}
    }
    
    type Pool struct {
    	lastId     uint64
    	addChan    chan (*Client)
    	removeChan chan (uint64)
    	msgChan    chan (string)
    	clients    map[uint64]*Client
    }
    
    func (this *Pool) serviceRoutine() {
    	for {
    		select {
    		case newClient := <-this.addChan:
    			this.clients[this.lastId] = newClient
    		case id := <-this.removeChan:
    			delete(this.clients, id)
    			log.Printf("Client with id %d disconnected\n", id)
    		case msg := <-this.msgChan:
    			for _, client := range this.clients {
    				client.sendMessage(msg)
    			}
    		}
    	}
    }
    
    func (this *Pool) addClient(client *Client) uint64 {
    	newId := atomic.AddUint64(&this.lastId, 1)
    	this.addChan <- client
    	log.Printf("Client with id %d connected\n", newId)
    	return newId
    }
    
    func NewPool() *Pool {
    	pool := &Pool{
    		addChan:    make(chan *Client),
    		removeChan: make(chan uint64),
    		msgChan:    make(chan string, 5),
    		clients:    make(map[uint64]*Client),
    	}
    	go pool.serviceRoutine()
    	return pool
    }
    
    var pool *Pool = NewPool()
    
    func main() {
    	go func() {
    		//здесь я получаю данные которые необходимо "проксировать"
    		ticker := time.NewTicker(time.Second)
    		for range ticker.C {
    			// Просто посылаем текущее время раз в секунду всем подключенным клиентам
    			pool.msgChan <- time.Now().Format("Mon Jan 2 15:04:05 -0700 MST 2006")
    		}
    	}()
    	router := httprouter.New()
    	router.GET("/events/ws/", EventsWSHandler)
    	router.NotFound = http.FileServer(http.Dir("www/"))
    	log.Fatal(http.ListenAndServe(":3000", router))
    }
    
    var upgrader = websocket.Upgrader{}
    
    func EventsWSHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    
    	c, err := upgrader.Upgrade(w, r, nil)
    	if err != nil {
    		log.Print("upgrade:", err)
    		return
    	}
    	defer c.Close()
    
    	id := pool.addClient(&Client{c: c})
    	defer func() {
    		pool.removeChan <- id
    	}()
    
    	for {
    		mt, message, err := c.ReadMessage()
    		if err != nil {
    			log.Println("read:", err)
    			break
    		}
    		log.Printf("recv: %d %s", mt, message)
    	}
    }
    Ответ написан
  • Почему не отвечает веб сервер?

    Добавьте в конец каждой строки \r\n, а после всего запроса сделайте это еще раз. Иначе сервер не поймет как разделять заголовки между собой и как определить конец запроса.

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"log"
    	"net"
    )
    
    func main() {
    	conn, err := net.Dial("tcp", "ya.ru:80")
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	fmt.Fprintf(conn, "GET / HTTP/1.1\r\n")
    	fmt.Fprintf(conn, "Host: localhost\r\n")
    	fmt.Fprintf(conn, "User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:38.0) Gecko/20100101 Firefox/38.0\r\n")
    	fmt.Fprintf(conn, "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n")
    	fmt.Fprintf(conn, "Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3\r\n")
    	fmt.Fprintf(conn, "Connection: close\r\n")
    	fmt.Fprintf(conn, "\r\n")
    	for {
    		message, err := bufio.NewReader(conn).ReadString('\n')
    		if err != nil {
    			log.Fatal(err)
    		}
    		fmt.Print("Message from server: " + message)
    	}
    }
    Ответ написан
  • Как настроить на авторизацию по паролю?

    Полагаю, так должно работать.
    package main
    
    import (
    	"github.com/armon/go-socks5"
    )
    
    func main() {
    
    	conf := &socks5.Config{
    		AuthMethods: []socks5.Authenticator{
    			&socks5.UserPassAuthenticator{
    				socks5.StaticCredentials{
    					"username1": "password1",
    					"username2": "password2",
    					"username3": "password3",
    				},
    			},
    		},
    	}
    
    	server, err := socks5.New(conf)
    	if err != nil {
    		panic(err)
    	}
    
    	// Create SOCKS5 proxy on localhost port 8000
    	if err := server.ListenAndServe("tcp", "127.0.0.1:8000"); err != nil {
    		panic(err)
    	}
    }


    Поясню, почему автор библиотеки сделал именно так.
    AuthMethods является массивом, чтобы можно было задать одновременно несколько методов аутентификации, если один не прошел, пробуется следующий из массива.
    Authenticator — это интерфейс, позволяющий подставлять на свое место все объекты, у которых есть методы:
    Authenticate(reader io.Reader, writer io.Writer) (*AuthContext, error)
    и
    GetCode() uint8

    UserPassAuthenticator как раз реализует эти методы для случая аутентификации по имени/паролю.
    Внутри него есть поле Credentials, в которое можно подставить любой объект, удовлетворяющий интерфейсу CredentialStore, т.е., имеющий метод Valid(user, password string) bool. Соответственно, вы можете сюда подставить свой объект, которому аутентификатор будет кидать пару имя/пароль, а объект в ответ будет выдавать, валидная это пара или нет.
    Простейшая реализация такого объекта есть в модуле в виде объекта StaticCredentials, который по сути является map[string]string и имеет метод, который проверяет, есть ли в этом map переданная пара юзер/пароль.

    Т.е., модуль предоставляет вам выбор, использовать штатные реализации аутентификации или писать свои.
    Ответ написан
    Комментировать
  • Как отправить данные во все рутины?

    Вот пример с пулом клиентов и сохранением в map.
    Клиентам рассылается то, что набрано на сервере, данные, пришедшие от клиентов обрабатываются.

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"log"
    	"net"
    	"os"
    	"strconv"
    	"strings"
    )
    
    var messages chan string
    
    type Client struct {
    	Id      uint64
    	MsgChan chan (string)
    }
    
    type ClientPool struct {
    	counter    uint64
    	joins      chan (Client)
    	lefts      chan (uint64)
    	ids        chan (uint64)
    	broadcasts chan (string)
    	clients    map[uint64]Client
    }
    
    func NewClientPool() *ClientPool {
    	pool := ClientPool{
    		joins:      make(chan (Client)),
    		lefts:      make(chan (uint64)),
    		ids:        make(chan (uint64)),
    		broadcasts: make(chan (string)),
    		clients:    make(map[uint64]Client),
    	}
    
    	go func() {
    		var id uint64
    		for {
    			id++
    			pool.ids <- id
    		}
    	}()
    
    	go func() {
    		for {
    			select {
    			case newClient := <-pool.joins:
    				pool.clients[newClient.Id] = newClient
    			case idForDeletion := <-pool.lefts:
    				delete(pool.clients, idForDeletion)
    			case text := <-pool.broadcasts:
    				for _, client := range pool.clients {
    					client.MsgChan <- text
    				}
    			}
    		}
    	}()
    
    	return &pool
    }
    
    func (this *ClientPool) NewClient() Client {
    	client := Client{
    		Id:      <-this.ids,
    		MsgChan: make(chan (string)),
    	}
    	this.joins <- client
    	return client
    }
    
    func (this *ClientPool) BroadcastMessage(text string) {
    	this.broadcasts <- text
    }
    
    func (this *ClientPool) DeleteClient(client Client) {
    	this.lefts <- client.Id
    }
    
    func main() {
    	pool := NewClientPool()
    	var port int = 3333
    	listen, err := net.Listen("tcp4", ":"+strconv.Itoa(port))
    	defer listen.Close()
    	if err != nil {
    		log.Fatalf("Прослушивание порта %d не удалось,\r\n\r\n %s", port, err)
    		os.Exit(1)
    	}
    
    	go func() {
    
    		log.Printf("Сервер слушает порт: %d", port)
    		reader := bufio.NewReader(os.Stdin)
    		for {
    			fmt.Print("Enter text: ")
    			text, _ := reader.ReadString('\n')
    			log.Print(text)
    			pool.BroadcastMessage(text)
    		}
    
    	}()
    
    	for {
    		conn, err := listen.Accept()
    		if err != nil {
    			log.Fatalln(err)
    			continue
    		}
    		go handler(conn, pool)
    	}
    }
    
    func handler(conn net.Conn, pool *ClientPool) {
    	client := pool.NewClient()
    	defer pool.DeleteClient(client)
    	defer conn.Close()
    	defer log.Printf("Клиент с номером %d вышел\n", client.Id)
    
    	log.Printf("Новый клиент присоединен, ему присвоен номер %d", client.Id)
    
    	incomingClientMsg := make(chan string)
    
    	go func() {
    		reader := bufio.NewReader(conn)
    		for {
    			text, err := reader.ReadString('\n')
    			if err != nil {
    				close(incomingClientMsg)
    				return
    			}
    			incomingClientMsg <- text
    		}
    	}()
    
    	for {
    		select {
    		case text := <-incomingClientMsg:
    			text = strings.Trim(text, "\r\n")
    			if text == "/quit" {
    				return
    			}
    			log.Printf("Клиент с номером %d написал: %s\n", client.Id, text)
    		case text := <-client.MsgChan:
    			_, err := conn.Write([]byte(text))
    			if err != nil {
    				return
    			}
    		}
    	}
    }
    Ответ написан
  • Как запустить несколько рутин?

    Запускать горутины с помощью команды go.
    Общение между горутинами делать с помощью каналов.

    Есть хороший сайт https://gobyexample.com
    Сейчас он почему-то недоступен, надеюсь, что временно. Пройдите там туториалы по-порядку для усвоения основ.
    Ответ написан
  • Что выбрать для написание backend к сайту?

    Выбирайте то, на чем вам будет удобнее разрабатывать, все равно все упрется в базу. На 80 rps выбор технологии вообще не критичен.
    Ответ написан
    Комментировать
  • Как изменить символы в шаблоне, заменив {{ и }} на -на Golang?

    template.Must(template.New("").Delims("<%", "%>").ParseGlob("Templates/Main/*/*"))


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

    В чем проблема выведения ошибки в консоль? Если ошибки выводить в STDERR, а обмен данными производить через STDOUT, никаких проблем не будет.
    Общение удобнее организовать через юникс-сокеты или через tcp на localhost. Пускай z-app висит демоном и принимает задачи на обработку.
    Ответ написан
  • Как в Go перевести строку в массив чисел?

    https://play.golang.org/p/gGU5-rsySS
    package main
    
    import (
    	"fmt"
    	"strconv"
    	"strings"
    )
    
    func main() {
    	str := "1,3,5,6,8,42"
    
    	strs := strings.Split(str, ",")
    	var ints []int
    	for _, s := range strs {
    		num, err := strconv.Atoi(s)
    		if err == nil {
    			ints = append(ints, num)
    		}
    	}
    
    	fmt.Println(ints)
    }
    Ответ написан
    Комментировать