How can I send signal from the server to the client upon receiving os.Interrupt

huangapple go评论81阅读模式
英文:

How can I send signal from the server to the client upon receiving os.Interrupt

问题

在我的代码中,我在关闭之前监听 os.Interrupt 的信号。

package main

import (
	"net/http"
	"os"
	"os/signal"
	"syscall"
)

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)

	// 监听 Ctrl+C 信号(你也可以做其他阻止程序退出的操作)
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)

	<-c
	if client.IsConnected() {
		client.Disconnect()
	}
}

passer.HandleSignal 是一个函数,用于向客户端发送 SSE(Server Sent Event):

package main

import (
	"fmt"
	"net/http"
)

type sseData struct {
	event, message string
}
type DataPasser struct {
	data       chan sseData
	connection chan struct{} // 控制最大允许的客户端连接数
}

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")

	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()

	// 连接到 WhatsApp 客户端
	go Connect()

	for {
		select {
		case data := <-p.data:
			fmt.Println("received")

			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
		}
	}
}

func Connect() {
   // 进行数据操作,并将结果发送给 `parser`
   passer.data <- sseData{
			event:   "notification",
			message: "Reconnecting to WhatsApp server ...",
   }
}

我的问题是,如果用户使用 Ctrl+C 中断应用程序,main 函数会对其做出响应,我希望它将数据发送给 parser,以便处理程序向客户端发送服务器已关闭的通知。

英文:

In my code, I've the below that is listening to os.Interrupt before closing

package main

import (
	&quot;net/http&quot;
	&quot;os&quot;
	&quot;os/signal&quot;
	&quot;syscall&quot;
)

var passer *DataPasser

const maxClients = 1

func init() {
	passer = &amp;DataPasser{
		data:       make(chan sseData),
		logs:       make(chan string),
		connection: make(chan struct{}, maxClients),
	}
}

func main() {

	http.HandleFunc(&quot;/sse&quot;, passer.HandleSignal)
	go http.ListenAndServe(&quot;:1234&quot;, 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)

	&lt;-c
	if client.IsConnected() {
		client.Disconnect()
	}
}

The passer.HandleSignal is a function that is sending SSE Server Sent Event to the client, as:

package main

import (
	&quot;fmt&quot;
	&quot;net/http&quot;
)

type sseData struct {
	event, message string
}
type DataPasser struct {
	data       chan sseData
	connection chan struct{} // To control maximum allowed clients connections
}

func (p *DataPasser) HandleSignal(w http.ResponseWriter, r *http.Request) {
	w.Header().Set(&quot;Content-Type&quot;, &quot;text/event-stream; charset=utf-8&quot;)
	w.Header().Set(&quot;Cache-Control&quot;, &quot;no-cache&quot;)
	w.Header().Set(&quot;Connection&quot;, &quot;keep-alive&quot;)

	fmt.Println(&quot;Client connected from IP:&quot;, r.RemoteAddr)

	p.connection &lt;- struct{}{}
	flusher, ok := w.(http.Flusher)
	if !ok {
		http.Error(w, &quot;Internal error&quot;, 500)
		return
	}

	fmt.Fprint(w, &quot;event: notification\ndata: Connection to WhatsApp server ...\n\n&quot;)
	flusher.Flush()

	// Connect to the WhatsApp client
	go Connect()

	for {
		select {
		case data := &lt;-p.data:
			fmt.Println(&quot;recieved&quot;)

			switch {
			case len(data.event) &gt; 0:
				fmt.Fprintf(w, &quot;event: %v\ndata: %v\n\n&quot;, data.event, data.message)
			case len(data.event) == 0:
				fmt.Fprintf(w, &quot;data: %v\n\n&quot;, data.message)
			}
			flusher.Flush()
		case &lt;-r.Context().Done():
			&lt;-p.connection
			fmt.Println(&quot;Connection closed&quot;)
			return
		}
	}
}

func Connect() {
   // Doing data manipulation, and sending reselt to the `parser`
   passer.data &lt;- sseData{
			event:   &quot;notification&quot;,
			message: &quot;Reconnecting to WhatsApp server ...&quot;,
   }
}

My question is that, if the user interupted the application using Ctrl+C, the main function is responding to it, I need it to send data to the parser so that the handler send notification to the client that the server had been shut down

答案1

得分: -1

我找到了解决方案,它很简单,只需将日期传递给在os.interupt范围内定义为全局变量的parser,如下所示:

	<-c
	if client.IsConnected() {
		passer.data <- sseData{
			event:   "notification",
			message: "服务器在主机上关闭...",
		}
		client.Disconnect()
	}
英文:

I found the solution, it was trivial, just pass date to the parser which is defined as global variable within the os.interupt scope, as:

	&lt;-c
	if client.IsConnected() {
		passer.data &lt;- sseData{
			event:   &quot;notification&quot;,
			message: &quot;Server is shut down at the host machine...&quot;,
		}
		client.Disconnect()
	}

huangapple
  • 本文由 发表于 2022年7月13日 15:15:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/72962285.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定