// RootWebsocket is the websocket handler for all pages
343232
func (exp *explorerUI) RootWebsocket(w http.ResponseWriter, r *http.Request) {
	wsHandler := websocket.Handler(func(ws *websocket.Conn) {
		// Create channel to signal updated data availability
		updateSig := make(hubSpoke, 3)
		// Create a channel for exchange updates
		xcChan := make(exchangeChannel, 3)
		// register websocket client with our signal channel
		clientData := exp.wsHub.RegisterClient(&updateSig, xcChan)
		// unregister (and close signal channel) before return
		defer exp.wsHub.UnregisterClient(&updateSig)

		// close the websocket
		closeWS := func() {
			err := ws.Close()
			// Do not log error if connection is just closed.
			if err != nil && !pstypes.IsWSClosedErr(err) &&
				!pstypes.IsIOTimeoutErr(err) {
				log.Errorf("Failed to close websocket: %v", err)
			}
		}
		defer closeWS()

		send := func(webData WebSocketMessage) error {
			err := ws.SetWriteDeadline(time.Now().Add(wsWriteTimeout))
			if err != nil && !pstypes.IsWSClosedErr(err) {
				log.Warnf("SetWriteDeadline failed: %v", err)
			}
			if err := websocket.JSON.Send(ws, webData); err != nil {
				// Do not log error if connection is just closed
				if !pstypes.IsWSClosedErr(err) {
					log.Debugf("Failed to send web socket message %s: %v", webData.EventId, err)
				}
				// If the send failed, the client is probably gone, so close
				// the connection and quit.
				return fmt.Errorf("Send fail")
			}
			return nil
		}

		requestLimit := 1 << 20
		// set the max payload size to 1 MB
		ws.MaxPayloadBytes = requestLimit

		// Start listening for websocket messages from client with raw
		// transaction bytes (hex encoded) to decode or broadcast.
		go func() {
			defer closeWS()
			for {
				// Wait to receive a message on the websocket
				msg := &WebSocketMessage{}
				err := ws.SetReadDeadline(time.Now().Add(wsReadTimeout))
				if err != nil && !pstypes.IsWSClosedErr(err) {
					log.Warnf("SetReadDeadline failed: %v", err)
				}
				if err = websocket.JSON.Receive(ws, &msg); err != nil {
					if err.Error() != "EOF" {
						log.Warnf("websocket client receive error: %v", err)
					}
					return
				}

				// handle received message according to event ID
				var webData WebSocketMessage
				//  If the request sent is past the limit continue to the next iteration.
				if len(msg.Message) > requestLimit {
					log.Debug("Request size over limit")
					webData.Message = "Request too large"
					continue
				}

				switch msg.EventId {
				case "decodetx":
					log.Debugf("Received decodetx signal for hex: %.40s...", msg.Message)
					tx, err := exp.blockData.DecodeRawTransaction(msg.Message)
					if err == nil {
						message, err := json.MarshalIndent(tx, "", "    ")
						if err != nil {
							log.Warn("Invalid JSON message: ", err)
							webData.Message = "Error: Could not encode JSON message"
							break
						}
						webData.Message = string(message)
					} else {
						log.Debugf("Could not decode raw tx")
						webData.Message = fmt.Sprintf("Error: %v", err)
					}

				case "sendtx":
					log.Debugf("Received sendtx signal for hex: %.40s...", msg.Message)
					txid, err := exp.blockData.SendRawTransaction(msg.Message)
					if err != nil {
						webData.Message = fmt.Sprintf("Error: %v", err)
					} else {
						webData.Message = fmt.Sprintf("Transaction sent: %s", txid)
					}

				case "getmempooltxs":
					// MempoolInfo. Used on mempool and home page.
					inv := exp.MempoolInventory()

					// Check if client supplied a mempool ID. If so, check that an update
					// is needed before sending.
					if msg.Message != "" {
						clientID, err := strconv.ParseUint(msg.Message, 10, 64)
						if err != nil {
							// For now, just log a warning and return the mempool anyway.
							log.Warn("Unable to parse supplied mempool ID %s", msg.Message)
						} else if inv.ID() == clientID {
							// Client is up-to-date. No need to send anything.
							continue
						}
					}

					inv.RLock()
					msg, err := json.Marshal(inv)
					inv.RUnlock()

					if err != nil {
						log.Warn("Invalid JSON message: ", err)
						webData.Message = "Error: Could not encode JSON message"
						break
					}
					webData.Message = string(msg)

				case "getmempooltrimmed":
					// TrimmedMempoolInfo. Used in nexthome.
					// construct mempool object with properties required in template
					inv := exp.MempoolInventory()
					mempoolInfo := inv.Trim() // Trim internally locks the MempoolInfo.

					exp.pageData.RLock()
					mempoolInfo.Subsidy = exp.pageData.HomeInfo.NBlockSubsidy
					exp.pageData.RUnlock()

					msg, err := json.Marshal(mempoolInfo)

					if err != nil {
						log.Warn("Invalid JSON message: ", err)
						webData.Message = "Error: Could not encode JSON message"
						break
					}
					webData.Message = string(msg)

				case "getticketpooldata":
					// Retrieve chart data on the given interval.
					interval := dbtypes.TimeGroupingFromStr(msg.Message)
					// Chart height is returned since the cache may be stale,
					// although it is automatically updated by the first caller
					// who requests data from a stale cache.
					timeChart, priceChart, donutChart, chartHeight, err :=
						exp.explorerSource.TicketPoolVisualization(interval)
					if dbtypes.IsTimeoutErr(err) {
						log.Warnf("TicketPoolVisualization DB timeout: %v", err)
						webData.Message = "Error: DB timeout"
						break
					}
					if err != nil {
						if strings.HasPrefix(err.Error(), "unknown interval") {
							log.Debugf("invalid ticket pool interval provided "+
								"via TicketPoolVisualization: %s", msg.Message)
							webData.Message = "Error: " + err.Error()
							break
						}
						log.Errorf("TicketPoolVisualization error: %v", err)
						webData.Message = "Error: failed to fetch ticketpool data"
						break
					}

					mp := new(apitypes.PriceCountTime)

					inv := exp.MempoolInventory()
					inv.RLock()
					if len(inv.Tickets) > 0 {
						mp.Price = inv.Tickets[0].TotalOut
						mp.Count = len(inv.Tickets)
						mp.Time = dbtypes.NewTimeDefFromUNIX(inv.Tickets[0].Time)
					} else {
						log.Debug("No tickets exists in the mempool")
					}
					inv.RUnlock()

					data := &apitypes.TicketPoolChartsData{
						ChartHeight: uint64(chartHeight),
						TimeChart:   timeChart,
						PriceChart:  priceChart,
						DonutChart:  donutChart,
						Mempool:     mp,
					}

					msg, err := json.Marshal(data)
					if err != nil {
						log.Warn("Invalid JSON message: ", err)
						webData.Message = "Error: Could not encode JSON message"
						break
					}
					webData.Message = string(msg)

				case "ping":
					log.Tracef("We've been pinged: %.40s...", msg.Message)
					continue
				default:
					log.Warnf("Unrecognized event ID: %v", msg.EventId)
					continue
				}

				webData.EventId = msg.EventId + "Resp"

				err = send(webData)
				if err != nil {
					return
				}
			}
		}()

		// Send loop (ping, new tx, block, etc. update loop)
	loop:
		for {
			// Wait for signal from the hub to update
			select {
			case sig, ok := <-updateSig:
				// Check if the update channel was closed. Either the websocket
				// hub will do it after unregistering the client, or forcibly in
				// response to (http.CloseNotifier).CloseNotify() and only then
				// if the hub has somehow lost track of the client.
				if !ok {
					break loop
				}

				if !sig.IsValid() {
					log.Errorf("invalid signal to send: %s / %d", sig.Signal.String(), int(sig.Signal))
					continue
				}

				log.Tracef("signaling client: %p", &updateSig)

				// Write block data to websocket client

				webData := WebSocketMessage{
					// Use HubSignal's string, not HubMessage's string, which is decorated.
					EventId: sig.Signal.String(),
					Message: "error",
				}
				buff := new(bytes.Buffer)
				enc := json.NewEncoder(buff)
				switch sig.Signal {
				case sigNewBlock:
					exp.pageData.RLock()
					err := enc.Encode(types.WebsocketBlock{
						Block: exp.pageData.BlockInfo,
						Extra: exp.pageData.HomeInfo,
					})
					exp.pageData.RUnlock()
					if err == nil {
						webData.Message = buff.String()
					} else {
						log.Errorf("json.Encode(WebsocketBlock) failed: %v", err)
					}

				case sigMempoolUpdate:
					inv := exp.MempoolInventory()
					inv.RLock()
					err := enc.Encode(inv.MempoolShort)
					inv.RUnlock()
					if err == nil {
						webData.Message = buff.String()
					} else {
						log.Errorf("json.Encode(MempoolShort) failed: %v", err)
					}

				case sigPingAndUserCount:
					// ping and send user count
					webData.Message = strconv.Itoa(exp.wsHub.NumClients())
				case sigNewTxs:
					// Do not use any tx slice in sig.Msg. Instead use client's
					// new transactions slice, newTxs.
					clientData.RLock()
					err := enc.Encode(clientData.newTxs)
					clientData.RUnlock()
					if err == nil {
						webData.Message = buff.String()
					} else {
						log.Errorf("json.Encode([]*MempoolTx) failed: %v", err)
					}

				case sigSyncStatus:
					err := enc.Encode(SyncStatus())
					if err == nil {
						webData.Message = buff.String()
					} else {
						log.Errorf("json.Encode([]SyncStatusInfo) failed: %v", err)
					}

				default:
					log.Errorf("RootWebsocket: Unhandled signal: %v", sig)
				}

				err := send(webData)
				if err != nil {
					return
				}

			case update := <-xcChan:
				buff := new(bytes.Buffer)
				enc := json.NewEncoder(buff)
				webData := WebSocketMessage{
					EventId: exchangeUpdateID,
					Message: "error",
				}
				err := enc.Encode(update)
				if err == nil {
					webData.Message = buff.String()
				} else {
					log.Errorf("json.Encode(*WebsocketExchangeUpdate) failed: %v", err)
				}
				err = send(webData)
				if err != nil {
					return
				}

			case <-exp.wsHub.quitWSHandler:
				break loop
			} // select
		} // for a.k.a. loop:
	}) // wsHandler := websocket.Handler(func(ws *websocket.Conn) {

	wsHandler.ServeHTTP(w, r)
}
1056561
func NewSocket(i *websocket.Conn, c *Context, f *Fibre) *Socket {
	return &Socket{i, c, f, nil}
}
558704
func NewTSSLSocketFromAddrTimeout(addr net.Addr, cfg *tls.Config, timeout time.Duration) *TSSLSocket {
	return &TSSLSocket{addr: addr, timeout: timeout, cfg: cfg}
}
1245294
func (app *App) WebSocket(ws *websocket.Conn) {
	app.WS = ws
	PutWS(ws)
}
1093946
func (s *WebsocketServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	logger.Println("WebsocketServer.ServeHTTP", r.Method, r.RequestURI)
	// TODO: subprotocol?
	conn, err := s.Upgrader.Upgrade(w, r, nil)
	if err != nil {
		logger.Println("Error upgrading to websocket connection:", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	s.handleWebsocket(conn)
}
255243
func (_m *Client) Root() string {
	ret := _m.Called()

	var r0 string
	if rf, ok := ret.Get(0).(func() string); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(string)
	}

	return r0
}
394079
func (self *SocketHandler) makeSocket(network string) error {
	address := fmt.Sprintf("%s:%d", self.host, self.port)
	conn, err := net.DialTimeout(network, address, SocketDefaultTimeout)
	if err != nil {
		return err
	}
	self.conn = conn
	return nil
}
1141457
func (service *WebSocketService) ServeHTTP(
	response http.ResponseWriter, request *http.Request) {
	if request.Method == "GET" && !strings.Contains(strings.ToLower(request.Header.Get("connection")), "upgrade") || request.Method == "POST" || request.Method == "OPTIONS" {
		service.HTTPService.ServeHTTP(response, request)
		return
	}
	conn, err := service.Upgrade(response, request, nil)
	if err != nil {
		context := new(rpc.HTTPContext)
		context.InitHTTPContext(service, response, request)
		resp := service.EndError(err, context)
		response.Header().Set("Content-Length", util.Itoa(len(resp)))
		response.Write(resp)
		return
	}
	defer conn.Close()

	mutex := new(sync.Mutex)
	for {
		msgType, data, err := conn.ReadMessage()
		if err != nil {
			break
		}
		if msgType == websocket.BinaryMessage {
			go service.handle(data, mutex, response, request, conn)
		}
	}
}
447189
func Websocket(route string, httpHandler websocket.Handler) {
	mainServer.Websocket(route, httpHandler)
}
1365429
func newSocketConnection(cfg *socketConfig) (websocketFeed, error) {
	dialer := &websocket.Dialer{
		Proxy:            http.ProxyFromEnvironment, // Same as DefaultDialer.
		HandshakeTimeout: 10 * time.Second,          // DefaultDialer is 45 seconds.
	}

	conn, _, err := dialer.Dial(cfg.address, nil)
	if err != nil {
		return nil, err
	}
	return &socketClient{
		conn: conn,
		done: make(chan struct{}),
	}, nil
}
931753
func IsWebSocketUpgrade(r *http.Request) bool {
	return tokenListContainsValue(r.Header, "Connection", "upgrade") &&
		tokenListContainsValue(r.Header, "Upgrade", "websocket")
}
193554
func NewWebsocketPeer(serialization Serialization, url, origin string) (Peer, error) {
	switch serialization {
	case JSON:
		return newWebsocketPeer(url, jsonWebsocketProtocol, origin,
			new(JSONSerializer), websocket.TextMessage,
		)
	case MSGPACK:
		return newWebsocketPeer(url, msgpackWebsocketProtocol, origin,
			new(MessagePackSerializer), websocket.BinaryMessage,
		)
	default:
		return nil, fmt.Errorf("Unsupported serialization: %v", serialization)
	}
}
954850
func NewPushSocket() (*PushSocket, error) {
	s, err := NewSocket(AF_SP, PUSH)
	return &PushSocket{s}, err
}
1323199
func newSocket(server *Server, bs backend.BackendSocket) *Socket {
	// Create a new socket value.
	s := &Socket{
		server: server,
		bs:     bs,

		id:       utils.RandomString(socketIDLength),
		channels: newChannels(),

		writeChan:    bs.WriteChan(),
		readChan:     bs.ReadChan(),
		isClosedChan: bs.ClosedChan(),

		pingTimer:   time.NewTimer(pingPeriod),
		pingTimeout: time.NewTimer(pingResponseTimeout),
	}

	// Create the main channel.
	s.mainChannel = s.Channel(mainChannelName)

	// Call the on close method as soon as the socket closes.
	go func() {
		<-s.isClosedChan
		s.onClose()
	}()

	// Stop the timeout again. It will be started by the ping timer.
	s.pingTimeout.Stop()

	// Add the new socket to the active sockets map.
	// If the ID is already present, then generate a new one.
	func() {
		// Lock the mutex.
		s.server.socketsMutex.Lock()
		defer s.server.socketsMutex.Unlock()

		// Be sure that the ID is unique.
		for {
			if _, ok := s.server.sockets[s.id]; !ok {
				break
			}

			s.id = utils.RandomString(socketIDLength)
		}

		// Add the socket to the map.
		s.server.sockets[s.id] = s
	}()

	// Start the loops and handlers in new goroutines.
	go s.pingTimeoutHandler()
	go s.readLoop()
	go s.pingLoop()

	return s
}
345422
func NewTSSLSocket(hostPort string, cfg *tls.Config) (*TSSLSocket, error) {
	return NewTSSLSocketTimeout(hostPort, cfg, 0)
}
1027240
func createWebSocketStreams(req *http.Request, w http.ResponseWriter, opts *Options, idleTimeout time.Duration) (*context, bool) {
	channels := createChannels(opts)
	conn := wsstream.NewConn(map[string]wsstream.ChannelProtocolConfig{
		"": {
			Binary:   true,
			Channels: channels,
		},
		preV4BinaryWebsocketProtocol: {
			Binary:   true,
			Channels: channels,
		},
		preV4Base64WebsocketProtocol: {
			Binary:   false,
			Channels: channels,
		},
		v4BinaryWebsocketProtocol: {
			Binary:   true,
			Channels: channels,
		},
		v4Base64WebsocketProtocol: {
			Binary:   false,
			Channels: channels,
		},
	})
	conn.SetIdleTimeout(idleTimeout)
	negotiatedProtocol, streams, err := conn.Open(httplog.Unlogged(w), req)
	if err != nil {
		runtime.HandleError(fmt.Errorf("Unable to upgrade websocket connection: %v", err))
		return nil, false
	}

	// Send an empty message to the lowest writable channel to notify the client the connection is established
	// TODO: make generic to SPDY and WebSockets and do it outside of this method?
	switch {
	case opts.Stdout:
		streams[stdoutChannel].Write([]byte{})
	case opts.Stderr:
		streams[stderrChannel].Write([]byte{})
	default:
		streams[errorChannel].Write([]byte{})
	}

	ctx := &context{
		conn:         conn,
		stdinStream:  streams[stdinChannel],
		stdoutStream: streams[stdoutChannel],
		stderrStream: streams[stderrChannel],
		tty:          opts.TTY,
		resizeStream: streams[resizeChannel],
	}

	switch negotiatedProtocol {
	case v4BinaryWebsocketProtocol, v4Base64WebsocketProtocol:
		ctx.writeStatus = v4WriteStatusFunc(streams[errorChannel])
	default:
		ctx.writeStatus = v1WriteStatusFunc(streams[errorChannel])
	}

	return ctx, true
}
732145
func handleWebsocketHelp(wsc *wsClient, icmd interface{}) (interface{}, error) {
	cmd, ok := icmd.(*btcjson.HelpCmd)
	if !ok {
		return nil, btcjson.ErrRPCInternal
	}

	// Provide a usage overview of all commands when no specific command
	// was specified.
	var command string
	if cmd.Command != nil {
		command = *cmd.Command
	}
	if command == "" {
		usage, err := wsc.server.helpCacher.rpcUsage(true)
		if err != nil {
			context := "Failed to generate RPC usage"
			return nil, internalRPCError(err.Error(), context)
		}
		return usage, nil
	}

	// Check that the command asked for is supported and implemented.
	// Search the list of websocket handlers as well as the main list of
	// handlers since help should only be provided for those cases.
	valid := true
	if _, ok := rpcHandlers[command]; !ok {
		if _, ok := wsHandlers[command]; !ok {
			valid = false
		}
	}
	if !valid {
		return nil, &btcjson.RPCError{
			Code:    btcjson.ErrRPCInvalidParameter,
			Message: "Unknown command: " + command,
		}
	}

	// Get the help for the command.
	help, err := wsc.server.helpCacher.rpcMethodHelp(command)
	if err != nil {
		context := "Failed to generate help"
		return nil, internalRPCError(err.Error(), context)
	}
	return help, nil
}