Files
ctrld/cmd/cli/commands_clients.go
Cuong Manh Le 54f58cc2e5 feat: capitalize all log messages for better readability
Capitalize the first letter of all log messages throughout the codebase
to improve readability and consistency in logging output.

Key improvements:
- All log messages now start with capital letters
- Consistent formatting across all logging statements
- Improved readability for debugging and monitoring
- Enhanced user experience with better formatted messages

Files updated:
- CLI commands and service management
- Internal client information discovery
- Network operations and configuration
- DNS resolver and proxy operations
- Platform-specific implementations

This completes the final phase of the logging improvement project,
ensuring all log messages follow consistent capitalization standards
for better readability and professional appearance.
2025-10-09 19:12:06 +07:00

142 lines
3.4 KiB
Go

package cli
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"github.com/kardianos/service"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
"github.com/Control-D-Inc/ctrld/internal/clientinfo"
)
// ClientsCommand handles clients-related operations
type ClientsCommand struct {
controlClient *controlClient
}
// NewClientsCommand creates a new clients command handler
func NewClientsCommand() (*ClientsCommand, error) {
dir, err := socketDir()
if err != nil {
return nil, fmt.Errorf("failed to find ctrld home dir: %w", err)
}
cc := newControlClient(filepath.Join(dir, ctrldControlUnixSock))
return &ClientsCommand{
controlClient: cc,
}, nil
}
// ListClients lists all connected clients
func (cc *ClientsCommand) ListClients(cmd *cobra.Command, args []string) error {
// Check service status first
sc := NewServiceCommand()
s, _, err := sc.initializeServiceManager()
if err != nil {
return err
}
status, err := s.Status()
if errors.Is(err, service.ErrNotInstalled) {
mainLog.Load().Warn().Msg("Service not installed")
return nil
}
if status == service.StatusStopped {
mainLog.Load().Warn().Msg("Service is not running")
return nil
}
resp, err := cc.controlClient.post(listClientsPath, nil)
if err != nil {
return fmt.Errorf("failed to get clients: %w", err)
}
defer resp.Body.Close()
var clients []*clientinfo.Client
if err := json.NewDecoder(resp.Body).Decode(&clients); err != nil {
return fmt.Errorf("failed to decode clients result: %w", err)
}
map2Slice := func(m map[string]struct{}) []string {
s := make([]string, 0, len(m))
for k := range m {
if k == "" { // skip empty source from output.
continue
}
s = append(s, k)
}
sort.Strings(s)
return s
}
// If metrics is enabled, server set this for all clients, so we can check only the first one.
// Ideally, we may have a field in response to indicate that query count should be shown, but
// it would break earlier version of ctrld, which only look list of clients in response.
withQueryCount := len(clients) > 0 && clients[0].IncludeQueryCount
data := make([][]string, len(clients))
for i, c := range clients {
row := []string{
c.IP.String(),
c.Hostname,
c.Mac,
strings.Join(map2Slice(c.Source), ","),
}
if withQueryCount {
row = append(row, strconv.FormatInt(c.QueryCount, 10))
}
data[i] = row
}
table := tablewriter.NewWriter(os.Stdout)
headers := []string{"IP", "Hostname", "Mac", "Discovered"}
if withQueryCount {
headers = append(headers, "Queries")
}
table.SetHeader(headers)
table.SetAutoFormatHeaders(false)
table.AppendBulk(data)
table.Render()
return nil
}
// InitClientsCmd creates the clients command with proper logic
func InitClientsCmd(rootCmd *cobra.Command) *cobra.Command {
listClientsCmd := &cobra.Command{
Use: "list",
Short: "List clients that ctrld discovered",
Args: cobra.NoArgs,
PreRun: func(cmd *cobra.Command, args []string) {
checkHasElevatedPrivilege()
},
RunE: func(cmd *cobra.Command, args []string) error {
cc, err := NewClientsCommand()
if err != nil {
return err
}
return cc.ListClients(cmd, args)
},
}
clientsCmd := &cobra.Command{
Use: "clients",
Short: "Manage clients",
Args: cobra.OnlyValidArgs,
ValidArgs: []string{
listClientsCmd.Use,
},
}
clientsCmd.AddCommand(listClientsCmd)
rootCmd.AddCommand(clientsCmd)
return clientsCmd
}