Exemplo n.º 1
1
func writer(ws *websocket.Conn) {
	pingTicker := time.NewTicker(pingPeriod)
	nodesTicker := time.NewTicker(nodesPeriod)
	defer func() {
		pingTicker.Stop()
		nodesTicker.Stop()
		ws.Close()
	}()
	for {
		select {
		case <-nodesTicker.C:

			p := []byte(fmt.Sprintf("%v", nodesH))

			if p != nil {
				ws.SetWriteDeadline(time.Now().Add(writeWait))
				if err := ws.WriteMessage(websocket.TextMessage, p); err != nil {
					return
				}
			}
		case <-pingTicker.C:
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		}
	}
}
Exemplo n.º 2
0
func (ws *WebSocker) writer(conn *websocket.Conn, user string, tmpl *template.Template) {
	pingTicker := time.NewTicker(pingPeriod)
	chl, chq := notifier.listen(user)
	ws.log.Println(user, "connected")
	defer func() {
		pingTicker.Stop()
		conn.Close()
		close(chq)
		ws.log.Println(user, "disconnected")
	}()
	for {
		var buf bytes.Buffer
		select {
		case p := <-chl:
			conn.SetWriteDeadline(time.Now().Add(writeWait))
			buf.Reset()
			if err := tmpl.Execute(&buf, p); err != nil {
				ws.log.Println(err)
				return
			}
			if err := conn.WriteMessage(websocket.TextMessage, buf.Bytes()); err != nil {
				return
			}
			ws.log.Println("notified:", user)
		case <-pingTicker.C:
			conn.SetWriteDeadline(time.Now().Add(writeWait))
			if err := conn.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				ws.log.Println("ping:", err)
				return
			}
		}
	}
}
Exemplo n.º 3
0
// writer runs in a goroutine for each connected WS client. It emits all message returned by the observer.
func writer(ws *websocket.Conn, a *ApiHandlers) {
	pingTicker := time.NewTicker(pingPeriod)
	s := a.getDBSubscriber()
	jww.INFO.Println("Opened WebSocket connection.")
	defer func(is *subscriber) {
		jww.INFO.Println("Closing WebSocket connection.")
		is.quitChan <- true
		pingTicker.Stop()
		ws.Close()
	}(s)

	for {
		select {
		case msg := <-s.bufChan:
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.WriteJSON(msg); err != nil {
				return
			}
		case <-pingTicker.C:
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		}
	}
}
Exemplo n.º 4
0
func write(ws *websocket.Conn, mt int, payload []byte) error {
	if ws == nil {
		return errors.New("no web socket connection: ws")
	}
	ws.SetWriteDeadline(time.Now().Add(writeWait))
	return ws.WriteMessage(mt, payload)
}
Exemplo n.º 5
0
// Pick requests off the RemoteServer queue and send them into the tunnel
func wsWriter(rs *remoteServer, ws *websocket.Conn, ch chan int) {
	var req *remoteRequest
	var err error
	for {
		// fetch a request
		select {
		case req = <-rs.requestQueue:
			// awesome...
		case _ = <-ch:
			// time to close shop
			rs.log.Info("WS closing on signal", "ws", wsp(ws))
			ws.Close()
			return
		}
		//log.Printf("WS->%s#%d start %s", req.token, req.id, req.info)
		// See whether the request has already expired
		if req.deadline.Before(time.Now()) {
			req.replyChan <- responseBuffer{
				err: errors.New("Timeout before forwarding the request"),
			}
			req.log.Info("WS   SND timeout before sending", "ago",
				time.Now().Sub(req.deadline).Seconds())
			continue
		}
		// write the request into the tunnel
		ws.SetWriteDeadline(time.Now().Add(time.Minute))
		var w io.WriteCloser
		w, err = ws.NextWriter(websocket.BinaryMessage)
		// got an error, reply with a "hey, retry" to the request handler
		if err != nil {
			break
		}
		// write the request Id
		_, err = fmt.Fprintf(w, "%04x", req.id)
		if err != nil {
			break
		}
		// write the request itself
		_, err = req.buffer.WriteTo(w)
		if err != nil {
			break
		}
		// done
		err = w.Close()
		if err != nil {
			break
		}
		req.log.Info("WS   SND", "info", req.info)
	}
	// tell the sender to retry the request
	req.replyChan <- responseBuffer{err: RetryError}
	req.log.Info("WS error causes retry")
	// close up shop
	ws.WriteControl(websocket.CloseMessage, nil, time.Now().Add(5*time.Second))
	time.Sleep(2 * time.Second)
	ws.Close()
}
Exemplo n.º 6
0
func NewCcusConn(ws *websocket.Conn, cc_in chan updateInfo) *ccusConn {

	log.Printf("ws[%s]:new connect %s", ws.RemoteAddr(), ws.LocalAddr())
	ws.SetReadDeadline(time.Now().Add(pongWait))
	ws.SetWriteDeadline(time.Now().Add(writeWait))
	pc := &ccusConn{}
	pc.ws = ws
	pc.cc_in = cc_in
	go pc.receiver()

	return pc
}
Exemplo n.º 7
0
// wsConnHandler starts goroutines for forever reading from, and writing to, a
// websocket connection. Reads can be read from the ch_r channel, writes be
// sent to the ch_w channel.
//
// When a read from the websocket returns an error (which for example happens
// when the connection is closed), the read goroutine will terminate, but not
// right away. The faulty read is available on the read channel for a while
// before a timeout kicks in and the channel is closed. This is a little weird,
// but it ensures that faulty reads can be read by some listening goroutine,
// while it is at the same time guaranteed that the goroutine terminates even
// if there is no listener.
//
// When the caller closes the write channel (don't forget to do that!),
// wsConnHandler will close the websocket connection (with Close(), not with a
// control message) and terminate both goroutines. If you want to close the
// websocket with a control message, just do it by sending a control message
// directly over the conn object (this is legal).  After that, close the write
// channel.
func wsConnHandler(c *websocket.Conn) (<-chan *wsReadResult,
	chan<- *wsWriteCmd) {

	// channels we expose
	ch_r := make(chan *wsReadResult)
	ch_w := make(chan *wsWriteCmd)

	// reader
	go func() {
		for cont := true; cont; {
			// read from websocket forever
			res := new(wsReadResult)
			c.SetReadDeadline(time.Now().Add(
				time.Duration(appVars.config.WebsocketConnectionTimeoutS) * time.Second))
			res.messageType, res.data, res.err = c.ReadMessage() // err on socket close

			if res.err == nil {
				// got a message? send to read channel and read from websocket again
				ch_r <- res
			} else {
				log.Printf("ws conn handler reader got error (normal at close)")
				// got an error from the read? offer on read channel until timeout.
				// Eventually, break out of loop
				select {
				case ch_r <- res:
					cont = false
				case <-time.After(30 * time.Second):
					cont = false
				}
			}
		}
		close(ch_r)
		log.Printf("ws conn handler reader terminates")
		return
	}()

	// writer
	go func() {
		// recv from ch_w and send what is received over WriteMessage until channel
		// is closed
		for cmd := range ch_w {
			c.SetWriteDeadline(time.Now().Add(
				time.Duration(appVars.config.WebsocketConnectionTimeoutS) * time.Second))
			err := c.WriteMessage(cmd.messageType, cmd.data)
			cmd.ch_ret <- err
		}
		// when channel is closed, close the websocket
		log.Printf("ws conn handler writer closes websocket connection and terminates")
		c.Close() // reader goroutine will get an error from ReadMessage()
		return
	}()
	return ch_r, ch_w
}
Exemplo n.º 8
0
func pumpStdout(ws *websocket.Conn, r io.Reader, done chan struct{}) {
	defer ws.Close()
	s := bufio.NewScanner(r)
	for s.Scan() {
		ws.SetWriteDeadline(time.Now().Add(writeWait))
		if err := ws.WriteMessage(websocket.TextMessage, s.Bytes()); err != nil {
			break
		}
	}
	if s.Err() != nil {
		log.Println("scan:", s.Err())
	}
	close(done)
	log.Println("exit stdout pump")
}
Exemplo n.º 9
0
func (ws *Websocket) Writer(c *goWs.Conn, closed <-chan bool) {
	ws.watcher.Start()
	defer ws.watcher.Stop()
	defer c.Close()
	for {
		select {
		case data := <-ws.watcher.C.Raw:
			c.SetWriteDeadline(time.Now().Add(WriteTimeout))
			err := c.WriteMessage(goWs.TextMessage, MdConverter.Convert(*data))
			if err != nil {
				return
			}
		case <-closed:
			return
		}
	}
}
Exemplo n.º 10
0
// pumpStdout handles reading data from stdout of the process and writing
// it to websocket connection.
func pumpStdout(conn *websocket.Conn, stdout io.Reader, done chan struct{}) {
	go pinger(conn, done)
	defer func() {
		conn.Close()
		close(done) // make sure to close the pinger when we are done.
	}()

	s := bufio.NewScanner(stdout)
	for s.Scan() {
		conn.SetWriteDeadline(time.Now().Add(writeWait))
		if err := conn.WriteMessage(websocket.TextMessage, bytes.TrimSpace(s.Bytes())); err != nil {
			break
		}
	}
	if s.Err() != nil {
		conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseGoingAway, s.Err().Error()), time.Time{})
	}
}
Exemplo n.º 11
0
func writer(ws *websocket.Conn, lastMod time.Time, which string) {
	pingTicker := time.NewTicker(pingPeriod)
	updateTicker := time.NewTicker(updatePeriod)
	defer func() {
		pingTicker.Stop()
		updateTicker.Stop()
		ws.Close()
	}()
	for {
		select {
		case <-updateTicker.C:
			var r []Result
			var t []interface{}
			var err error

			if which == "score" {
				r, lastMod, err = getTeamScoreIfModified(lastMod)
			} else if which == "service" {
				t, lastMod, err = getServiceIfModified(lastMod)
			}
			if err != nil {
				Logger.Printf("Could not get websocket team score: %v\n", err)
			}

			if r != nil || t != nil {
				ws.SetWriteDeadline(time.Now().Add(writeWait))
				if which == "service" {
					if err := ws.WriteJSON(t); err != nil {
						return
					}
				} else {
					if err := ws.WriteJSON(r); err != nil {
						return
					}
				}
			}
		case <-pingTicker.C:
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		}
	}
}
Exemplo n.º 12
0
func writer(ws *websocket.Conn, lastMod time.Time, filename string) {
	lastError := ""
	pingTicker := time.NewTicker(pingPeriod)
	fileTicker := time.NewTicker(filePeriod)
	defer func() {
		pingTicker.Stop()
		fileTicker.Stop()
		ws.Close()
	}()
	var offset int64
	for {
		select {
		case <-fileTicker.C:
			var p []byte
			var err error

			p, lastMod, offset, err = readFileIfModified(filename, offset, lastMod)

			if err != nil {
				if s := err.Error(); s != lastError {
					lastError = s
					p = []byte(lastError)
				}
			} else {
				lastError = ""
			}

			if p != nil {
				ws.SetWriteDeadline(time.Now().Add(writeWait))
				if err := ws.WriteMessage(websocket.TextMessage, p); err != nil {
					return
				}
			}
		case <-pingTicker.C:
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		}
	}
}
Exemplo n.º 13
0
func pumpStdout(ws *websocket.Conn, r io.Reader, done chan struct{}) {
	defer func() {
	}()
	s := bufio.NewScanner(r)
	for s.Scan() {
		ws.SetWriteDeadline(time.Now().Add(writeWait))
		if err := ws.WriteMessage(websocket.TextMessage, s.Bytes()); err != nil {
			ws.Close()
			break
		}
	}
	if s.Err() != nil {
		log.Println("scan:", s.Err())
	}
	close(done)

	ws.SetWriteDeadline(time.Now().Add(writeWait))
	ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
	time.Sleep(closeGracePeriod)
	ws.Close()
}
Exemplo n.º 14
0
func writer(ws *websocket.Conn, uiMsgChan chan types.UIUpdateMsg) {
	pingTicker := time.NewTicker(pingPeriod)
	defer func() {
		pingTicker.Stop()
		ws.Close()
	}()
	for {
		select {
		case msg := <-uiMsgChan:
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.WriteJSON(msg); err != nil {
				return
			}
		case <-pingTicker.C:
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		}
	}
}
Exemplo n.º 15
0
func (this *subServer) wsWritePump(clientGone chan struct{}, ws *websocket.Conn, fetcher store.Fetcher) {
	defer fetcher.Close()

	var err error
	for {
		select {
		case msg := <-fetcher.Messages():
			ws.SetWriteDeadline(time.Now().Add(time.Second * 10))
			// FIXME because of buffer, client recv 10, but kateway written 100, then
			// client quit...
			if err = ws.WriteMessage(websocket.BinaryMessage, msg.Value); err != nil {
				log.Error("%s: %v", ws.RemoteAddr(), err)
				return
			}

			if err = fetcher.CommitUpto(msg); err != nil {
				log.Error(err) // TODO add more ctx
			}

		case err = <-fetcher.Errors():
			// TODO
			log.Error(err)

		case <-this.timer.After(this.wsPongWait / 3):
			ws.SetWriteDeadline(time.Now().Add(time.Second * 10))
			if err = ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				log.Error("%s: %v", ws.RemoteAddr(), err)
				return
			}

		case <-this.gw.shutdownCh:
			return

		case <-clientGone:
			return
		}

	}

}
Exemplo n.º 16
0
func wsWriter(ws *websocket.Conn, mc chan string) {
	pingTicker := time.NewTicker(pingPeriod)
	defer func() {
		pingTicker.Stop()
		ws.Close()
	}()
	for {
		select {
		case msg := <-mc:
			log.Println("Writing: " + msg)
			if err := ws.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil {
				return
			}
		case <-pingTicker.C:
			log.Println("Sending ping")
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		}
	}
}
Exemplo n.º 17
0
func writer(ws *websocket.Conn, fn string) {
	pingTicker := time.NewTicker(pingPeriod)
	fileTicker := time.NewTicker(filePeriod)
	defer func() {
		pingTicker.Stop()
		fileTicker.Stop()
		ws.Close()
	}()
	var r *bufio.Reader
	if !stdIn {
		f, _ := os.Open(fn)
		r = bufio.NewReader(f)
		defer f.Close()
	} else {
		r = bufio.NewReader(os.Stdin)
	}

	for {
		select {
		case <-fileTicker.C:
			p, err := r.ReadBytes('\n')

			if err != io.EOF {
				ws.SetWriteDeadline(time.Now().Add(writeWait))
				if err := ws.WriteMessage(websocket.TextMessage, p); err != nil {
					return
				}
			}
		case <-pingTicker.C:
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		}
	}
}
Exemplo n.º 18
0
// Reads incoming data from the websocket and forwards it to stdout.
func readWS(ws *websocket.Conn, query *regexp.Regexp, done chan struct{}) {
	defer func() {
		done <- struct{}{}
	}()
	ws.SetPingHandler(func(string) error {
		ws.SetWriteDeadline(time.Now().Add(writeTimeout))
		return ws.WriteMessage(websocket.PongMessage, []byte{})
	})
	for {
		_, msg, err := ws.ReadMessage()
		if err != nil {
			return
		}
		var log LogMessage
		err = json.Unmarshal(msg, &log)
		if err == nil {
			if query == nil || query.MatchString(log.Message) {
				logrus.Printf("%s - %s", log.Timestamp, log.Message)
			}
		} else {
			logrus.StandardLogger().Out.Write(msg)
		}
	}
}
Exemplo n.º 19
0
Arquivo: user.go Projeto: zvin/vandal
func write(ws *websocket.Conn, opCode int, payload []byte) error {
	ws.SetWriteDeadline(time.Now().Add(WRITE_WAIT))
	return ws.WriteMessage(opCode, payload)
}
Exemplo n.º 20
0
// Writes a message with the given message type (mt) and payload.
func ws_write(ws *websocket.Conn, mt int, payload []byte) error {
	ws.SetWriteDeadline(time.Now().Add(writeWait))
	return ws.WriteMessage(mt, payload)
}
Exemplo n.º 21
0
// timeout error on all network activity
func setDeadline(ws *websocket.Conn, d time.Duration) {
	ws.SetReadDeadline(time.Now().Add(d))
	ws.SetWriteDeadline(time.Now().Add(d))
}
Exemplo n.º 22
0
// Stream will init a new pubsub.KafkaPublisher and pubsub.KafkaSubscriber
// then upgrade the current request to a websocket connection. Any messages
// consumed from Kafka will be published to the web socket and vice versa.
func (s *StreamService) Stream(w http.ResponseWriter, r *http.Request) {
	cfg := *s.cfg
	cfg.Topic = topicName(web.GetInt64Var(r, "stream_id"))
	server.LogWithFields(r).WithField("topic", cfg.Topic).Info("new stream req")

	sub, err := pubsub.NewKafkaSubscriber(&cfg, zeroOffset, discardOffset)
	if err != nil {
		server.LogWithFields(r).WithField("error", err).Error("unable to create sub")
		http.Error(w, "unable to create subscriber: "+err.Error(), http.StatusBadRequest)
		return
	}
	defer func() {
		if err := sub.Stop(); err != nil {
			server.LogWithFields(r).WithField("error", err).Error("unable to stop sub")
		}
	}()

	var pub *pubsub.KafkaPublisher
	pub, err = pubsub.NewKafkaPublisher(&cfg)
	if err != nil {
		server.LogWithFields(r).WithField("error", err).Error("unable to create pub")
		http.Error(w, "unable to create publisher: "+err.Error(), http.StatusBadRequest)
		return
	}
	defer func() {
		if err := pub.Stop(); err != nil {
			server.LogWithFields(r).WithField("error", err).Error("unable to stop pub")
		}
	}()
	var ws *websocket.Conn
	ws, err = upgrader.Upgrade(w, r, nil)
	if err != nil {
		server.LogWithFields(r).WithField("error", err).Error("unable to create websocket")
		http.Error(w, "unable to create websocket: "+err.Error(), http.StatusBadRequest)
		return
	}
	defer func() {
		if err := ws.Close(); err != nil {
			server.LogWithFields(r).WithField("error", err).Error("unable to close ws")
		}
	}()

	// start consumer, emit to ws
	noopTicker := time.NewTicker(time.Second * 5)
	subscriberDone := make(chan bool, 1)
	stopSubscriber := make(chan bool, 1)
	go func() {
		defer func() { subscriberDone <- true }()
		var (
			payload []byte
			msgs    = sub.Start()
		)
		for {
			select {
			case msg := <-msgs:
				payload = msg.Message()
				err = ws.SetWriteDeadline(time.Now().Add(time.Second * 30))
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to write deadline")
				}
				err = ws.WriteMessage(websocket.TextMessage, payload)
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to write ws message")
				}
				err = msg.Done()
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to mark gizmo message as done")
				}
			case <-noopTicker.C:
				err = ws.SetWriteDeadline(time.Now().Add(time.Second * 30))
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to write deadline")
				}
				if err := ws.WriteMessage(websocket.PingMessage, []byte("ping")); err != nil {
					server.LogWithFields(r).WithField("error", err).Error("error writing ws message")
					return
				}
			case <-stopSubscriber:
				return
			}
		}
	}()

	// start producer, emit to kafka
	producerDone := make(chan bool, 1)
	go func() {
		defer func() {
			producerDone <- true
			stopSubscriber <- true
			server.LogWithFields(r).WithField("topic", cfg.Topic).Info("closing stream req")
		}()
		var (
			messageType int
			payload     []byte
			err         error
			read        io.Reader
		)
		for {
			messageType, read, err = ws.NextReader()
			if err != nil {
				if err != io.EOF {
					server.LogWithFields(r).WithField("error", err).Error("error reading message")
				}
				return
			}

			switch messageType {
			case websocket.TextMessage:
				payload, err = ioutil.ReadAll(read)
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to read payload")
					return
				}
				err = pub.PublishRaw(cfg.Topic, payload)
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to publish payload")
					return
				}
			case websocket.PingMessage, websocket.PongMessage, websocket.BinaryMessage:
				server.LogWithFields(r).Info("discarding message type: ", messageType)
			case websocket.CloseMessage:
				server.LogWithFields(r).Info("closing websocket")
				return
			}
		}
	}()

	<-subscriberDone
	<-producerDone
	noopTicker.Stop()
	server.LogWithFields(r).WithField("topic", cfg.Topic).Info("leaving stream req")
}
Exemplo n.º 23
0
func writer(ws *websocket.Conn) {
	pingTicker := time.NewTicker(pingPeriod)
	fileTicker := time.NewTicker(dataPushPeriod)
	defer func() {
		pingTicker.Stop()
		fileTicker.Stop()
		ws.Close()
	}()

	timeout := time.Duration(1 * time.Second)
	httpClient := http.Client{
		Timeout: timeout,
	}

	for {
		select {
		case <-fileTicker.C:
			var clusterState ClusterState

			app, err := client.Application("cattlestore")
			if err != nil {
				log.Printf("Not scaling: %s", err)
			}
			clusterState.NrOfInstances = app.Instances

			ops_t, max_t := 0.0, 0.0

			if app != nil && err == nil {
				for _, task := range app.Tasks {
					resp, err := httpClient.Get(fmt.Sprintf("http://172.17.0.1:%d/info", task.Ports[0]))
					if err != nil {
						continue
					}

					state, err := ioutil.ReadAll(resp.Body)
					if err != nil {
						continue
					}

					f := State{}
					json.Unmarshal(state, &f)
					clusterState.Instances = append(clusterState.Instances, Instance{
						Id:  task.ID[12:20],
						Ops: f.Ops,
						Max: f.Max,
					})
					ops_t += float64(f.Ops)
					max_t += float64(f.Max)
				}
			}

			go scaleUp(ops_t, max_t)

			p, err := json.Marshal(clusterState)
			if err != nil {
				continue
			}
			//			p := []byte(`[{"id":"6cd8a58f","max":24,"ops":24},{"id":"6cd8a58e","max":24,"ops":18},
			//			{"id":"1cd8a58f","max":24,"ops":24},{"id":"4cd8a58e","max":24,"ops":18},
			//			{"id":"2cd8a58f","max":24,"ops":24},{"id":"5cd8a58e","max":24,"ops":18},
			//			{"id":"3cd8a58f","max":24,"ops":24},{"id":"7cd8a58e","max":24,"ops":18}, {"id":"6cdf3444","max":30,"ops":12},{"id":"6cbdca8b","max":13,"ops":3},{"id":"6ce8f854","max":13,"ops":12}]`)

			if p != nil {
				ws.SetWriteDeadline(time.Now().Add(writeWait))
				if err := ws.WriteMessage(websocket.TextMessage, p); err != nil {
					return
				}
			}
		case <-pingTicker.C:
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		}
	}
}
func ping(ws *websocket.Conn) error {
	ws.SetWriteDeadline(time.Now().Add(writeWait))
	return ws.WriteMessage(websocket.PingMessage, []byte{})
}