Skip to content

Commit 4781f16

Browse files
committed
chore: quick update fix/version at 2025-09-17 22:36:02
1 parent 7c14e8e commit 4781f16

File tree

3 files changed

+457
-0
lines changed

3 files changed

+457
-0
lines changed

metaflags/example/main.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"net/http"
7+
"strings"
8+
"time"
9+
10+
"github.com/pubgo/funk/metaflags"
11+
)
12+
13+
var startTime = time.Now()
14+
15+
func main() {
16+
status := metaflags.String("app_status", "ok", "Current app status")
17+
replicas := metaflags.Int("replicas", 1, "Number of replicas")
18+
timeout := metaflags.Duration("timeout", 5*time.Second, "Request timeout")
19+
features := metaflags.StringSlice("features", []string{"auth"}, "Enabled features")
20+
labels := metaflags.StringMap("labels", map[string]string{"env": "dev"}, "Node labels")
21+
22+
// 模拟更新
23+
go func() {
24+
time.Sleep(2 * time.Second)
25+
status.Set("degraded")
26+
27+
time.Sleep(2 * time.Second)
28+
replicas.Set(3)
29+
30+
time.Sleep(2 * time.Second)
31+
timeout.Set(10 * time.Second)
32+
33+
time.Sleep(2 * time.Second)
34+
features.Set([]string{"auth", "metrics", "tracing"})
35+
36+
time.Sleep(2 * time.Second)
37+
lbls := labels.Get().(map[string]string)
38+
lbls["updated"] = time.Now().Format("15:04")
39+
labels.Set(lbls)
40+
}()
41+
42+
// HTTP 输出所有元数据
43+
http.HandleFunc("/metadata", func(w http.ResponseWriter, r *http.Request) {
44+
w.Header().Set("Content-Type", "application/json")
45+
fmt.Fprintln(w, "{")
46+
first := true
47+
metaflags.VisitAll(func(e *metaflags.Entry) {
48+
if !first {
49+
fmt.Fprint(w, ",")
50+
}
51+
first = false
52+
fmt.Fprintf(w, "\n %q: %v", e.Name, mustJSON(e.Value.Get()))
53+
})
54+
fmt.Fprintln(w, "\n}")
55+
})
56+
57+
log.Println("Server starting on :8080")
58+
log.Fatal(http.ListenAndServe(":8080", nil))
59+
}
60+
61+
// 简单 JSON 转换(生产环境用 json.Marshal)
62+
func mustJSON(v interface{}) string {
63+
switch val := v.(type) {
64+
case string:
65+
return fmt.Sprintf("%q", val)
66+
case []string:
67+
return fmt.Sprintf("%q", val)
68+
case map[string]string:
69+
var parts []string
70+
for k, v := range val {
71+
parts = append(parts, fmt.Sprintf("%q:%q", k, v))
72+
}
73+
return fmt.Sprintf("{%s}", strings.Join(parts, ","))
74+
default:
75+
return fmt.Sprintf("%v", val)
76+
}
77+
}

metaflags/metaflag.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package metaflags
2+
3+
import (
4+
"github.com/pubgo/funk/assert"
5+
"sync"
6+
)
7+
8+
// Value is the interface to the dynamic value stored in metadata.
9+
type Value interface {
10+
Get() any
11+
Set(value any) error
12+
String() string
13+
Key() string // 返回该值的名称
14+
}
15+
16+
// Entry holds metadata about a registered value
17+
type Entry struct {
18+
Name string
19+
Value Value
20+
Usage string
21+
}
22+
23+
// FlagSet holds a set of metadata values
24+
type FlagSet struct {
25+
m map[string]*Entry
26+
mu sync.RWMutex
27+
}
28+
29+
var defaultSet = NewFlagSet()
30+
31+
func NewFlagSet() *FlagSet { return &FlagSet{m: make(map[string]*Entry)} }
32+
33+
func (f *FlagSet) AddFunc(name string, getter func() any, setter func(val any) error, usage string) Value {
34+
return f.Add(name, &FuncValue{get: getter, set: setter, name: name}, usage)
35+
}
36+
37+
// Add registers a new metadata entry and injects name if supported
38+
func (f *FlagSet) Add(name string, value Value, usage string) Value {
39+
f.mu.Lock()
40+
defer f.mu.Unlock()
41+
42+
assert.If(value == nil, "flag value is nil")
43+
assert.If(name == "", "flag name is empty")
44+
assert.If(f.m[name] != nil, "flag '%s' already registered", name)
45+
46+
f.m[name] = &Entry{
47+
Name: name,
48+
Value: value,
49+
Usage: usage,
50+
}
51+
return value
52+
}
53+
54+
// Lookup returns the Entry for the given name
55+
func (f *FlagSet) Lookup(name string) *Entry {
56+
f.mu.RLock()
57+
defer f.mu.RUnlock()
58+
return f.m[name]
59+
}
60+
61+
// VisitAll calls fn for each Entry
62+
func (f *FlagSet) VisitAll(fn func(*Entry)) {
63+
f.mu.RLock()
64+
defer f.mu.RUnlock()
65+
for _, entry := range f.m {
66+
fn(entry)
67+
}
68+
}
69+
70+
// Default accessors
71+
func Lookup(name string) *Entry { return defaultSet.Lookup(name) }
72+
func VisitAll(fn func(*Entry)) { defaultSet.VisitAll(fn) }
73+
func Add(name string, val Value, u string) Value {
74+
return defaultSet.Add(name, val, u)
75+
}

0 commit comments

Comments
 (0)