Я очень плохо знаком с языком Go и пытаюсь обернуть голову вокруг каналов. Чтобы очистить свое понимание, я просмотрел видеоуроки, прочитал несколько книг, но я все еще чувствую растерянность, когда дело доходит до практического кодирования и использования каналов в веб-приложении, написанном на Go.
Я пытаюсь создать 2 URL-адреса:
- Обычный обычный URL GET или POST, который отображает или получает значение и
обработайте это. В бэк-энде происходит некоторая обработка, и я хочу, чтобы
обработка вывода для отправки в обновлении веб-сокета к тому же
URL, поэтому обновление / перезагрузка окна не требуется.
- URL-адрес веб-сокетов на основе пакетов Gorilla.
Ниже приведен тестовый код, который я пробовал, который все еще является урезанной версией кода, который я сделал, пытаясь найти решение:
//file main.go
package main
import (
"io"
"net/http"
"fmt"
"math/rand"
"log"
"time"
"github.com/gorilla/websocket"
)
func logging(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Println(r.URL.Path)
if r.URL.Path == `/ws` {
log.Println("WebSocket is accessed from ws://localhost:8080/ws")
}
f(w, r)
}
}
type hotcat int
func (c hotcat) ServeHTTP(res http.ResponseWriter, req *http.Request) {
io.WriteString(res, "cat cat cat")
//Some code here who's output I want to pass to websockets url ws://localhost:8080/ws
n := timeConsumingWork(4)
fmt.Println("Random Number Print from cat: ", n)
//Example the value of n I need to pass to ws://localhost:8080/ws, how can I do it?
// Some other example test code just giving some random output from hotcat http handler
// Would like to pass it's output to ws://localhost:8080/ws to print in websocckets output in browser
go func(){
out := make(chan string)
go func(){
for i := 0; ; i++ {
out <- `foo said something`
time.Sleep(time.Duration(rand.Intn(2e3)) * time.Millisecond)
}
//out <- `foo said something`
}()
printer(out)
}()
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// Execute this in browser console to initiate websococket connection and to send ws.send() commands etc.
/*
var ws = new WebSocket("ws://localhost:8080/ws")
ws.addEventListener("message", function(e) {console.log(e);});
ws.onmessage = function (event) {
console.log(event.data);
}
ws.send("foo")
ws.send(JSON.stringify({username: "Sat"}))
ws.readyState
ws.CLOSED
ws.OPEN
ws.close()
*/
func ws(w http.ResponseWriter, r *http.Request) {
socket, err := upgrader.Upgrade(w, r, nil)
if err != nil {
fmt.Println(err)
return
}
for {
msgType, msg, err := socket.ReadMessage()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(msg))
if err = socket.WriteMessage(msgType, msg); err != nil {
fmt.Println(err)
}
}
}
func main() {
var c hotcat
http.Handle("/cat", c)
http.HandleFunc("/ws", logging(ws))
http.ListenAndServe(":8080", nil)
}
func timeConsumingWork(n int) int {
time.Sleep(time.Microsecond * time.Duration(rand.Intn(500)))
return n + rand.Intn(1000)
}
func printer(in <-chan string) {
//log.Println(<-in)
go func() {
for {
log.Println(<-in)
}
}()
}
# command shell output
$ go run main.go
Random Number Print from cat: 891
2019/03/11 14:15:32 foo said something
2019/03/11 14:15:33 /ws
2019/03/11 14:15:33 WebSocket is accessed from ws://localhost:8080/ws
foo
2019/03/11 14:15:34 foo said something
2019/03/11 14:15:34 foo said something
2019/03/11 14:15:34 foo said something
2019/03/11 14:15:36 foo said something
2019/03/11 14:15:36 foo said something
^Csignal: interrupt
$
Я хочу отобразить случайную строку вывода "2019/03/11 14:15:34 foo сказал что-то", как выходные данные в выводе websocket в браузере.
Я бы очень признателен за руководство или помощь.
Я думаю, что комментарии в коде, выводе терминала и скриншоте браузера для этого вопроса должны прояснить, что я пытаюсь сделать, но если этот вопрос все еще неясен, пожалуйста, дайте мне знать, я постараюсь расширить его больше.
Спасибо и всего наилучшего,
Сатиндер
Обновление 1:
Я прочитал, попробовал пример приложения чата Mat Ryer: https://github.com/matryer/goblueprints/tree/master/chapter1/chat
Вот код для копирования: https://github.com/satindergrewal/golang-practice/tree/master/chat-examples/mychat02
Из примера я понимаю, что, если у меня есть дескриптор веб-сокета, я могу направлять сообщения из этого дескриптора http веб-сокета в другие подключенные веб-клиенты. Но я до сих пор не понимаю, как отправить сообщение с http-дескриптора, не являющегося веб-сокетом, на маршрут / адрес дескриптора веб-сокета.
Я знаю, что не могу просто использовать этот код для /
ServeHTTP
:
// ServeHTTP handles the HTTP request.
func (t *templateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
t.once.Do(func() {
t.templ = template.Must(template.ParseFiles(filepath.Join("templates", t.filename)))
})
fmt.Println(r.Host)
t.templ.Execute(w, r)
var room *room
socket, _ := upgrader.Upgrade(w, r, nil)
client := &client{
socket: socket,
send: make(chan []byte, messageBufferSize),
room: room,
}
room.join <- client
go func() {
for i := 0; i < 10; i++ {
time.Sleep(time.Duration(rand.Intn(8e3)) * time.Millisecond)
client.socket.WriteMessage(websocket.TextMessage, []byte("Hello from / ServeHTTP Handle"))
//fmt.Println("Sending automatic hello from root ServeHTTP handle to web page!")
}
}()
}
Это уже дает мне следующую ошибку:
localhost:8080
2019/03/25 11:19:18 http: superfluous response.WriteHeader call from github.com/gorilla/websocket.(*Upgrader).returnError (server.go:81)
2019/03/25 11:19:18 http: panic serving [::1]:52691: runtime error: invalid memory address or nil pointer dereference
goroutine 39 [running]:
net/http.(*conn).serve.func1(0xc00013e140)
/usr/local/Cellar/go/1.12.1/libexec/src/net/http/server.go:1769 +0x139
panic(0x13a3e00, 0x172dc20)
/usr/local/Cellar/go/1.12.1/libexec/src/runtime/panic.go:522 +0x1b5
main.(*templateHandler).ServeHTTP(0xc00008ef60, 0x14954a0, 0xc0001dc380, 0xc000214200)
/Users/satinder/go/src/golang-practice/chat-examples/mychat02/main.go:40 +0x209
net/http.(*ServeMux).ServeHTTP(0x173cfa0, 0x14954a0, 0xc0001dc380, 0xc000214200)
/usr/local/Cellar/go/1.12.1/libexec/src/net/http/server.go:2375 +0x1d6
net/http.serverHandler.ServeHTTP(0xc000130000, 0x14954a0, 0xc0001dc380, 0xc000214200)
/usr/local/Cellar/go/1.12.1/libexec/src/net/http/server.go:2774 +0xa8
net/http.(*conn).serve(0xc00013e140, 0x1495ba0, 0xc0000a0380)
/usr/local/Cellar/go/1.12.1/libexec/src/net/http/server.go:1878 +0x851
created by net/http.(*Server).Serve
/usr/local/Cellar/go/1.12.1/libexec/src/net/http/server.go:2884 +0x2f4
Обновление 2: Попробовал иначе, после перечитывания первого ответа из комментариев снова.
// ServeHTTP handles the HTTP request.
func (t *templateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
t.once.Do(func() {
t.templ = template.Must(template.ParseFiles(filepath.Join("templates", t.filename)))
})
fmt.Println(r.Host)
t.templ.Execute(w, r)
room := newRoom()
go func() {
for i := 0; i < 10; i++ {
time.Sleep(time.Duration(rand.Intn(8e3)) * time.Millisecond)
room.forward <- []byte("Hello from / ServeHTTP Handle")
//client.socket.WriteMessage(websocket.TextMessage, []byte("Hello from / ServeHTTP Handle"))
fmt.Println("Sending automatic hello from root ServeHTTP handle to web page!")
}
}()
}
Теперь это не выдает ошибку, но я не вижу консоли, показывающей добавленный второй клиент, которого я ожидал, что /
добавлен через командную строку.
GoldenBook:mychat02 satinder$ go build -o chat
GoldenBook:mychat02 satinder$ ./chat
2019/03/25 11:37:49 Starting web server on :8080
localhost:8080
New client joined
^C
Попробовал еще раз с предыдущим и новым микшированием кода, и вот результат:
// ServeHTTP handles the HTTP request.
func (t *templateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
t.once.Do(func() {
t.templ = template.Must(template.ParseFiles(filepath.Join("templates", t.filename)))
})
fmt.Println(r.Host)
t.templ.Execute(w, r)
room := newRoom()
socket, _ := upgrader.Upgrade(w, r, nil)
client := &client{
socket: socket,
send: make(chan []byte, messageBufferSize),
room: room,
}
room.join <- client
go func() {
for i := 0; i < 10; i++ {
time.Sleep(time.Duration(rand.Intn(8e3)) * time.Millisecond)
room.forward <- []byte("Hello from / ServeHTTP Handle")
//client.socket.WriteMessage(websocket.TextMessage, []byte("Hello from / ServeHTTP Handle"))
//fmt.Println("Sending automatic hello from root ServeHTTP handle to web page!")
}
}()
}
GoldenBook:mychat02 satinder$ go build -o chat
GoldenBook:mychat02 satinder$ ./chat
2019/03/25 11:40:44 Starting web server on :8080
localhost:8080
2019/03/25 11:40:50 http: superfluous response.WriteHeader call from github.com/gorilla/websocket.(*Upgrader).returnError (server.go:81)
^C
Все еще чувствуя себя смущенным ...
Может кто-нибудь дать мне решение этой проблемы? Буду очень признателен за вашу помощь.
Заранее спасибо.
Сатиндер