Итак, @Slabgorb верен - если вы посмотрите здесь (https://github.com/sacOO7/GoWebsocket/blob/master/gowebsocket.go#L87), вы увидите, что OnConnectErrorHandler
вызывается синхронно во время выполнения вашего вызова к Connect()
. Функция Connect()
не ' t запустить отдельную процедуру обработки веб-сокета до тех пор, пока соединение не будет полностью установлено и обратный вызов OnConnected
не завершен. Поэтому, когда вы пытаетесь записать в небуферизованный канал done
, вы блокируете тот же подпрограмма, которая вначале вызывала функцию run()
, и вы зашли в тупик, потому что ни одна подпрограмма никогда не сможет читать с канала, чтобы разблокировать вас.
Так что вы могли бы пойти с его решением и превратить его в буферизованный канал, и это сработает, но я бы предложил не записывать в канал для такого рода одноразового поведения флага, а использовать сигнализацию close
вместо. Определите канал для каждого условия, которое вы хотите прекратить run()
, и в соответствующей функции обработчика веб-сокета, close
канал, когда это условие произойдет. Внизу run()
вы можете select
на всех каналах и выйти, когда первый из них закроется. Это будет выглядеть примерно так:
package main
import "errors"
func run(appName string) (err error) {
// first, define one channel per socket-closing-reason (DO NOT defer close these channels.)
connectErrorChan := make(chan struct{})
successDoneChan := make(chan struct{})
surpriseDisconnectChan := make(chan struct{})
// next, wrap calls to your handlers in a closure `https://gobyexample.com/closures`
// that captures a reference to the channel you care about
OnConnectErrorHandler := func(err error, socket gowebsocket.Socket) {
MyOnConnectErrorHandler(connectErrorChan, err, socket)
}
OnDisconnectedHandler := func(err error, socket gowebsocket.Socket) {
MyOnDisconectedHandler(surpriseDisconnectChan, err, socket)
}
// ... declare any other handlers that might close the connection here
// Do your setup logic here
// serviceURL, e := GetContext().getServiceURL(appName)
// . . .
// socket := gowebsocket.New(url)
socket.OnConnectError = OnConnectErrorHandler
socket.OnConnected = OnConnectedHandler
socket.OnTextMessage = socketTextMessageHandler
socket.OnDisconnected = OnDisconnectedHandler
// Prepare and send your message here...
// LogDebug("In %v func connecting to URL %v", methodName, url)
// . . .
// socket.SendText(jsonStr)
// now wait for one of your signalling channels to close.
select { // this will block until one of the handlers signals an exit
case <-connectError:
err = errors.New("never connected :( ")
case <-successDone:
socket.Close()
LogDebug("mission accomplished! :) ")
case <-surpriseDisconnect:
err = errors.New("somebody cut the wires! :O ")
}
if err != nil {
LogDebug(err)
}
return err
}
// *Your* connect error handler will take an extra channel as a parameter
func MyOnConnectErrorHandler(done chan struct{}, err error, socket gowebsocket.Socket) {
methodName := "OnConnectErrorHandler"
LogDebug("Starting %v parameters [err = %v , socket = %v]", methodName, err, socket)
LogInfo("Disconnected from server ")
close(done) // signal we are done.
}
Это имеет несколько преимуществ:
1) Вам не нужно угадывать, какие обратные вызовы происходят в процессе, а какие происходят в фоновых процедурах (и вам не нужно делать буферизацию всех ваших каналов «на всякий случай»)
2) Выбор нескольких каналов позволяет узнать , почему вы выходите и, возможно, по-разному справитесь с очисткой или регистрацией.
Примечание 1: Если вы решите использовать close
сигнализацию, у вас будет , чтобы использовать разные каналы для каждого источника, чтобы избежать условий гонки, которые могут привести к двойному закрытию канала из-за различных процедур ( например, тайм-аут происходит, как только вы получаете ответ, и оба обработчика срабатывают; второй обработчик, закрывающий один и тот же канал, вызывает panic
.) Это также, почему вы не хотите defer close
всех каналов в верхняя часть функции.
Примечание 2: Не имеет прямого отношения к вашему вопросу, но - вам не нужно закрывать каждый канал - как только все указатели на него выйдут из области видимости, канал будет собирать мусор или нет он был закрыт.