I'm making a progress bar for my program, and send it to client. The IPC I used is websocket. But I'm facing write: broken pipe
when updating progress bar to the client. This error occurs after the first request. For example, on initial run of my app, when i perfrom request to the server, there is no error. But, when I perform another request, this error will occur.
Even though there is this error, but the progress bar is actually working despite the error (the progress bar is successfully sent to the client until 100%)
I'm using go fiber websocket as my server
// middleware
app.Use("/ws", func(c *fiber.Ctx) error {
if websocket.IsWebSocketUpgrade(c) {
c.Locals("allowed", true)
return c.Next()
}
return fiber.ErrUpgradeRequired
})
// handler
func (s *downloaderService) progressBar(c *websocket.Conn) {
channel := api.CreateChannel(c.Params("client"))
done := make(chan bool)
go func() {
for {
t, _, err := c.ReadMessage()
if err != nil {
log.Println("Error reading message:", err)
return
}
if t == websocket.CloseMessage {
done <- true
}
}
}()
for {
select {
case <-done:
return
case data, ok := <-channel.Subscribe():
if !ok {
return
}
progressBar := data.(downloader.Progressbar)
payload, err := json.Marshal(progressBar)
if err != nil {
log.Println("Error marshalling data:", err)
break
}
c.SetWriteDeadline(time.Now().Add(10 * time.Second))
if err := c.WriteMessage(websocket.TextMessage, payload); err != nil {
log.Println("Error sending progress data:", err)
done <- true
}
}
}
}
On the client, I'm using gorilla websocket
func main() {
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, []os.Signal{syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGSTOP, os.Interrupt}...)
ctx, cancel := context.WithCancel(context.Background())
conn, res, err := websocket.DefaultDialer.DialContext(ctx, ws, nil)
if err != nil {
log.Fatalf("Error dialing websocket: %v. Status courlde %d", err, res.StatusCode)
return
}
executeCommand(ctx)
progressBar := progressbar()
go func() {
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("Error reading message:", err)
break
}
var progress progress
if err := json.Unmarshal(message, &progress); err != nil {
log.Println("Error unmarshalling message:", err)
break
}
if progress.Done {
truncateStore()
cancel()
break
}
progressBar.update(progress.Index, progress.Downloaded, progress.Size)
}
}()
for {
select {
case <-ctx.Done():
closeConn(ctx, conn)
return
case <-interrupt:
stopDownload()
closeConn(ctx, conn)
return
}
}
}
func closeConn(ctx context.Context, conn *websocket.Conn) {
if err := conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")); err != nil {
log.Println("Error sending close signal to server:", err)
return
}
select {
case <-ctx.Done():
case <-time.After(time.Second):
}
}
The client is a CLI that will create request to the server. And when the progress bar is complete, it will be terminated.
Update
After reading the close message from client, I manage to get rid the broken pipe error. Instead, i got write: close sent