this repo has no description
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 config.EnableCompression = false 44 45 config.LogOutput = os.Stdout 46 47 if *secretKey != "" { 48 keyBytes, err := hex.DecodeString(*secretKey) 49 if err != nil { 50 log.Fatalf("Invalid hex key: %v", err) 51 } 52 if len(keyBytes) != 16 && len(keyBytes) != 24 && len(keyBytes) != 32 { 53 log.Fatalf("Key must be 16, 24, or 32 bytes (got %d)", len(keyBytes)) 54 } 55 keyring, err := memberlist.NewKeyring(nil, keyBytes) 56 if err != nil { 57 log.Fatalf("Failed to create keyring: %v", err) 58 } 59 config.Keyring = keyring 60 config.GossipVerifyIncoming = true 61 config.GossipVerifyOutgoing = true 62 log.Printf("Encryption enabled with %d-byte key", len(keyBytes)) 63 } 64 65 list, err := memberlist.Create(config) 66 if err != nil { 67 log.Fatalf("Failed to create memberlist: %v", err) 68 } 69 70 log.Printf("Memberlist started: %s on %s:%d", *name, *bind, *port) 71 72 if *join != "" { 73 log.Printf("Joining cluster via %s", *join) 74 n, err := list.Join([]string{*join}) 75 if err != nil { 76 log.Printf("Failed to join: %v", err) 77 } else { 78 log.Printf("Joined %d nodes", n) 79 } 80 } 81 82 go func() { 83 ticker := time.NewTicker(5 * time.Second) 84 for range ticker.C { 85 members := list.Members() 86 log.Printf("--- Members (%d) ---", len(members)) 87 for _, m := range members { 88 log.Printf(" %s: %s:%d (state=%v)", m.Name, m.Addr, m.Port, m.State) 89 } 90 } 91 }() 92 93 sigCh := make(chan os.Signal, 1) 94 signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) 95 <-sigCh 96 97 log.Println("Shutting down...") 98 if err := list.Leave(time.Second); err != nil { 99 log.Printf("Leave error: %v", err) 100 } 101 if err := list.Shutdown(); err != nil { 102 log.Printf("Shutdown error: %v", err) 103 } 104}