diff --git a/entrypoint/src/cmd/entrypoint/admin.go b/entrypoint/src/cmd/entrypoint/admin.go index 1cce0e2..88353de 100644 --- a/entrypoint/src/cmd/entrypoint/admin.go +++ b/entrypoint/src/cmd/entrypoint/admin.go @@ -84,10 +84,8 @@ var subCmdAdminCreateNetwork = subCmd{ return fmt.Errorf("parsing flags: %w", err) } - env := subCmdCtx.env - if *dumpConfig { - return daemon.CopyDefaultConfig(os.Stdout, env.AppDirPath) + return daemon.CopyDefaultConfig(os.Stdout, envAppDirPath) } if *domain == "" || *subnetStr == "" || *hostName == "" { @@ -111,7 +109,7 @@ var subCmdAdminCreateNetwork = subCmd{ } { - runtimeDirPath := env.RuntimeDirPath + runtimeDirPath := envRuntimeDirPath fmt.Fprintf(os.Stderr, "will use runtime directory %q for temporary state\n", runtimeDirPath) @@ -129,7 +127,7 @@ var subCmdAdminCreateNetwork = subCmd{ }() } - daemonConfig, err := daemon.LoadConfig(env.AppDirPath, *daemonConfigPath) + daemonConfig, err := daemon.LoadConfig(envAppDirPath, *daemonConfigPath) if err != nil { return fmt.Errorf("loading daemon config: %w", err) } @@ -165,16 +163,16 @@ var subCmdAdminCreateNetwork = subCmd{ GarageGlobalBucketS3APICredentials: garage.NewS3APICredentials(), } - if hostBootstrap, err = mergeDaemonConfigIntoBootstrap(env, hostBootstrap, daemonConfig); err != nil { + if hostBootstrap, err = mergeDaemonConfigIntoBootstrap(hostBootstrap, daemonConfig); err != nil { return fmt.Errorf("merging daemon config into bootstrap data: %w", err) } - nebulaPmuxProcConfig, err := nebulaPmuxProcConfig(env, hostBootstrap, daemonConfig) + nebulaPmuxProcConfig, err := nebulaPmuxProcConfig(hostBootstrap, daemonConfig) if err != nil { return fmt.Errorf("generating nebula config: %w", err) } - garagePmuxProcConfigs, err := garagePmuxProcConfigs(env, hostBootstrap, daemonConfig) + garagePmuxProcConfigs, err := garagePmuxProcConfigs(hostBootstrap, daemonConfig) if err != nil { return fmt.Errorf("generating garage configs: %w", err) } @@ -188,7 +186,7 @@ var subCmdAdminCreateNetwork = subCmd{ ), } - ctx, cancel := context.WithCancel(env.Context) + ctx, cancel := context.WithCancel(subCmdCtx.ctx) pmuxDoneCh := make(chan struct{}) fmt.Fprintln(os.Stderr, "starting child processes") @@ -269,9 +267,7 @@ var subCmdAdminMakeBootstrap = subCmd{ return errors.New("--name and --admin-path are required") } - env := subCmdCtx.env - - hostBootstrap, err := loadHostBootstrap(env.DataDirPath) + hostBootstrap, err := loadHostBootstrap() if err != nil { return fmt.Errorf("loading host bootstrap: %w", err) } @@ -287,7 +283,7 @@ var subCmdAdminMakeBootstrap = subCmd{ // command for this host has been run recently then it might not have // made it into the bootstrap file yet, and so won't be in // `hostBootstrap`. - hosts, err := bootstrap.GetGarageBootstrapHosts(env.Context, client) + hosts, err := bootstrap.GetGarageBootstrapHosts(subCmdCtx.ctx, client) if err != nil { return fmt.Errorf("retrieving host info from garage: %w", err) } diff --git a/entrypoint/src/cmd/entrypoint/bootstrap_util.go b/entrypoint/src/cmd/entrypoint/bootstrap_util.go index 7092cf4..cf1381a 100644 --- a/entrypoint/src/cmd/entrypoint/bootstrap_util.go +++ b/entrypoint/src/cmd/entrypoint/bootstrap_util.go @@ -9,9 +9,9 @@ import ( "path/filepath" ) -func loadHostBootstrap(dataDirPath string) (bootstrap.Bootstrap, error) { +func loadHostBootstrap() (bootstrap.Bootstrap, error) { - dataDirPath = bootstrap.DataDirPath(dataDirPath) + dataDirPath := bootstrap.DataDirPath(envDataDirPath) hostBootstrap, err := bootstrap.FromFile(dataDirPath) if errors.Is(err, fs.ErrNotExist) { @@ -24,9 +24,9 @@ func loadHostBootstrap(dataDirPath string) (bootstrap.Bootstrap, error) { return hostBootstrap, nil } -func writeBootstrapToDataDir(dataDirPath string, hostBootstrap bootstrap.Bootstrap) error { +func writeBootstrapToDataDir(hostBootstrap bootstrap.Bootstrap) error { - path := bootstrap.DataDirPath(dataDirPath) + path := bootstrap.DataDirPath(envDataDirPath) dirPath := filepath.Dir(path) if err := os.MkdirAll(dirPath, 0700); err != nil { diff --git a/entrypoint/src/cmd/entrypoint/daemon.go b/entrypoint/src/cmd/entrypoint/daemon.go index 0ddc382..fe62ef3 100644 --- a/entrypoint/src/cmd/entrypoint/daemon.go +++ b/entrypoint/src/cmd/entrypoint/daemon.go @@ -41,14 +41,14 @@ import ( // the new bootstrap file is different than the existing one, the existing one // is overwritten and true is returned. func reloadBootstrap( - env crypticnet.Env, + ctx context.Context, hostBootstrap bootstrap.Bootstrap, s3Client garage.S3APIClient, ) ( bootstrap.Bootstrap, bool, error, ) { - newHosts, err := bootstrap.GetGarageBootstrapHosts(env.Context, s3Client) + newHosts, err := bootstrap.GetGarageBootstrapHosts(ctx, s3Client) if err != nil { return bootstrap.Bootstrap{}, false, fmt.Errorf("getting hosts from garage: %w", err) } @@ -69,7 +69,7 @@ func reloadBootstrap( newHostBootstrap := hostBootstrap.WithHosts(newHosts) - if err := writeBootstrapToDataDir(env.DataDirPath, newHostBootstrap); err != nil { + if err := writeBootstrapToDataDir(newHostBootstrap); err != nil { return bootstrap.Bootstrap{}, false, fmt.Errorf("writing new bootstrap.tgz to data dir: %w", err) } @@ -81,7 +81,7 @@ func reloadBootstrap( // until the spawned pmux has returned, and returns a copy of hostBootstrap with // updated boostrap info. func runDaemonPmuxOnce( - env crypticnet.Env, + ctx context.Context, hostBootstrap bootstrap.Bootstrap, daemonConfig daemon.Config, ) ( @@ -96,17 +96,17 @@ func runDaemonPmuxOnce( // endpoint. s3Client := hostBootstrap.GlobalBucketS3APIClient() - nebulaPmuxProcConfig, err := nebulaPmuxProcConfig(env, hostBootstrap, daemonConfig) + nebulaPmuxProcConfig, err := nebulaPmuxProcConfig(hostBootstrap, daemonConfig) if err != nil { return bootstrap.Bootstrap{}, fmt.Errorf("generating nebula config: %w", err) } - dnsmasqPmuxProcConfig, err := dnsmasqPmuxProcConfig(env, hostBootstrap, daemonConfig) + dnsmasqPmuxProcConfig, err := dnsmasqPmuxProcConfig(hostBootstrap, daemonConfig) if err != nil { return bootstrap.Bootstrap{}, fmt.Errorf("generating dnsmasq config: %w", err) } - garagePmuxProcConfigs, err := garagePmuxProcConfigs(env, hostBootstrap, daemonConfig) + garagePmuxProcConfigs, err := garagePmuxProcConfigs(hostBootstrap, daemonConfig) if err != nil { return bootstrap.Bootstrap{}, fmt.Errorf("generating garage children configs: %w", err) } @@ -121,12 +121,12 @@ func runDaemonPmuxOnce( ), } - doneCh := env.Context.Done() + doneCh := ctx.Done() var wg sync.WaitGroup defer wg.Wait() - ctx, cancel := context.WithCancel(env.Context) + ctx, cancel := context.WithCancel(ctx) defer cancel() wg.Add(1) @@ -184,7 +184,7 @@ func runDaemonPmuxOnce( select { case <-doneCh: - return bootstrap.Bootstrap{}, env.Context.Err() + return bootstrap.Bootstrap{}, ctx.Err() case <-ticker.C: @@ -195,7 +195,7 @@ func runDaemonPmuxOnce( err error ) - if hostBootstrap, changed, err = reloadBootstrap(env, hostBootstrap, s3Client); err != nil { + if hostBootstrap, changed, err = reloadBootstrap(ctx, hostBootstrap, s3Client); err != nil { return bootstrap.Bootstrap{}, fmt.Errorf("reloading bootstrap: %w", err) } else if changed { @@ -232,13 +232,11 @@ var subCmdDaemon = subCmd{ return fmt.Errorf("parsing flags: %w", err) } - env := subCmdCtx.env - if *dumpConfig { - return daemon.CopyDefaultConfig(os.Stdout, env.AppDirPath) + return daemon.CopyDefaultConfig(os.Stdout, envAppDirPath) } - runtimeDirPath := env.RuntimeDirPath + runtimeDirPath := envRuntimeDirPath fmt.Fprintf(os.Stderr, "will use runtime directory %q for temporary state\n", runtimeDirPath) @@ -260,8 +258,8 @@ var subCmdDaemon = subCmd{ }() var ( - bootstrapDataDirPath = bootstrap.DataDirPath(env.DataDirPath) - bootstrapAppDirPath = bootstrap.AppDirPath(env.AppDirPath) + bootstrapDataDirPath = bootstrap.DataDirPath(envDataDirPath) + bootstrapAppDirPath = bootstrap.AppDirPath(envAppDirPath) hostBootstrapPath string hostBootstrap bootstrap.Bootstrap @@ -302,12 +300,12 @@ var subCmdDaemon = subCmd{ // If the bootstrap file is not being stored in the data dir, copy // it there, so it can be loaded from there next time. - if err := writeBootstrapToDataDir(env.DataDirPath, hostBootstrap); err != nil { + if err := writeBootstrapToDataDir(hostBootstrap); err != nil { return fmt.Errorf("writing bootstrap.tgz to data dir: %w", err) } } - daemonConfig, err := daemon.LoadConfig(env.AppDirPath, *daemonConfigPath) + daemonConfig, err := daemon.LoadConfig(envAppDirPath, *daemonConfigPath) if err != nil { return fmt.Errorf("loading daemon config: %w", err) } @@ -317,13 +315,13 @@ var subCmdDaemon = subCmd{ // up-to-date possible bootstrap. This updated bootstrap will later get // updated in garage using bootstrap.PutGarageBoostrapHost, so other // hosts will see it as well. - if hostBootstrap, err = mergeDaemonConfigIntoBootstrap(env, hostBootstrap, daemonConfig); err != nil { + if hostBootstrap, err = mergeDaemonConfigIntoBootstrap(hostBootstrap, daemonConfig); err != nil { return fmt.Errorf("merging daemon config into bootstrap data: %w", err) } for { - hostBootstrap, err = runDaemonPmuxOnce(env, hostBootstrap, daemonConfig) + hostBootstrap, err = runDaemonPmuxOnce(subCmdCtx.ctx, hostBootstrap, daemonConfig) if errors.Is(err, context.Canceled) { return nil diff --git a/entrypoint/src/cmd/entrypoint/daemon_util.go b/entrypoint/src/cmd/entrypoint/daemon_util.go index dd5d853..30f42c9 100644 --- a/entrypoint/src/cmd/entrypoint/daemon_util.go +++ b/entrypoint/src/cmd/entrypoint/daemon_util.go @@ -2,7 +2,6 @@ package main import ( "context" - crypticnet "cryptic-net" "cryptic-net/bootstrap" "cryptic-net/daemon" "fmt" @@ -10,7 +9,6 @@ import ( ) func mergeDaemonConfigIntoBootstrap( - env crypticnet.Env, hostBootstrap bootstrap.Bootstrap, daemonConfig daemon.Config, ) ( @@ -36,7 +34,7 @@ func mergeDaemonConfigIntoBootstrap( hostBootstrap.Hosts[host.Name] = host - if err := writeBootstrapToDataDir(env.DataDirPath, hostBootstrap); err != nil { + if err := writeBootstrapToDataDir(hostBootstrap); err != nil { return bootstrap.Bootstrap{}, fmt.Errorf("writing bootstrap file: %w", err) } diff --git a/entrypoint/src/cmd/entrypoint/dnsmasq_util.go b/entrypoint/src/cmd/entrypoint/dnsmasq_util.go index feb7422..54fd279 100644 --- a/entrypoint/src/cmd/entrypoint/dnsmasq_util.go +++ b/entrypoint/src/cmd/entrypoint/dnsmasq_util.go @@ -1,7 +1,6 @@ package main import ( - crypticnet "cryptic-net" "cryptic-net/bootstrap" "cryptic-net/daemon" "cryptic-net/dnsmasq" @@ -13,14 +12,13 @@ import ( ) func dnsmasqPmuxProcConfig( - env crypticnet.Env, hostBootstrap bootstrap.Bootstrap, daemonConfig daemon.Config, ) ( pmuxlib.ProcessConfig, error, ) { - confPath := filepath.Join(env.RuntimeDirPath, "dnsmasq.conf") + confPath := filepath.Join(envRuntimeDirPath, "dnsmasq.conf") hostsSlice := make([]bootstrap.Host, 0, len(hostBootstrap.Hosts)) for _, host := range hostBootstrap.Hosts { diff --git a/entrypoint/src/cmd/entrypoint/garage.go b/entrypoint/src/cmd/entrypoint/garage.go index ff4de28..cd63a87 100644 --- a/entrypoint/src/cmd/entrypoint/garage.go +++ b/entrypoint/src/cmd/entrypoint/garage.go @@ -28,9 +28,7 @@ var subCmdGarageMC = subCmd{ return fmt.Errorf("parsing flags: %w", err) } - env := subCmdCtx.env - - hostBootstrap, err := loadHostBootstrap(env.DataDirPath) + hostBootstrap, err := loadHostBootstrap() if err != nil { return fmt.Errorf("loading host bootstrap: %w", err) } @@ -88,9 +86,7 @@ var subCmdGarageCLI = subCmd{ checkLock: true, do: func(subCmdCtx subCmdCtx) error { - env := subCmdCtx.env - - hostBootstrap, err := loadHostBootstrap(env.DataDirPath) + hostBootstrap, err := loadHostBootstrap() if err != nil { return fmt.Errorf("loading host bootstrap: %w", err) } diff --git a/entrypoint/src/cmd/entrypoint/garage_util.go b/entrypoint/src/cmd/entrypoint/garage_util.go index e2fa448..5d44e01 100644 --- a/entrypoint/src/cmd/entrypoint/garage_util.go +++ b/entrypoint/src/cmd/entrypoint/garage_util.go @@ -2,7 +2,6 @@ package main import ( "context" - crypticnet "cryptic-net" "cryptic-net/bootstrap" "cryptic-net/daemon" "cryptic-net/garage" @@ -68,7 +67,6 @@ func waitForGarageAndNebula( } func garageWriteChildConfig( - env crypticnet.Env, hostBootstrap bootstrap.Bootstrap, alloc daemon.ConfigStorageAllocation, ) ( @@ -100,7 +98,7 @@ func garageWriteChildConfig( } garageTomlPath := filepath.Join( - env.RuntimeDirPath, fmt.Sprintf("garage-%d.toml", alloc.RPCPort), + envRuntimeDirPath, fmt.Sprintf("garage-%d.toml", alloc.RPCPort), ) err := garage.WriteGarageTomlFile(garageTomlPath, garage.GarageTomlData{ @@ -125,7 +123,6 @@ func garageWriteChildConfig( } func garagePmuxProcConfigs( - env crypticnet.Env, hostBootstrap bootstrap.Bootstrap, daemonConfig daemon.Config, ) ( @@ -136,7 +133,7 @@ func garagePmuxProcConfigs( for _, alloc := range daemonConfig.Storage.Allocations { - childConfigPath, err := garageWriteChildConfig(env, hostBootstrap, alloc) + childConfigPath, err := garageWriteChildConfig(hostBootstrap, alloc) if err != nil { return nil, fmt.Errorf("writing child config file for alloc %+v: %w", alloc, err) diff --git a/entrypoint/src/cmd/entrypoint/hosts.go b/entrypoint/src/cmd/entrypoint/hosts.go index 65c1c19..98d4571 100644 --- a/entrypoint/src/cmd/entrypoint/hosts.go +++ b/entrypoint/src/cmd/entrypoint/hosts.go @@ -59,9 +59,7 @@ var subCmdHostsAdd = subCmd{ // TODO validate that the IP is in the correct CIDR - env := subCmdCtx.env - - hostBootstrap, err := loadHostBootstrap(env.DataDirPath) + hostBootstrap, err := loadHostBootstrap() if err != nil { return fmt.Errorf("loading host bootstrap: %w", err) } @@ -75,7 +73,7 @@ var subCmdHostsAdd = subCmd{ }, } - return bootstrap.PutGarageBoostrapHost(env.Context, client, host) + return bootstrap.PutGarageBoostrapHost(subCmdCtx.ctx, client, host) }, } @@ -85,16 +83,14 @@ var subCmdHostsList = subCmd{ checkLock: true, do: func(subCmdCtx subCmdCtx) error { - env := subCmdCtx.env - - hostBootstrap, err := loadHostBootstrap(env.DataDirPath) + hostBootstrap, err := loadHostBootstrap() if err != nil { return fmt.Errorf("loading host bootstrap: %w", err) } client := hostBootstrap.GlobalBucketS3APIClient() - hostsMap, err := bootstrap.GetGarageBootstrapHosts(env.Context, client) + hostsMap, err := bootstrap.GetGarageBootstrapHosts(subCmdCtx.ctx, client) if err != nil { return fmt.Errorf("retrieving hosts from garage: %w", err) } @@ -131,16 +127,14 @@ var subCmdHostsDelete = subCmd{ return errors.New("--name is required") } - env := subCmdCtx.env - - hostBootstrap, err := loadHostBootstrap(env.DataDirPath) + hostBootstrap, err := loadHostBootstrap() if err != nil { return fmt.Errorf("loading host bootstrap: %w", err) } client := hostBootstrap.GlobalBucketS3APIClient() - return bootstrap.RemoveGarageBootstrapHost(env.Context, client, *name) + return bootstrap.RemoveGarageBootstrapHost(subCmdCtx.ctx, client, *name) }, } diff --git a/entrypoint/src/cmd/entrypoint/main.go b/entrypoint/src/cmd/entrypoint/main.go index 0d73e67..f6eae40 100644 --- a/entrypoint/src/cmd/entrypoint/main.go +++ b/entrypoint/src/cmd/entrypoint/main.go @@ -1,9 +1,14 @@ package main import ( + "context" + "fmt" "os" + "os/signal" + "path/filepath" + "syscall" - crypticnet "cryptic-net" + "github.com/adrg/xdg" ) // The purpose of this binary is to act as the entrypoint of the cryptic-net @@ -11,13 +16,42 @@ import ( // then passes execution along to an appropriate binary housed in AppDir/bin // (usually a bash script, which is more versatile than a go program). +func getAppDirPath() string { + appDirPath := os.Getenv("APPDIR") + if appDirPath == "" { + appDirPath = "." + } + return appDirPath +} + +var ( + envAppDirPath = getAppDirPath() + envRuntimeDirPath = filepath.Join(xdg.RuntimeDir, "cryptic-net") + envDataDirPath = filepath.Join(xdg.DataHome, "cryptic-net") +) + func main() { - env := crypticnet.NewEnv() + ctx, cancel := context.WithCancel(context.Background()) + + signalCh := make(chan os.Signal, 2) + signal.Notify(signalCh, syscall.SIGINT, syscall.SIGTERM) + + go func() { + sig := <-signalCh + cancel() + fmt.Fprintf(os.Stderr, "got signal %v, will exit gracefully\n", sig) + + sig = <-signalCh + fmt.Fprintf(os.Stderr, "second interrupt signal %v received, force quitting, there may be zombie children left behind, good luck!\n", sig) + + os.Stderr.Sync() + os.Exit(1) + }() err := subCmdCtx{ args: os.Args[1:], - env: env, + ctx: ctx, }.doSubCmd( subCmdAdmin, subCmdDaemon, diff --git a/entrypoint/src/cmd/entrypoint/nebula_util.go b/entrypoint/src/cmd/entrypoint/nebula_util.go index dd195e5..ceace33 100644 --- a/entrypoint/src/cmd/entrypoint/nebula_util.go +++ b/entrypoint/src/cmd/entrypoint/nebula_util.go @@ -2,7 +2,6 @@ package main import ( "context" - crypticnet "cryptic-net" "cryptic-net/bootstrap" "cryptic-net/daemon" "cryptic-net/yamlutil" @@ -36,7 +35,6 @@ func waitForNebula(ctx context.Context, hostBootstrap bootstrap.Bootstrap) error } func nebulaPmuxProcConfig( - env crypticnet.Env, hostBootstrap bootstrap.Bootstrap, daemonConfig daemon.Config, ) ( @@ -105,7 +103,7 @@ func nebulaPmuxProcConfig( } } - nebulaYmlPath := filepath.Join(env.RuntimeDirPath, "nebula.yml") + nebulaYmlPath := filepath.Join(envRuntimeDirPath, "nebula.yml") if err := yamlutil.WriteYamlFile(config, nebulaYmlPath); err != nil { return pmuxlib.ProcessConfig{}, fmt.Errorf("writing nebula.yml to %q: %w", nebulaYmlPath, err) diff --git a/entrypoint/src/cmd/entrypoint/sub_cmd.go b/entrypoint/src/cmd/entrypoint/sub_cmd.go index cf4f21f..fe5df12 100644 --- a/entrypoint/src/cmd/entrypoint/sub_cmd.go +++ b/entrypoint/src/cmd/entrypoint/sub_cmd.go @@ -1,6 +1,7 @@ package main import ( + "context" crypticnet "cryptic-net" "fmt" "os" @@ -14,7 +15,8 @@ type subCmdCtx struct { subCmd subCmd // the subCmd itself args []string // command-line arguments, excluding the subCmd itself. subCmdNames []string // names of subCmds so far, including this one - env crypticnet.Env + + ctx context.Context } type subCmd struct { @@ -99,7 +101,7 @@ func (ctx subCmdCtx) doSubCmd(subCmds ...subCmd) error { if subCmd.checkLock { - err := crypticnet.NewProcLock(ctx.env.RuntimeDirPath).AssertLock() + err := crypticnet.NewProcLock(envRuntimeDirPath).AssertLock() if err != nil { return fmt.Errorf("checking lock file: %w", err) @@ -110,7 +112,7 @@ func (ctx subCmdCtx) doSubCmd(subCmds ...subCmd) error { subCmd: subCmd, args: args, subCmdNames: append(ctx.subCmdNames, subCmdName), - env: ctx.env, + ctx: ctx.ctx, }) if err != nil { diff --git a/entrypoint/src/cmd/entrypoint/version.go b/entrypoint/src/cmd/entrypoint/version.go index 1bab4e6..039d02d 100644 --- a/entrypoint/src/cmd/entrypoint/version.go +++ b/entrypoint/src/cmd/entrypoint/version.go @@ -11,7 +11,7 @@ var subCmdVersion = subCmd{ descr: "Dumps version and build info to stdout", do: func(subCmdCtx subCmdCtx) error { - versionPath := filepath.Join(subCmdCtx.env.AppDirPath, "share/version") + versionPath := filepath.Join(envAppDirPath, "share/version") version, err := os.ReadFile(versionPath) diff --git a/entrypoint/src/env.go b/entrypoint/src/env.go deleted file mode 100644 index 731d844..0000000 --- a/entrypoint/src/env.go +++ /dev/null @@ -1,63 +0,0 @@ -package crypticnet - -import ( - "context" - "fmt" - "os" - "os/signal" - "path/filepath" - "syscall" - - "github.com/adrg/xdg" -) - -// Env contains the values of environment variables, as well as other entities -// which are useful across all processes. -type Env struct { - Context context.Context - - AppDirPath string - RuntimeDirPath string - DataDirPath string -} - -func getAppDirPath() string { - appDirPath := os.Getenv("APPDIR") - if appDirPath == "" { - appDirPath = "." - } - return appDirPath -} - -// NewEnv calculates an Env instance based on the APPDIR and XDG envvars. -func NewEnv() Env { - - runtimeDirPath := filepath.Join(xdg.RuntimeDir, "cryptic-net") - appDirPath := getAppDirPath() - - env := Env{ - AppDirPath: appDirPath, - RuntimeDirPath: runtimeDirPath, - DataDirPath: filepath.Join(xdg.DataHome, "cryptic-net"), - } - - var cancel context.CancelFunc - env.Context, cancel = context.WithCancel(context.Background()) - - signalCh := make(chan os.Signal, 2) - signal.Notify(signalCh, syscall.SIGINT, syscall.SIGTERM) - - go func() { - sig := <-signalCh - cancel() - fmt.Fprintf(os.Stderr, "got signal %v, will exit gracefully\n", sig) - - sig = <-signalCh - fmt.Fprintf(os.Stderr, "second interrupt signal %v received, force quitting, there may be zombie children left behind, good luck!\n", sig) - - os.Stderr.Sync() - os.Exit(1) - }() - - return env -}