diff --git a/cmd/cli/cli.go b/cmd/cli/cli.go index 1ba716c..dfe0507 100644 --- a/cmd/cli/cli.go +++ b/cmd/cli/cli.go @@ -21,11 +21,10 @@ import ( ) var ( - verbose bool - socketFile string - workspace string - ver = version.Get() - cliCmd = &cobra.Command{ + verbose bool + workspace string + ver = version.Get() + cliCmd = &cobra.Command{ Use: "stt-cli", Short: "", Long: ``, @@ -41,10 +40,8 @@ var ( logger.Debug().Str("foo", "bar").Msg("this is a dummy log") } - socketPath := filepath.Join(workspace, socketFile) - - cmd.SetContext(context.WithValue(cmd.Context(), constants.SocketPathKey{}, socketPath)) cmd.SetContext(context.WithValue(cmd.Context(), constants.LoggerKey{}, logger)) + cmd.SetContext(context.WithValue(cmd.Context(), constants.SocketPathKey{}, filepath.Join(workspace, constants.SocketFileName))) }, } ) @@ -66,7 +63,6 @@ func init() { } cliCmd.PersistentFlags().StringVarP(&workspace, "workspace", "w", filepath.Join(homeDir, ".split-the-tunnel"), "workspace directory path") - cliCmd.PersistentFlags().StringVarP(&socketFile, "socket-file", "s", "ipc.sock", "unix domain socket file in workspace") cliCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "enable verbose mode") cliCmd.AddCommand(add.AddCmd) diff --git a/cmd/daemon/daemon.go b/cmd/daemon/daemon.go index 7b7e585..be61b70 100644 --- a/cmd/daemon/daemon.go +++ b/cmd/daemon/daemon.go @@ -20,11 +20,6 @@ import ( "github.com/spf13/cobra" ) -var ( - opts *options.RootOptions - ver = version.Get() -) - func init() { opts = options.GetRootOptions() if err := opts.InitFlags(daemonCmd); err != nil { @@ -32,72 +27,80 @@ func init() { } } -// daemonCmd represents the base command when called without any subcommands -var daemonCmd = &cobra.Command{ - Use: "split-the-tunnel", - Short: "", - Long: ``, - Version: ver.GitVersion, - RunE: func(cmd *cobra.Command, args []string) error { - if err := opts.ReadConfig(); err != nil { - return errors.Wrap(err, "failed to read config") - } - - fmt.Println(opts) - - if err := os.MkdirAll(opts.Workspace, 0755); err != nil { - return errors.Wrap(err, "failed to create workspace directory") - } - - logger := logging.GetLogger().With().Str("job", "main").Logger() - logger.Info().Str("appVersion", ver.GitVersion).Str("goVersion", ver.GoVersion).Str("goOS", ver.GoOs). - Str("goArch", ver.GoArch).Str("gitCommit", ver.GitCommit).Str("buildDate", ver.BuildDate). - Msg(constants.AppStarted) - - // Setup signal handling for a graceful shutdown - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) - - st := state.NewState(logger) - - // Initialize IPC mechanism - if err := ipc.InitIPC(st, opts.SocketPath, logger); err != nil { - logger.Error().Err(err).Msg(constants.FailedToInitializeIPC) - return err - } - - logger.Info().Str("socket", opts.SocketPath).Msg(constants.IPCInitialized) - - defer func() { - if err := ipc.Cleanup(opts.SocketPath); err != nil { - logger.Error().Err(err).Msg(constants.FailedToCleanupIPC) +var ( + // opts is the root options of the application + opts *options.RootOptions + // ver is the version of the application + ver = version.Get() + // daemonCmd represents the base command when called without any subcommands + daemonCmd = &cobra.Command{ + Use: "split-the-tunnel", + Short: "", + Long: ``, + Version: ver.GitVersion, + RunE: func(cmd *cobra.Command, args []string) error { + if err := os.MkdirAll(opts.Workspace, 0755); err != nil { + return errors.Wrap(err, "failed to create workspace directory") } - }() - logger.Info().Str("socket", opts.SocketPath).Msg(constants.DaemonRunning) + if err := opts.ReadConfig(); err != nil { + return errors.Wrap(err, "failed to read config") + } + + fmt.Println(opts) + + logger := logging.GetLogger().With().Str("job", "main").Logger() + logger.Info().Str("appVersion", ver.GitVersion).Str("goVersion", ver.GoVersion).Str("goOS", ver.GoOs). + Str("goArch", ver.GoArch).Str("gitCommit", ver.GitCommit).Str("buildDate", ver.BuildDate). + Msg(constants.AppStarted) - go func() { - // Create a ticker that fires every 5 minutes - ticker := time.NewTicker(10 * time.Second) - logger := logger.With().Str("job", "ip-change-check").Logger() + st := state.NewState(logger, opts.StatePath) + + // initialize IPC for communication between CLI and daemon + if err := ipc.InitIPC(st, opts.SocketPath, logger); err != nil { + logger.Error().Err(err).Msg(constants.FailedToInitializeIPC) + return err + } - for range ticker.C { - if <-ticker.C; true { - if err := st.CheckIPChanges(); err != nil { - logger.Error().Err(err).Msg("failed to check ip changes") + logger.Info().Str("socket", opts.SocketPath).Msg(constants.IPCInitialized) + + defer func() { + logger := logger.With().Str("job", "cleanup").Logger() + logger.Info().Msg(constants.CleaningUpIPC) + if err := ipc.Cleanup(opts.SocketPath); err != nil { + logger.Error().Err(err).Msg(constants.FailedToCleanupIPC) + } + }() + + logger.Info().Str("socket", opts.SocketPath).Msg(constants.DaemonRunning) + + go func() { + // Create a ticker that fires every 5 minutes + ticker := time.NewTicker(time.Duration(int64(opts.CheckIntervalMin)) * time.Minute) + logger := logger.With().Str("job", "ip-change-check").Logger() + + for range ticker.C { + if <-ticker.C; true { + if err := st.CheckIPChanges(); err != nil { + logger.Error().Err(err).Msg("failed to check ip changes") + } } } - } - }() + }() - // Wait for termination signal to gracefully shut down the daemon - s := <-sigs - logger.Info().Any("signal", s.String()).Msg(constants.TermSignalReceived) - logger.Info().Msg(constants.ShuttingDownDaemon) + // setup signal handling for graceful shutdown + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) - return nil - }, -} + // Wait for termination signal to gracefully shut down the daemon + s := <-sigs + logger.Info().Any("signal", s.String()).Msg(constants.TermSignalReceived) + logger.Info().Msg(constants.ShuttingDownDaemon) + + return nil + }, + } +) func main() { if err := daemonCmd.Execute(); err != nil { diff --git a/cmd/daemon/options/options.go b/cmd/daemon/options/options.go index e369b62..ebef15a 100644 --- a/cmd/daemon/options/options.go +++ b/cmd/daemon/options/options.go @@ -1,10 +1,11 @@ package options import ( - "log" "os" "path/filepath" + "github.com/bilalcaliskan/split-the-tunnel/internal/constants" + "github.com/spf13/viper" "github.com/pkg/errors" @@ -13,14 +14,22 @@ import ( var rootOptions = &RootOptions{} -// RootOptions contains frequent command line and application options. type RootOptions struct { - Workspace string // This field will be managed by the command line argument - ConfigFile string // This field will be managed by the command line argument - DnsServers string `toml:"dns-servers"` // This field will be managed by the config file - CheckIntervalMin int `toml:"check-interval-min"` // This field will be managed by the config file - SocketPath string `toml:"socket-path"` // This field will be managed by the config file - Verbose bool `toml:"verbose"` // This field will be managed by the config file + // Workspace is the directory path where the application will store its data + Workspace string + // ConfigFile is the path of the configuration file, which will be searched in the Workspace + ConfigFile string + // SocketPath is the path of the socket file, which will be stored in the Workspace + SocketPath string + // StatePath is the path of the state file, which will be stored in the Workspace + StatePath string + + // DnsServers is the list of DNS servers to be used for DNS resolving + DnsServers string `toml:"dnsservers"` + // CheckIntervalMin is the interval in minutes to check the routing table with the collected state.State + CheckIntervalMin int `toml:"checkintervalmin"` + // Verbose is the flag to enable verbose logging output + Verbose bool `toml:"verbose"` } // GetRootOptions returns the pointer of RootOptions @@ -28,6 +37,7 @@ func GetRootOptions() *RootOptions { return rootOptions } +// InitFlags initializes the flags of the root command func (opts *RootOptions) InitFlags(cmd *cobra.Command) error { if err := opts.setFlags(cmd); err != nil { return errors.Wrap(err, "failed to set flags") @@ -40,19 +50,7 @@ func (opts *RootOptions) InitFlags(cmd *cobra.Command) error { return nil } -//func (opts *RootOptions) setDefaultWorkspace() error { -// homeDir, err := os.UserHomeDir() -// if err != nil { -// return errors.Wrap(err, "failed to get user home directory") -// } -// -// ws := filepath.Join(homeDir, ".split-the-tunnel") -// opts.Workspace = ws -// opts.ConfigFile = filepath.Join(ws, "config.toml") -// -// return nil -//} - +// setFlags sets the flags of the root command func (opts *RootOptions) setFlags(cmd *cobra.Command) error { homeDir, err := os.UserHomeDir() if err != nil { @@ -61,7 +59,6 @@ func (opts *RootOptions) setFlags(cmd *cobra.Command) error { cmd.Flags().StringVarP(&opts.Workspace, "workspace", "w", filepath.Join(homeDir, ".split-the-tunnel"), "workspace directory path") cmd.Flags().StringVarP(&opts.ConfigFile, "config-file", "c", "config.toml", "config file path, will search in workspace") - cmd.Flags().StringVarP(&opts.SocketPath, "socket-path", "", "ipc.sock", "unix domain socket path in workspace") cmd.Flags().BoolVarP(&opts.Verbose, "verbose", "", false, "verbose logging output") cmd.Flags().StringVarP(&opts.DnsServers, "dns-servers", "", "", "comma separated dns servers to be used for DNS resolving") cmd.Flags().IntVarP(&opts.CheckIntervalMin, "check-interval-min", "", 5, "routing table check interval with collected state, in minutes") @@ -69,20 +66,10 @@ func (opts *RootOptions) setFlags(cmd *cobra.Command) error { return nil } +// ReadConfig reads the configuration file and unmarshalls it into RootOptions func (opts *RootOptions) ReadConfig() error { - viper.SetConfigFile(opts.ConfigFile) viper.SetConfigType("toml") - - opts.SocketPath = filepath.Join(opts.Workspace, opts.SocketPath) - opts.ConfigFile = filepath.Join(opts.Workspace, opts.ConfigFile) - - if _, err := os.Stat(opts.ConfigFile); os.IsNotExist(err) { - log.Printf("config file not found in %s, will use default values\n", opts.ConfigFile) - return nil - } else if err != nil { - return errors.Wrap(err, "failed to access config file") - } - + viper.SetConfigFile(filepath.Join(opts.Workspace, opts.ConfigFile)) if err := viper.ReadInConfig(); err != nil { return errors.Wrap(err, "failed to read config file") } @@ -91,5 +78,9 @@ func (opts *RootOptions) ReadConfig() error { return errors.Wrap(err, "failed to unmarshal config file") } + opts.ConfigFile = filepath.Join(opts.Workspace, opts.ConfigFile) + opts.StatePath = filepath.Join(opts.Workspace, constants.StateFileName) + opts.SocketPath = filepath.Join(opts.Workspace, constants.SocketFileName) + return nil } diff --git a/internal/config/config.go b/internal/config/config.go deleted file mode 100644 index a4ffaf4..0000000 --- a/internal/config/config.go +++ /dev/null @@ -1,32 +0,0 @@ -package config - -import ( - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -func ReadConfig(cmd *cobra.Command, path string) (conf *Config, err error) { - // set config file name and path - viper.SetConfigName(path) - viper.SetConfigType("toml") - viper.AddConfigPath(".") - - // read config file - if err := viper.ReadInConfig(); err != nil { - return nil, errors.Wrap(err, "an error occurred while reading config file") - } - - // unmarshal config file into Config struct - if err := viper.Unmarshal(&conf); err != nil { - return nil, errors.Wrap(err, "an error occurred while unmarshaling config file") - } - - // if a flag is set, it overrides the value in config file - if cmd.Flags().Changed("verbose") { - verbose, _ := cmd.Flags().GetBool("verbose") - conf.Verbose = verbose - } - - return conf, nil -} diff --git a/internal/config/types.go b/internal/config/types.go deleted file mode 100644 index a3f871f..0000000 --- a/internal/config/types.go +++ /dev/null @@ -1,9 +0,0 @@ -package config - -// Config struct represents the config file -type Config struct { - CheckIntervalMin int `toml:"check-interval-min"` - DnsServers []string `toml:"dns-servers"` - Verbose bool `toml:"verbose"` - SocketPath string `toml:"socket-path"` -} diff --git a/internal/constants/errors.go b/internal/constants/errors.go index f013d4d..62cc725 100644 --- a/internal/constants/errors.go +++ b/internal/constants/errors.go @@ -5,15 +5,13 @@ const ( FailedToConnectToUnixDomainSocket = "failed to connect to unix domain socket" FailedToOpenRoutingInfoFile = "failed to open routing info file" FailedToWriteToUnixDomainSocket = "failed to write to unix domain socket" - FileDoesNotExist = "file does not exist" - NoArgumentsProvided = "no arguments provided" + FailedToWriteState = "failed to write state to file" FailedToReadFromIPC = "failed to read from IPC connection" FailedToReloadState = "failed to reload state" FailedToGetDefaultGateway = "failed to get default gateway" EmptyCommandReceived = "empty command received" FailedToResolveDomain = "failed to resolve domain" FailedToMarshalResponse = "failed to marshal response" - FailedToWriteRouteEntry = "failed to write RouteEntry to state" EntryNotFound = "route entry not found in state" NonVPNGatewayNotFound = "non-VPN gateway not found" FailedToDecodeHex = "failed to decode hex string" @@ -22,6 +20,4 @@ const ( FailedToCleanupIPC = "failed to cleanup IPC" FailedToInitializeIPC = "failed to initialize IPC" FailedToRemoveRouteEntry = "failed to remove RouteEntry from state" - EntryAlreadyExists = "route entry already exists in state" - NoRoutesToPurge = "no routes to purge" ) diff --git a/internal/constants/infos.go b/internal/constants/infos.go index 299bf6c..2d25297 100644 --- a/internal/constants/infos.go +++ b/internal/constants/infos.go @@ -2,10 +2,12 @@ package constants const ( SuccessfullyProcessed = "successfully processed command" - IPCInitialized = "IPC is initialized" + IPCInitialized = "ipc is initialized" DaemonRunning = "daemon is running, waiting for requests over unix domain socket..." TermSignalReceived = "termination signal received" ShuttingDownDaemon = "shutting down daemon..." AppStarted = "split-the-tunnel is started!" ProcessCommand = "processing command" + CleaningUpIPC = "cleaning up IPC socket" + PurgedAllRoutes = "purged all routes" ) diff --git a/internal/constants/others.go b/internal/constants/types.go similarity index 59% rename from internal/constants/others.go rename to internal/constants/types.go index 515672e..3755537 100644 --- a/internal/constants/others.go +++ b/internal/constants/types.go @@ -1,7 +1,8 @@ package constants const ( - StateFilePath = "/tmp/state.json" + StateFileName = "state.json" + SocketFileName = "ipc.sock" ) type ( diff --git a/internal/constants/warnings.go b/internal/constants/warnings.go new file mode 100644 index 0000000..17f5ffc --- /dev/null +++ b/internal/constants/warnings.go @@ -0,0 +1,6 @@ +package constants + +const ( + EntryAlreadyExists = "route entry already exists in state" + NoRoutesToPurge = "no routes to purge" +) diff --git a/internal/ipc/ipc.go b/internal/ipc/ipc.go index c70478a..ec02566 100644 --- a/internal/ipc/ipc.go +++ b/internal/ipc/ipc.go @@ -117,10 +117,17 @@ func processCommand(logger zerolog.Logger, command string, conn net.Conn, st *st // handleAddCommand handles the add command and adds the given domains to the routing table func handleAddCommand(logger zerolog.Logger, gw string, domains []string, conn net.Conn, st *state.State) { logger = logger.With().Str("operation", "add").Logger() + resp := new(DaemonResponse) for _, domain := range domains { ips, err := utils.ResolveDomain(domain) if err != nil { + logger.Error().Err(err).Str("domain", domain).Msg(constants.FailedToResolveDomain) + + resp.Success = false + resp.Response = "" + resp.Error = errors.Wrap(err, constants.FailedToResolveDomain).Error() + if err := writeResponse(&DaemonResponse{ Success: false, Response: "", @@ -189,15 +196,17 @@ func handleAddCommand(logger zerolog.Logger, gw string, domains []string, conn n } } +// handlePurgeCommand removes all the routes from the routing table by looking at the state func handlePurgeCommand(logger zerolog.Logger, conn net.Conn, st *state.State) { logger = logger.With().Str("operation", "purge").Logger() + resp := new(DaemonResponse) if len(st.Entries) == 0 { - if err := writeResponse(&DaemonResponse{ - Success: false, - Response: "", - Error: errors.New(constants.NoRoutesToPurge).Error(), - }, conn); err != nil { + resp.Success = false + resp.Response = "" + resp.Error = errors.New(constants.NoRoutesToPurge).Error() + + if err := writeResponse(resp, conn); err != nil { logger.Error(). Err(err). Msg(constants.FailedToWriteToUnixDomainSocket) @@ -206,17 +215,16 @@ func handlePurgeCommand(logger zerolog.Logger, conn net.Conn, st *state.State) { return } - // TODO: in each iteration, we should somehow mark routing table entries for _, entry := range st.Entries { for _, ip := range entry.ResolvedIPs { if err := utils.RemoveRoute(ip); err != nil { logger.Error().Err(err).Str("domain", entry.Domain).Str("ip", ip).Msg("failed to remove route from routing table") - if err := writeResponse(&DaemonResponse{ - Success: false, - Response: "", - Error: errors.Wrapf(err, "failed to remove route for domain %s from routing table", entry.Domain).Error(), - }, conn); err != nil { + resp.Success = false + resp.Response = "" + resp.Error = errors.Wrapf(err, "failed to remove route for domain %s from routing table", entry.Domain).Error() + + if err := writeResponse(resp, conn); err != nil { logger.Error(). Err(err). Str("domain", entry.Domain). @@ -231,16 +239,27 @@ func handlePurgeCommand(logger zerolog.Logger, conn net.Conn, st *state.State) { } st.Entries = make([]*state.RouteEntry, 0) + if err := st.Write(); err != nil { + logger.Error().Err(err).Msg(constants.FailedToWriteState) + + resp.Success = false + resp.Response = "" + resp.Error = errors.Wrap(err, constants.FailedToWriteState).Error() - if err := st.Write(constants.StateFilePath); err != nil { - logger.Error().Err(err).Msg("failed to write state to file") + if err := writeResponse(resp, conn); err != nil { + logger.Error(). + Err(err). + Msg(constants.FailedToWriteToUnixDomainSocket) + } + + return } - if err := writeResponse(&DaemonResponse{ - Success: true, - Response: "purged all routes", - Error: "", - }, conn); err != nil { + resp.Success = true + resp.Response = constants.PurgedAllRoutes + resp.Error = "" + + if err := writeResponse(resp, conn); err != nil { logger.Error(). Err(err). Msg(constants.FailedToWriteToUnixDomainSocket) @@ -250,36 +269,39 @@ func handlePurgeCommand(logger zerolog.Logger, conn net.Conn, st *state.State) { // handleRemoveCommand removes the given domains from the routing table func handleRemoveCommand(logger zerolog.Logger, domains []string, conn net.Conn, st *state.State) { logger = logger.With().Str("operation", "remove").Logger() + resp := new(DaemonResponse) for _, domain := range domains { entry := st.GetEntry(domain) if entry == nil { - if err := writeResponse(&DaemonResponse{ - Success: false, - Response: "", - Error: errors.Wrap(errors.New(constants.EntryNotFound), constants.FailedToRemoveRouteEntry).Error(), - }, conn); err != nil { + resp.Success = false + resp.Response = "" + resp.Error = errors.Wrap(errors.New(constants.EntryNotFound), constants.FailedToRemoveRouteEntry).Error() + + if err := writeResponse(resp, conn); err != nil { logger.Error(). Err(err). Str("domain", domain). Msg(constants.FailedToWriteToUnixDomainSocket) } + continue } if err := st.RemoveEntry(domain); err != nil { - logger.Error().Err(err).Str("domain", domain).Msg("failed to remove route from state") + logger.Error().Err(err).Str("domain", domain).Msg(constants.FailedToRemoveRouteEntry) - if err := writeResponse(&DaemonResponse{ - Success: false, - Response: "", - Error: errors.Wrap(err, constants.FailedToRemoveRouteEntry).Error(), - }, conn); err != nil { + resp.Success = false + resp.Response = "" + resp.Error = errors.Wrap(err, constants.FailedToRemoveRouteEntry).Error() + + if err := writeResponse(resp, conn); err != nil { logger.Error(). Err(err). Str("domain", domain). Msg(constants.FailedToWriteToUnixDomainSocket) } + continue } @@ -287,11 +309,11 @@ func handleRemoveCommand(logger zerolog.Logger, domains []string, conn net.Conn, if err := utils.RemoveRoute(ip); err != nil { logger.Error().Err(err).Str("domain", domain).Str("ip", ip).Msg("failed to remove route from routing table") - if err := writeResponse(&DaemonResponse{ - Success: false, - Response: "", - Error: errors.Wrapf(err, "failed to remove route for domain %s from routing table", domain).Error(), - }, conn); err != nil { + resp.Success = false + resp.Response = "" + resp.Error = errors.Wrapf(err, "failed to remove route for domain %s from routing table", domain).Error() + + if err := writeResponse(resp, conn); err != nil { logger.Error(). Err(err). Str("domain", domain). @@ -304,11 +326,11 @@ func handleRemoveCommand(logger zerolog.Logger, domains []string, conn net.Conn, logger.Info().Str("domain", domain).Msg("successfully removed route from routing table") - if err := writeResponse(&DaemonResponse{ - Success: true, - Response: fmt.Sprintf("removed route for " + domain), - Error: "", - }, conn); err != nil { + resp.Success = true + resp.Response = fmt.Sprintf("removed route for " + domain) + resp.Error = "" + + if err := writeResponse(resp, conn); err != nil { logger.Error(). Err(err). Str("domain", domain). @@ -318,7 +340,7 @@ func handleRemoveCommand(logger zerolog.Logger, domains []string, conn net.Conn, } func handleListCommand(logger zerolog.Logger, conn net.Conn, st *state.State) { - response := new(DaemonResponse) + logger = logger.With().Str("operation", "list").Logger() str, err := state.ToStringSlice(st.Entries) if err != nil { @@ -328,6 +350,7 @@ func handleListCommand(logger zerolog.Logger, conn net.Conn, st *state.State) { return } + response := new(DaemonResponse) response.Response = str responseJson, err := json.Marshal(response) if err != nil { diff --git a/internal/state/state.go b/internal/state/state.go index d644cba..b979755 100644 --- a/internal/state/state.go +++ b/internal/state/state.go @@ -18,13 +18,15 @@ import ( type State struct { Entries []*RouteEntry `json:"entries"` logger zerolog.Logger + path string } // NewState creates a new State with an empty list of RouteEntry -func NewState(logger zerolog.Logger) *State { +func NewState(logger zerolog.Logger, path string) *State { return &State{ - Entries: []*RouteEntry{}, - logger: logger, + []*RouteEntry{}, + logger, + path, } } @@ -56,7 +58,7 @@ func (s *State) CheckIPChanges() error { s.logger.Info(). Str("job", "ip-change"). Msg("ip changes detected, applying internal state") - return s.Write(constants.StateFilePath) + return s.Write() } s.logger.Info(). @@ -112,13 +114,13 @@ func (s *State) AddEntry(entry *RouteEntry) error { } e.ResolvedIPs = entry.ResolvedIPs - return s.Write(constants.StateFilePath) + return s.Write() } } s.Entries = append(s.Entries, entry) - return s.Write(constants.StateFilePath) + return s.Write() } // RemoveEntry removes a RouteEntry from the State @@ -126,7 +128,7 @@ func (s *State) RemoveEntry(domain string) error { for i, entry := range s.Entries { if entry.Domain == domain { s.Entries = append(s.Entries[:i], s.Entries[i+1:]...) - return s.Write(constants.StateFilePath) + return s.Write() } } @@ -148,18 +150,16 @@ func (s *State) GetEntry(domain string) *RouteEntry { // Reload reads the State from the given path func (s *State) Reload() error { // Attempt to get the file status - var _, err = os.Stat(constants.StateFilePath) - - if err != nil { + if _, err := os.Stat(s.path); err != nil { if os.IsNotExist(err) { // File does not exist, create an empty state and write to new file - return s.Write(constants.StateFilePath) + return s.Write() } // Some other error occurred return err } - content, err := os.ReadFile(constants.StateFilePath) + content, err := os.ReadFile(s.path) if err != nil { return err } @@ -169,11 +169,11 @@ func (s *State) Reload() error { } // Write writes the State to the given path -func (s *State) Write(path string) error { +func (s *State) Write() error { data, err := json.Marshal(s) if err != nil { return err } - return os.WriteFile(path, data, 0644) + return os.WriteFile(s.path, data, 0644) } diff --git a/resources/config.toml b/resources/config.toml new file mode 100644 index 0000000..d75a04d --- /dev/null +++ b/resources/config.toml @@ -0,0 +1,3 @@ +dnsservers = "8.8.8.8,8.8.4.4" +checkintervalmin = 1 +verbose = false