Ответы пользователя по тегу Go
  • Как настроить 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)
    }
    Ответ написан
    Комментировать
  • Нужны ли несколько сессий для MongoDB (mgo) в Golang?

    Судя по документации, там используется пул соединений, то есть, и так создается несколько подключений к базе и запросы балансируются между ними.
    Ответ написан
    Комментировать
  • Как правильно использовать базу данных для чата?

    Если вам нужны связи, то лучше взять PostgreSQL, например, вместо Монги. Там есть и геолокационные фишки и даже с JSON можно нативно работать.
    Ответ написан
    6 комментариев
  • Как лучше запустить серьезный GO веб-сервис в продакшен?

    Демонизировать лучше внешними средствами. systemd или docker, например.
    Ответ написан
    Комментировать
  • Распределенный чат/систему оповещений, на чем писать?

    Go + websockets
    Ответ написан
    Комментировать
  • Как в Golang сделать несколько слушателей из одного канала?

    Посланное в канал сообщение всегда приходит только одному слушателю. Чтобы сообщение гарантированно доставлялось n-му количеству слушателей, придется делать массив каналов, по одному на каждого слушателя или специального одинокого приемщика, который будет один читать из канала и рассылать всем сообщение.
    Ответ написан
    1 комментарий
  • Go, как парсить XML?

    Примерно так: https://play.golang.org/p/yiKGZY4GZL

    package main
    
    import (
    	"encoding/xml"
    	"fmt"
    	"log"
    )
    
    type CNode struct {
    	Hash string `xml:"hash,attr"`
    	Node string `xml:"node,attr"`
    }
    
    type Features struct {
    	XMLName    xml.Name `xml:"stream features"`
    	Mechanisms []string `xml:"mechanisms>mechanism"`
    	C          CNode    `xml:"c"`
    }
    
    func main() {
    	raw_data := []byte(`
            <stream:features>
                <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
                <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
                    <mechanism>PLAIN</mechanism>
                    <mechanism>DIGEST-MD5</mechanism>
                    <mechanism>SCRAM-SHA-1</mechanism>
                </mechanisms>
                <c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.process-one.net/en/ejabberd/' ver='NUUMEO3rKA30XLGO1FbA9EZT1rY='/>
                <register xmlns='http://jabber.org/features/iq-register'/>
            </stream:features>
        `)
    
    	var v Features
    	err := xml.Unmarshal(raw_data, &v)
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	fmt.Printf("%+v\n", v)
    }


    В принципе, спецификация и пара примеров есть здесь https://golang.org/pkg/encoding/xml
    Ответ написан
    Комментировать
  • Как в Go прочитать несколько строк не разрывая соединения?

    Вот, пример кода. Здесь мы читаем входящие данные построчно и посылаем "Message received" после прочтения каждой строки. Чтение продолжается пока клиент не закроет соединение.

    package main
    
    import (
    	"bufio"
    	"log"
    	"net"
    )
    
    func main() {
    	ln, _ := net.Listen("tcp", ":6556")
    	defer ln.Close()
    	for {
    		conn, _ := ln.Accept()
    		go handleServer(conn)
    	}
    }
    
    func handleServer(conn net.Conn) {
    	reader := bufio.NewReader(conn)
    	defer conn.Close()
    
    	for {
    		line, err := reader.ReadString('\n')
    		if err != nil {
    			return
    		}
    		conn.Write([]byte("Message received.\n"))
    		log.Printf("Received line length: %d\n", len(line))
    	}
    }
    Ответ написан
    4 комментария
  • Какова скорость обработки текста в Go?

    Штатный модуль регулярный выражений, который написан на go сильно уступает в производительности перловому.
    Но к Go можно подключить PCRE https://godoc.org/github.com/glenn-brown/golang-pk... и все будет сравнимо по скорости с перлом.

    Если же речь не про регулярные выражения, а про анализаторы, написанные руками, то Go на данной задаче точно переплюнет perl.
    Ответ написан
    2 комментария
  • Не могу правильно послать командную строку exec в Go, в чем ошибка?

    Нужно вот так:
    exec.Command(
        "composite",
        "-compose","Dst_Over",
        "-tile","pattern:checkerboard",
        `C:\go_project\src\parsing\2.png`,
        `C:\go_project\src\parsing\test1.png`,
    )
    Ответ написан