this repo has no description
at main 2.6 kB view raw
1package main 2 3import ( 4 "encoding/hex" 5 "flag" 6 "log" 7 "os" 8 "os/signal" 9 "syscall" 10 "time" 11 12 "github.com/hashicorp/memberlist" 13) 14 15type eventDelegate struct{} 16 17func (e *eventDelegate) NotifyJoin(node *memberlist.Node) { 18 log.Printf("[EVENT] Node joined: %s (%s:%d)", node.Name, node.Addr, node.Port) 19} 20 21func (e *eventDelegate) NotifyLeave(node *memberlist.Node) { 22 log.Printf("[EVENT] Node left: %s", node.Name) 23} 24 25func (e *eventDelegate) NotifyUpdate(node *memberlist.Node) { 26 log.Printf("[EVENT] Node updated: %s", node.Name) 27} 28 29func main() { 30 name := flag.String("name", "go-node", "Node name") 31 bind := flag.String("bind", "127.0.0.1", "Bind address") 32 port := flag.Int("port", 7946, "Bind port") 33 join := flag.String("join", "", "Address to join (host:port)") 34 secretKey := flag.String("key", "", "Secret key (hex encoded, 16 bytes for AES-128)") 35 flag.Parse() 36 37 config := memberlist.DefaultLANConfig() 38 config.Name = *name 39 config.BindAddr = *bind 40 config.BindPort = *port 41 config.AdvertisePort = *port 42 config.Events = &eventDelegate{} 43 44 config.LogOutput = os.Stdout 45 46 if *secretKey != "" { 47 keyBytes, err := hex.DecodeString(*secretKey) 48 if err != nil { 49 log.Fatalf("Invalid hex key: %v", err) 50 } 51 if len(keyBytes) != 16 && len(keyBytes) != 24 && len(keyBytes) != 32 { 52 log.Fatalf("Key must be 16, 24, or 32 bytes (got %d)", len(keyBytes)) 53 } 54 keyring, err := memberlist.NewKeyring(nil, keyBytes) 55 if err != nil { 56 log.Fatalf("Failed to create keyring: %v", err) 57 } 58 config.Keyring = keyring 59 config.GossipVerifyIncoming = true 60 config.GossipVerifyOutgoing = true 61 log.Printf("Encryption enabled with %d-byte key", len(keyBytes)) 62 } 63 64 list, err := memberlist.Create(config) 65 if err != nil { 66 log.Fatalf("Failed to create memberlist: %v", err) 67 } 68 69 log.Printf("Memberlist started: %s on %s:%d", *name, *bind, *port) 70 71 if *join != "" { 72 log.Printf("Joining cluster via %s", *join) 73 n, err := list.Join([]string{*join}) 74 if err != nil { 75 log.Printf("Failed to join: %v", err) 76 } else { 77 log.Printf("Joined %d nodes", n) 78 } 79 } 80 81 go func() { 82 ticker := time.NewTicker(5 * time.Second) 83 for range ticker.C { 84 members := list.Members() 85 log.Printf("--- Members (%d) ---", len(members)) 86 for _, m := range members { 87 log.Printf(" %s: %s:%d (state=%v)", m.Name, m.Addr, m.Port, m.State) 88 } 89 } 90 }() 91 92 sigCh := make(chan os.Signal, 1) 93 signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) 94 <-sigCh 95 96 log.Println("Shutting down...") 97 if err := list.Leave(time.Second); err != nil { 98 log.Printf("Leave error: %v", err) 99 } 100 if err := list.Shutdown(); err != nil { 101 log.Printf("Shutdown error: %v", err) 102 } 103}