-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathappx.go
114 lines (99 loc) · 2.39 KB
/
appx.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package appx
import (
"context"
"fmt"
"os"
"os/signal"
"runtime/debug"
"sync"
"syscall"
"time"
)
var startTime = time.Now()
// Context of the application listening SIGINT and SIGTERM signals.
func Context() context.Context {
ctx, _ := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
return ctx
}
// Uptime of the application.
func Uptime() time.Duration {
return time.Since(startTime)
}
var (
appEnv string
appEnvOnce sync.Once
)
// Env where application is running. Can be set via SetEnv func.
func Env() string { return appEnv }
// SetEnv for the application from environment variable or a default.
// Can be called once, all next calls panics.
// Example:
//
// appx.SetEnv("ENV", "dev") // set from ENV or set default "dev"
// appx.SetEnv("ENV", "") // set from ENV or leave unset
// appx.SetEnv("", "dev") // set "dev" directly
//
// This function should be called at the start of the application.
func SetEnv(env, def string) string {
if appEnv != "" {
panic("appx: SetEnv called twice")
}
appEnvOnce.Do(func() {
v := os.Getenv(env)
if v == "" {
v = def
}
appEnv = v
})
return appEnv
}
// OnSignal run fn.
// Function is async, context is used to close underlying goroutine.
func OnSignal(ctx context.Context, sig os.Signal, fn func(ctx context.Context)) {
ch := newChan(sig)
go func() {
for {
select {
case <-ch:
fn(ctx)
case <-ctx.Done():
return
}
}
}()
}
// newChan returns a channel triggered on every sig.
func newChan(sig os.Signal) <-chan os.Signal {
ch := make(chan os.Signal, 1)
signal.Notify(ch, sig)
return ch
}
// BuildInfo of the app (if -buildvcs flag provided).
func BuildInfo() (revision string, at time.Time, isModified, ok bool) {
info, ok := debug.ReadBuildInfo()
if !ok {
return "", time.Time{}, false, false
}
for _, setting := range info.Settings {
switch setting.Key {
case "vcs.revision":
revision = setting.Value
case "vcs.time":
at, _ = time.Parse(time.RFC3339, setting.Value)
case "vcs.modified":
isModified = setting.Value == "true"
}
}
return revision, at, isModified, true
}
// SelfSignal sends signal to the current process.
func SelfSignal(sig os.Signal) error {
proc, err := os.FindProcess(os.Getpid())
if err != nil {
return fmt.Errorf("unable to find own pid: %w", err)
}
if err := proc.Signal(sig); err != nil {
return fmt.Errorf("signal: %w", err)
}
return nil
}