src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

wwan.go (2169B)


      1 package wwan
      2 
      3 import (
      4 	"bufio"
      5 	"bytes"
      6 	"context"
      7 	"fmt"
      8 	"net"
      9 	"os/exec"
     10 	"path"
     11 	"strings"
     12 )
     13 
     14 type Block struct {
     15 	iface string
     16 }
     17 
     18 func New(iface string) *Block {
     19 	return &Block{iface: iface}
     20 }
     21 
     22 func (b *Block) Name() string {
     23 	return "wwan"
     24 }
     25 
     26 // TODO: signal strength icon.
     27 // TODO: get IP address (net.Interfaces).
     28 func (b *Block) Render(ctx context.Context) (string, error) {
     29 	out, err := exec.CommandContext(ctx, "mmcli", "--list-modems").Output()
     30 	if err != nil {
     31 		return "", fmt.Errorf("exec mmcli failed: %v", err)
     32 	}
     33 
     34 	fields := strings.Fields(string(out))
     35 	if len(fields) == 0 {
     36 		return "", fmt.Errorf("unexpected output: %v", err)
     37 	}
     38 	modem := path.Base(fields[0])
     39 
     40 	out, err = exec.CommandContext(
     41 		ctx, "mmcli", "-m", modem, "--output-keyvalue",
     42 	).Output()
     43 	if err != nil {
     44 		return "", fmt.Errorf("exec mmcli failed: %v", err)
     45 	}
     46 
     47 	var (
     48 		scanner = bufio.NewScanner(bytes.NewReader(out))
     49 
     50 		state, signal string
     51 	)
     52 	for scanner.Scan() {
     53 		fields := strings.Fields(scanner.Text())
     54 		if len(fields) < 3 {
     55 			continue
     56 		}
     57 
     58 		switch {
     59 		case fields[0] == "modem.generic.state":
     60 			state = fields[2]
     61 		case fields[0] == "modem.generic.signal-quality.value":
     62 			signal = fields[2]
     63 		}
     64 	}
     65 
     66 	if state == "disabled" {
     67 		return " ", nil
     68 	}
     69 
     70 	// Get the IP address.
     71 	iface, err := net.InterfaceByName(b.iface)
     72 	if err != nil {
     73 		return "", fmt.Errorf(
     74 			"failed to get interface %s: %v", b.iface, err,
     75 		)
     76 	}
     77 
     78 	var ip4, ip6 string
     79 	addrs, err := iface.Addrs()
     80 	if err != nil {
     81 		return "", fmt.Errorf("failed to get addresses: %v", err)
     82 	}
     83 
     84 	for _, addr := range addrs {
     85 		a := addr.String()
     86 		if isIPv4(a) {
     87 			ip4 = a
     88 			continue
     89 		} else {
     90 			ip6 = a
     91 		}
     92 	}
     93 
     94 	switch {
     95 	case ip4 == "" && ip6 == "":
     96 		return fmt.Sprintf(" %s%%", signal), nil
     97 	case ip4 != "" && ip6 == "":
     98 		return fmt.Sprintf(" %s %s%%", ip4, signal), nil
     99 	case ip4 == "" && ip6 != "":
    100 		return fmt.Sprintf(" %s %s%%", ip6, signal), nil
    101 	default:
    102 		return fmt.Sprintf(" %s %s %s%%", ip4, ip6, signal), nil
    103 	}
    104 }
    105 
    106 func isIPv4(s string) bool {
    107 	for i := 0; i < len(s); i++ {
    108 		switch s[i] {
    109 		case '.':
    110 			return true
    111 		case ':':
    112 			return false
    113 		}
    114 	}
    115 
    116 	return false
    117 }