Skip to content

Commit

Permalink
Rearrange the config file handling code
Browse files Browse the repository at this point in the history
There is a new package called profiles and the config handling code is
now there. Instead of using the viper default APIs, I'll now explicitly
use a viper struct, and then I'll be able to use the same APIs to switch
struct to "load" another profile.
  • Loading branch information
gcla committed Jun 5, 2022
1 parent 41c25b4 commit 0117c97
Show file tree
Hide file tree
Showing 16 changed files with 306 additions and 209 deletions.
58 changes: 25 additions & 33 deletions cmd/termshark/termshark.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/gcla/termshark/v2"
"github.com/gcla/termshark/v2/capinfo"
"github.com/gcla/termshark/v2/cli"
"github.com/gcla/termshark/v2/configs/profiles"
"github.com/gcla/termshark/v2/convs"
"github.com/gcla/termshark/v2/pcap"
"github.com/gcla/termshark/v2/shark"
Expand Down Expand Up @@ -133,8 +134,6 @@ func cmain() int {
// processes start running, they use the same tty line discipline.
system.RegisterForSignals(sigChan)

viper.SetConfigName("termshark") // no need to include file extension - looks for file called termshark.ini for example

stdConf := configdir.New("", "termshark")
dirs := stdConf.QueryFolders(configdir.Cache)
if err := dirs[0].CreateParentDir("dummy"); err != nil {
Expand All @@ -144,17 +143,10 @@ func cmain() int {
if err := dirs[0].CreateParentDir("dummy"); err != nil {
fmt.Fprintf(os.Stderr, "Warning: could not create config dir: %v\n", err)
}
viper.AddConfigPath(dirs[0].Path)

if f, err := os.OpenFile(filepath.Join(dirs[0].Path, "termshark.toml"), os.O_RDONLY|os.O_CREATE, 0666); err != nil {
fmt.Fprintf(os.Stderr, "Warning: could not create initial config file: %v\n", err)
} else {
f.Close()
}

err := viper.ReadInConfig()
err := profiles.ReadDefaultConfig(dirs[0].Path)
if err != nil {
fmt.Println("Config file not found...")
fmt.Fprintf(os.Stderr, fmt.Sprintf("%s\n", err.Error()))
}

if os.Getenv("TERMSHARK_CAPTURE_MODE") == "1" {
Expand Down Expand Up @@ -312,7 +304,7 @@ func cmain() int {
// Allow the user to override the shell's TERM variable this way. Perhaps the user runs
// under screen/tmux, and the TERM variable doesn't reflect the fact their preferred
// terminal emumlator supports 256 colors.
termVar := termshark.ConfString("main.term", "")
termVar := profiles.ConfString("main.term", "")
if termVar != "" {
fmt.Fprintf(os.Stderr, "Configuration file overrides TERM setting, using TERM=%s\n", termVar)
os.Setenv("TERM", termVar)
Expand Down Expand Up @@ -533,7 +525,7 @@ func cmain() int {
}

debug := false
if (opts.Debug.Set && opts.Debug.Val == true) || (!opts.Debug.Set && termshark.ConfBool("main.debug", false)) {
if (opts.Debug.Set && opts.Debug.Val == true) || (!opts.Debug.Set && profiles.ConfBool("main.debug", false)) {
debug = true
}

Expand Down Expand Up @@ -575,7 +567,7 @@ func cmain() int {
// Here, tsharkBin is a fully-qualified tshark binary that exists on the fs (absent race
// conditions...)

valids := termshark.ConfStrings("main.validated-tsharks")
valids := profiles.ConfStrings("main.validated-tsharks")

if !termshark.StringInSlice(tsharkBin, valids) {
tver, err := termshark.TSharkVersion(tsharkBin)
Expand All @@ -592,32 +584,32 @@ func cmain() int {
}

valids = append(valids, tsharkBin)
termshark.SetConf("main.validated-tsharks", valids)
profiles.SetConf("main.validated-tsharks", valids)
}

// If the last tshark we used isn't the same as the current one, then remove the cached fields
// data structure so it can be regenerated.
if tsharkBin != termshark.ConfString("main.last-used-tshark", "") {
if tsharkBin != profiles.ConfString("main.last-used-tshark", "") {
termshark.DeleteCachedFields()
}

// Write out the last-used tshark path. We do this to make the above fields cache be consistent
// with the tshark binary we're using.
termshark.SetConf("main.last-used-tshark", tsharkBin)
profiles.SetConf("main.last-used-tshark", tsharkBin)

// Determine if the current binary supports color. Tshark will fail with an error if it's too old
// and you supply the --color flag. Assume true, and check if our current binary is not in the
// validate list.
ui.PacketColorsSupported = true
colorTsharks := termshark.ConfStrings("main.color-tsharks")
colorTsharks := profiles.ConfStrings("main.color-tsharks")

if !termshark.StringInSlice(tsharkBin, colorTsharks) {
ui.PacketColorsSupported, err = termshark.TSharkSupportsColor(tsharkBin)
if err != nil {
ui.PacketColorsSupported = false
} else {
colorTsharks = append(colorTsharks, tsharkBin)
termshark.SetConf("main.color-tsharks", colorTsharks)
profiles.SetConf("main.color-tsharks", colorTsharks)
}
}

Expand Down Expand Up @@ -732,24 +724,24 @@ func cmain() int {
}()

// Initialize application state for dark mode and auto-scroll
ui.DarkMode = termshark.ConfBool("main.dark-mode", true)
ui.AutoScroll = termshark.ConfBool("main.auto-scroll", true)
ui.PacketColors = termshark.ConfBool("main.packet-colors", true)
ui.DarkMode = profiles.ConfBool("main.dark-mode", true)
ui.AutoScroll = profiles.ConfBool("main.auto-scroll", true)
ui.PacketColors = profiles.ConfBool("main.packet-colors", true)

// Set them up here so they have access to any command-line flags that
// need to be passed to the tshark commands used
pdmlArgs := termshark.ConfStringSlice("main.pdml-args", []string{})
psmlArgs := termshark.ConfStringSlice("main.psml-args", []string{})
pdmlArgs := profiles.ConfStringSlice("main.pdml-args", []string{})
psmlArgs := profiles.ConfStringSlice("main.psml-args", []string{})
if opts.TimestampFormat != "" {
psmlArgs = append(psmlArgs, "-t", opts.TimestampFormat)
}
tsharkArgs := termshark.ConfStringSlice("main.tshark-args", []string{})
tsharkArgs := profiles.ConfStringSlice("main.tshark-args", []string{})
if ui.PacketColors && !ui.PacketColorsSupported {
log.Warnf("Packet coloring is enabled, but %s does not support --color", tsharkBin)
ui.PacketColors = false
}
cacheSize := termshark.ConfInt("main.pcap-cache-size", 64)
bundleSize := termshark.ConfInt("main.pcap-bundle-size", 1000)
cacheSize := profiles.ConfInt("main.pcap-cache-size", 64)
bundleSize := profiles.ConfInt("main.pcap-bundle-size", 1000)
if bundleSize <= 0 {
maxBundleSize := 100000
log.Infof("Config specifies pcap-bundle-size as %d - setting to max (%d)", bundleSize, maxBundleSize)
Expand Down Expand Up @@ -795,8 +787,8 @@ func cmain() int {
// 0-21 are set up normally, and not remapped. If the closest match is one of those
// colors, then the theme won't look as expected. A workaround is to tell
// gowid not to use colors 0-21 when finding the closest match.
if termshark.ConfKeyExists("main.ignore-base16-colors") {
gowid.IgnoreBase16 = termshark.ConfBool("main.ignore-base16-colors", false)
if profiles.ConfKeyExists("main.ignore-base16-colors") {
gowid.IgnoreBase16 = profiles.ConfBool("main.ignore-base16-colors", false)
} else {
// Try to auto-detect whether or not base16-shell is installed and in-use
gowid.IgnoreBase16 = (os.Getenv("BASE16_SHELL") != "")
Expand All @@ -810,7 +802,7 @@ func cmain() int {
// just an implementation snafu, or if something else is going on... In any case,
// termshark will fall back to 256-colors if base16 is detected because I can
// programmatically avoid choosing colors 0-21 for anything termshark needs.
if os.Getenv("COLORTERM") != "" && !termshark.ConfBool("main.respect-colorterm", false) {
if os.Getenv("COLORTERM") != "" && !profiles.ConfBool("main.respect-colorterm", false) {
log.Infof("Pessimistically disabling 24-bit color to avoid conflicts with base16")
os.Unsetenv("COLORTERM")
}
Expand Down Expand Up @@ -1129,7 +1121,7 @@ Loop:
case <-checkPcapCacheChan:
// Only check the cache dir if we own it; don't want to delete pcap files
// that might be shared with wireshark
if termshark.ConfBool("main.use-tshark-temp-for-pcap-cache", false) {
if profiles.ConfBool("main.use-tshark-temp-for-pcap-cache", false) {
log.Infof("Termshark does not own the pcap temp dir %s; skipping size check", termshark.PcapDir())
} else {
termshark.PrunePcapCache()
Expand Down Expand Up @@ -1160,7 +1152,7 @@ Loop:
// activated.
mode := app.GetColorMode()
modeStr := theme.Mode(mode) // more concise
themeName := termshark.ConfString(fmt.Sprintf("main.theme-%s", modeStr), "default")
themeName := profiles.ConfString(fmt.Sprintf("main.theme-%s", modeStr), "default")
loaded := false
if themeName != "" {
err = theme.Load(themeName, app)
Expand Down Expand Up @@ -1198,7 +1190,7 @@ Loop:
// If exists is true, it means we already tried and then reverted back, so
// just load up termshark normally with no further interruption.
if _, exists := os.LookupEnv("TERMSHARK_ORIGINAL_TERM"); !exists {
if !termshark.ConfBool("main.disable-term-helper", false) {
if !profiles.ConfBool("main.disable-term-helper", false) {
err = termshark.Does256ColorTermExist()
if err != nil {
log.Infof("Must use 8-color mode because 256-color version of TERM=%s unavailable - %v.", os.Getenv("TERM"), err)
Expand Down
169 changes: 169 additions & 0 deletions configs/profiles/profiles.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Copyright 2019-2022 Graham Clark. All rights reserved. Use of this source
// code is governed by the MIT license that can be found in the LICENSE
// file.

package profiles

import (
"fmt"
"os"
"path/filepath"
"sync"

"github.com/spf13/viper"
)

//======================================================================

// The config is accessed by the main goroutine and pcap loading goroutines. So this
// is an attempt to prevent warnings with the -race flag (though they are very likely
// harmless)
var confMutex sync.Mutex

// If this is non-nil, then the user has a profile loaded
var vProfile *viper.Viper
var vDefault *viper.Viper

//======================================================================

func init() {
vDefault = viper.New()
vProfile = viper.New()
}

//======================================================================

// First is error, second is warning
func ReadDefaultConfig(dir string) error {
return readConfig(vDefault, dir, "termshark")
}

func readConfig(v *viper.Viper, dir string, base string) error {
confMutex.Lock()
defer confMutex.Unlock()

var err error

v.SetConfigName(base) // no need to include file extension - looks for file called termshark.ini for example
v.AddConfigPath(dir)

fp := filepath.Join(dir, fmt.Sprintf("%s.toml", base))
if f, err2 := os.OpenFile(fp, os.O_RDONLY|os.O_CREATE, 0666); err2 != nil {
err = fmt.Errorf("Warning: could not create initial config file: %w", err2)
} else {
f.Close()
}

err = v.ReadInConfig()
if err != nil {
err = fmt.Errorf("Warning: config file %s not found...", fp)
}

return err
}

func ConfKeyExists(name string) bool {
return confKeyExists(vDefault, name)
}

func confKeyExists(v *viper.Viper, name string) bool {
return v.Get(name) != nil
}

func ConfString(name string, def string) string {
return confString(vDefault, name, def)
}

func confString(v *viper.Viper, name string, def string) string {
confMutex.Lock()
defer confMutex.Unlock()
if v.Get(name) != nil {
return v.GetString(name)
} else {
return def
}
}

func SetConf(name string, val interface{}) {
setConf(vDefault, name, val)
}

func setConf(v *viper.Viper, name string, val interface{}) {
confMutex.Lock()
defer confMutex.Unlock()
v.Set(name, val)
v.WriteConfig()
}

func ConfStrings(name string) []string {
return confStrings(vDefault, name)
}

func confStrings(v *viper.Viper, name string) []string {
confMutex.Lock()
defer confMutex.Unlock()
return v.GetStringSlice(name)
}

func DeleteConf(name string) {
deleteConf(vDefault, name)
}

func deleteConf(v *viper.Viper, name string) {
confMutex.Lock()
defer confMutex.Unlock()
v.Set(name, "")
v.WriteConfig()
}

func ConfInt(name string, def int) int {
return confInt(vDefault, name, def)
}

func confInt(v *viper.Viper, name string, def int) int {
confMutex.Lock()
defer confMutex.Unlock()
if v.Get(name) != nil {
return v.GetInt(name)
} else {
return def
}
}

func ConfBool(name string, def ...bool) bool {
return confBool(vDefault, name, def...)
}

func confBool(v *viper.Viper, name string, def ...bool) bool {
confMutex.Lock()
defer confMutex.Unlock()
if v.Get(name) != nil {
return v.GetBool(name)
} else {
if len(def) > 0 {
return def[0]
} else {
return false
}
}
}

func ConfStringSlice(name string, def []string) []string {
return confStringSlice(vDefault, name, def)
}

func confStringSlice(v *viper.Viper, name string, def []string) []string {
confMutex.Lock()
defer confMutex.Unlock()
res := v.GetStringSlice(name)
if res == nil {
res = def
}
return res
}

//======================================================================
// Local Variables:
// mode: Go
// fill-column: 78
// End:
3 changes: 2 additions & 1 deletion shark/columnformat.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/gcla/gowid/widgets/table"
"github.com/gcla/termshark/v2"
"github.com/gcla/termshark/v2/configs/profiles"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -295,7 +296,7 @@ func GetPsmlColumnFormatFrom(colKey string) []PsmlColumnSpec {

func getPsmlColumnFormatWithoutLock(colKey string) []PsmlColumnSpec {
res := make([]PsmlColumnSpec, 0)
widths := termshark.ConfStringSlice(colKey, []string{})
widths := profiles.ConfStringSlice(colKey, []string{})
if len(widths) == 0 || (len(widths)/3)*3 != len(widths) {
logrus.Warnf("Unexpected %s structure - using defaults", colKey)
res = DefaultPsmlColumnSpec
Expand Down
Loading

0 comments on commit 0117c97

Please sign in to comment.