code: func (db *Dashboard) apiHandler(conn *websocket.Conn) {
  	id := atomic.AddUint32(&db.nextConnID, 1)
  	client := &client{
  		conn:   conn,
  		msg:    make(chan *Message, 128),
  		logger: log.New("id", id),
  	}
  	done := make(chan struct{})
  
  	// Start listening for messages to send.
  	db.wg.Add(1)
  	go func() {
  		defer db.wg.Done()
  
  		for {
  			select {
  			case <-done:
  				return
  			case msg := <-client.msg:
  				if err := websocket.JSON.Send(client.conn, msg); err != nil {
  					client.logger.Warn("Failed to send the message", "msg", msg, "err", err)
  					client.conn.Close()
  					return
  				}
  			}
  		}
  	}()
  
  	// Send the past data.
  	db.sysLock.RLock()
  	db.peerLock.RLock()
  	db.logLock.RLock()
  
  	h := deepcopy.Copy(db.history).(*Message)
  
  	db.sysLock.RUnlock()
  	db.peerLock.RUnlock()
  	db.logLock.RUnlock()
  
  	client.msg <- h
  
  	// Start tracking the connection and drop at connection loss.
  	db.lock.Lock()
  	db.conns[id] = client
  	db.lock.Unlock()
  	defer func() {
  		db.lock.Lock()
  		delete(db.conns, id)
  		db.lock.Unlock()
  	}()
  	for {
  		r := new(Request)
  		if err := websocket.JSON.Receive(conn, r); err != nil {
  			if err != io.EOF {
  				client.logger.Warn("Failed to receive request", "err", err)
  			}
  			close(done)
  			return
  		}
  		if r.Logs != nil {
  			db.handleLogRequest(r.Logs, client)
  		}
  	}
  }
docs: // apiHandler handles requests for the dashboard.