In my code I want to do the following:
- Recieve data from inputs as
event
andmessage
- Format the received data based on the
event
I thought to use something close to the method in the OOP, but it looks I meesed things up.
What I wrote is:
// Define the structs that contains the channels
type sseData struct {
event, message string
}
type DataPasser struct {
data chan sseData
logs chan string
connection chan struct{} // To control maximum allowed clients connections
}
// DEfine the struct's reciever that do the formating based on the input date
func (p *DataPasser) Format() {
data := <-p.data
switch {
case len(data.event) > 0:
p.logs <- fmt.Sprintf("event: %v\ndata: %v\n\n", data.event, data.message)
case len(data.event) == 0:
p.logs <- fmt.Sprintf("data: %v\n\n", data.message)
}
}
Then I’ve the below:
func (p *DataPasser) HandleSignal(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
setupCORS(&w, r)
fmt.Println("Client connected from IP:", r.RemoteAddr)
p.connection <- struct{}{}
flusher, ok := w.(http.Flusher)
if !ok {
http.Error(w, "Internal error", 500)
return
}
fmt.Fprint(w, "event: notification\ndata: Connection to WhatsApp server ...\n\n")
flusher.Flush()
// Connect to the WhatsApp client
go Connect()
// Prepare dataParser `p` to recieve data through its sseData channel
go p.Format()
for {
select {
case c := <-p.logs:
fmt.Fprint(w, c)
flusher.Flush()
case <-r.Context().Done():
<-p.connection
fmt.Println("Connection closed")
return
}
}
}
func setupCORS(w *http.ResponseWriter, req *http.Request) {
(*w).Header().Set("Cache-Control", "no-cache")
(*w).Header().Set("Access-Control-Allow-Origin", "*")
(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}
Anf in the connect function, I’ve the:
package main
import (
"context"
"fmt"
)
var err error
func Connect() {
fmt.Println("Connected")
if client.IsConnected() {
client.Disconnect()
passer.data <- sseData{
event: "notification",
message: "Reconnecting to WhatsApp server ...",
}
}
if client.Store.ID == nil {
// No ID stored, new login
GetQR:
qrChan, _ := client.GetQRChannel(context.Background())
err = client.Connect()
if err != nil {
// panic(err)
//passer.logs <- "Can not connect with WhatApp server, try again later"
passer.data <- sseData{
event: "notification",
message: "Can not connect with WhatApp server, try again later",
}
fmt.Println("Sorry", err)
}
for evt := range qrChan {
switch evt.Event {
case "success":
{
//passer.logs <- "success"
passer.data <- sseData{
event: "notification",
message: "success",
}
fmt.Println("Login event: success")
}
case "timeout":
{
//passer.logs <- "timeout/Refreshing"
passer.data <- sseData{
event: "notification",
message: "timeout/Refreshing",
}
fmt.Println("Login event: timeout")
goto GetQR
}
case "code":
{
fmt.Println("new code recieved")
fmt.Println(evt.Code)
//passer.logs <- evt.Code
passer.data <- sseData{
event: "qrCode",
message: evt.Code,
}
}
}
}
} else {
// Already logged in, just connect
//passer.logs <- "Already logged"
passer.data <- sseData{
event: "notification",
message: "Already logged in",
}
fmt.Println("Already logged")
err = client.Connect()
if err != nil {
panic(err)
}
}
/*
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c
passer.data <- sseData{
event: "notification",
message: "Server got shut down",
}
*/
}
In the main file, I do have:
var passer *DataPasser
const maxClients = 1
func init() {
passer = &DataPasser{
data: make(chan sseData),
logs: make(chan string),
connection: make(chan struct{}, maxClients),
}
}
func main() {
http.HandleFunc("/sse", passer.HandleSignal)
go http.ListenAndServe(":1234", nil)
// Listen to Ctrl+C (you can also do something else that prevents the program from exiting)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c
if client.IsConnected() {
client.Disconnect()
}
}
What is happeneing is that the server sending the first SSE correctly only, and it looks it hangs somewhere in the channel communication.
I solved it by writting:
// Connect to the WhatsApp client
go Connect()
for {
select {
case data := <-p.data:
fmt.Println("recieved")
switch {
case len(data.event) > 0:
fmt.Fprintf(w, "event: %v\ndata: %v\n\n", data.event, data.message)
case len(data.event) == 0:
fmt.Fprintf(w, "data: %v\n\n", data.message)
}
flusher.Flush()
case <-r.Context().Done():
<-p.connection
fmt.Println("Connection closed")
return
}
}
But I still interested in splitting the action and using the reciever, any thought?