func main() { server := gomsg.NewServer() server.SetTimeout(time.Second) server.Listen(":7777") cli := gomsg.NewClient() cli.Handle("REVERSE", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== processing (1):", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[1]=%s", reverse(m)), nil }) cli.Connect("localhost:7777") cli2 := gomsg.NewClient() cli2.Handle("REVERSE", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== processing (2):", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[2]=%s", reverse(m)), nil }) cli2.Connect("localhost:7777") time.Sleep(time.Millisecond * 100) // Warning: when requesting many in a server, the last response (end mark) will have a null connection server.RequestAll("REVERSE", "hello", func(ctx gomsg.Response, r string) { fmt.Println("===> reply:", r, ", last?", ctx.Last()) }, time.Second) time.Sleep(time.Second * 2) fmt.Println("I: close...") cli.Destroy() time.Sleep(time.Second * 5) }
func main() { server := gomsg.NewServer() server.Listen(":7777") ungrouped := 0 cli := gomsg.NewClient() cli.Handle("HELLO", func(m string) { fmt.Println("<=== [0] processing:", m) ungrouped++ }) <-cli.Connect("localhost:7777") group1 := 0 // Group HA subscriber cli1 := gomsg.NewClient() cli1.SetGroupId("HA") cli1.Handle("HELLO", func(m string) { fmt.Println("<=== [1] processing:", m) group1++ }) <-cli1.Connect("localhost:7777") // Group HA subscriber group2 := 0 cli2 := gomsg.NewClient() cli2.SetGroupId("HA") cli2.Handle("HELLO", func(m string) { fmt.Println("<=== [2] processing:", m) group2++ }) <-cli2.Connect("localhost:7777") // Only one element of the group HA will process each message, alternately (round robin). server.Publish("HELLO", "one") wait() server.Publish("HELLO", "two") wait() server.Publish("HELLO", "three") wait() server.Publish("HELLO", "four") wait() if ungrouped != 4 { fmt.Println("ERROR: RECEIVED", ungrouped, "UNGROUPED EVENTS. EXPECTED 4.") } if group1 != 2 { fmt.Println("ERROR: RECEIVED", group1, "GROUP EVENTS. EXPECTED 2.") } if group2 != 2 { fmt.Println("ERROR: RECEIVED", group2, "GROUP EVENTS. EXPECTED 2.") } wait() server.Destroy() wait() }
func main() { server := gomsg.NewServer() server.Listen(SERVER_PORT_1) defer server.Destroy() // client #1 var received1 = 0 cli1 := gomsg.NewClient() cli1.Handle(CONSUMER, func(m string) { fmt.Println("<<< client #1: received", m) if m == MESSAGE { received1++ } }) cli1.Connect(SERVER_1) defer cli1.Destroy() // client #2 var received2 = 0 cli2 := gomsg.NewClient() cli2.Handle(CONSUMER, func(m string) { fmt.Println("<<< client #2: received", m) if m == MESSAGE { received2++ } }) cli2.Connect(SERVER_1) defer cli2.Destroy() // give time to connect wait() // only one client will receive the message e := <-server.Push(CONSUMER, MESSAGE) if e != nil { fmt.Printf("Error: %s\n", e) } // a different client from before (round-robin) // will receive the message e = <-server.Push(CONSUMER, MESSAGE) if e != nil { fmt.Printf("Error: %s\n", e) } if received1 != 1 { fmt.Printf("Expected '%v', got '%v'\n", 1, received1) } if received2 != 1 { fmt.Printf("Expected '%v', got '%v'\n", 1, received2) } }
func main() { // routing requests between server 1 and server 2 server1 := gomsg.NewServer() server1.SetTimeout(time.Second) server1.Listen(":7777") server2 := gomsg.NewServer() server2.SetTimeout(time.Second) server2.Listen(":7778") // all (*) messages arriving to server 1 are routed to server 2 gomsg.Route("*", server1, server2, time.Second, func(ctx *gomsg.Request) bool { fmt.Println("===>routing incoming msg:", string(ctx.Request())) return true }, nil) // client 1 connects to server 1 cli := gomsg.NewClient() cli.Connect("localhost:7777") cli2 := gomsg.NewClient() cli2.Handle("HELLO", func(ctx *gomsg.Request, m string) (string, error) { if m != MESSAGE { fmt.Printf("###> EXPECTED '%s'. RECEIVED '%s'.\n", MESSAGE, m) } fmt.Println("<=== processing:", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("Hello %s", m), nil }) // client 2 connects to server 2 cli2.Connect("localhost:7778") var err error /* err = <-cli.Push("XPTO", "PUSH: One") if err != nil { fmt.Println("W: error:", err) } */ err = <-cli.Request("HELLO", MESSAGE, func(ctx gomsg.Response, r string, e error) { if r != REPLY { fmt.Printf("###> EXPECTED '%s'. RECEIVED '%s'.\n", REPLY, r) } fmt.Println("=================> reply:", r, e, "from", ctx.Connection().RemoteAddr()) }) if err != nil { fmt.Println("===> error:", err) } time.Sleep(time.Second * 3) cli.Destroy() time.Sleep(time.Millisecond * 100) }
func main() { server := gomsg.NewServer() server.Listen(":7777") cli := gomsg.NewClient() cli.Connect("localhost:7777") // this late server handler must propagate to the client server.Handle("XPTO", func(m string) { fmt.Println("<=== handling pull:", m) }) time.Sleep(time.Millisecond * 100) e := <-cli.Publish("XPTO", "teste") if e != nil { fmt.Println("===> XPTO error:", e) } // this late client handler must propagate to the server cli.Handle("SUB", func(m string) { fmt.Println("<=== handling pub-sub:", m) }) time.Sleep(time.Millisecond * 100) e = <-server.Publish("SUB", "teste") if e != nil { fmt.Println("===> SUB error:", e) } time.Sleep(time.Millisecond * 100) }
func (node *Node) connectPeer(peerAddr string) error { node.mu.Lock() defer node.mu.Unlock() if node.peers[peerAddr] == nil { cli := gomsg.NewClient().SetCodec(node.Codec) cli.OnConnect = func(w *gomsg.Wired) { node.Put(w.Conn(), w.Wire()) } cli.OnClose = func(c net.Conn) { node.Kill(c) node.mu.Lock() defer node.mu.Unlock() // remove from connected peers delete(node.peers, peerAddr) } // doesn't try to reconnect cli.SetReconnectInterval(0) // wait for the connection to establish var err = <-cli.Connect(peerAddr) if err != nil { return err } node.peers[peerAddr] = cli } return nil }
func main() { cli := gomsg.NewClient().Connect("localhost:7777") time.Sleep(time.Millisecond * 100) // THE SERVER SHOWS UP AFTER THE CLIENT server := gomsg.NewServer() server.Handle("XPTO", func(m string) { fmt.Println("<=== handling pull:", m) }) server.Listen(":7777") time.Sleep(time.Second) e := <-cli.Publish("XPTO", "teste") if e != nil { fmt.Println("===> error:", e) } /* cli.Handle("SUB", func(m string) { fmt.Println("<=== handling pub-sub:", m) }) time.Sleep(time.Millisecond * 100) <-server.Publish("SUB", "teste") */ time.Sleep(time.Second) }
func NewBStarClient(primary string, backup string) BStarClient { this := BStarClient{ client: gomsg.NewClient().SetCodec(codec), servers: []string{primary, backup}, } this.client.SetTimeout(time.Second) this.client.Connect(primary) return this }
func NewPeer(dirAddr string, bindAddr string, codec gomsg.Codec) *Peer { this := &Peer{ codec: codec, peers: NewPeers(), } this.local = gomsg.NewServer() this.local.SetTimeout(time.Second) this.local.SetCodec(codec) this.local.Listen(bindAddr) this.dir = gomsg.NewClient().SetCodec(codec) this.dir.SetTimeout(time.Second) this.dir.OnConnect = func(w *gomsg.Wired) { this.dir.Handle("NEW", func(peerAddr string) { if peerAddr != this.self { fmt.Println("====>", bindAddr, ": new peer at", peerAddr) cli := gomsg.NewClient().SetCodec(codec) cli.Connect(peerAddr) this.peers.Put(peerAddr, cli) } }) this.dir.Handle("DROP", func(peerAddr string) { this.peers.Remove(peerAddr) }) port := this.local.Port() <-this.dir.Request("DIR", nil, func(ctx gomsg.Response, addrs []string) { this.self = fmt.Sprint(ctx.Connection().LocalAddr().(*net.TCPAddr).IP, ":", port) for _, v := range addrs { cli := gomsg.NewClient().SetCodec(this.codec) cli.Connect(v) this.peers.Put(v, cli) } }) this.dir.Push("READY", port) } this.dir.Connect(dirAddr) return this }
// This is our main task. First we bind/connect our sockets with our // peer and make sure we will get state messages correctly. We use // three sockets; one to publish state, one to subscribe to state, and // one for client requests/replies: func NewBStar(primary bool, frontentAddr string, stateLocalAddr string, stateRemoteAddr string) *BStar { this := &BStar{} if primary { fmt.Println("I: Primary active, waiting for backup (passive)") this.state = STATE_PRIMARY } else { fmt.Println("I: Backup passive, waiting for primary (active)") this.state = STATE_BACKUP } this.quit = make(chan bool, 1) this.statepub = gomsg.NewClient().SetCodec(codec) this.statesub = gomsg.NewServer() this.statesub.SetCodec(codec) this.statesub.Handle("STATE", func(ctx *gomsg.Request) { state, _ := ctx.Reader().ReadUI8() // Have state from our peer, execute as event if this.stateMachine(Event(state)) { this.quit <- true // Error, so exit } else { this.updatePeerExpiry() } }) this.frontend = gomsg.NewServer() this.frontend.SetCodec(codec) this.frontend.Handle("*", func(ctx *gomsg.Request) { // Have a client request ok := !this.stateMachine(CLIENT_REQUEST) if ok { this.frontendHandler(this, ctx) } else { // rejects request ctx.Terminate() } }) this.stateRemoteAddr = stateRemoteAddr this.stateLocalAddr = stateLocalAddr this.frontentAddr = frontentAddr return this }
func main() { server := gomsg.NewServer() server.SetTimeout(time.Second) server.Listen(":7777") cli := gomsg.NewClient() cli.Handle("REVERSE", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== processing (1):", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[1]=%s", reverse(m)), nil }) cli.Connect("localhost:7777") /* cli2 := gomsg.NewClient() cli2.Handle("REVERSE", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== processing (2):", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[2]=%s", reverse(m)), nil }) cli2.Connect("localhost:7777") // just to get in the way cli3 := gomsg.NewClient() cli3.Connect("localhost:7777") */ // =============== //time.Sleep(time.Millisecond * 100) fmt.Println("====> requesting...") <-server.Request("REVERSE", "hello", func(ctx gomsg.Response, r string) { fmt.Println("===> reply:", r) }) /* server.RequestAll("REVERSE", "hello", func(ctx gomsg.Response, r string) { fmt.Println("===> reply:", ctx.Kind, r) }, time.Second) */ time.Sleep(time.Second * 2) fmt.Println("I: close...") cli.Destroy() time.Sleep(time.Second * 5) }
// Request sends a request to the Binary Star. // If there's no reply within our timeout, we close the socket and try again. // In Binary Star, it's the client vote that decides which // server is primary; the client must therefore try to connect // to each server in turn: func (bsc BStarClient) Request(name string, payload interface{}, handler interface{}, timeout time.Duration) { expectReply := true // A request is used so that the bstar server can decide not to reply // if there is an inconsistent server state ch := bsc.client.RequestTimeout(name, payload, handler, timeout) for expectReply { err := <-ch if err == nil { expectReply = false } else { fmt.Println("W: no response from server, failing over. error:", err) // client is confused; close it and open a new one bsc.client.Destroy() bsc.serverNbr = (bsc.serverNbr + 1) % 2 <-time.After(SETTLE_DELAY) fmt.Printf("I: connecting to server at %s...\n", bsc.servers[bsc.serverNbr]) bsc.client = gomsg.NewClient().SetCodec(codec) bsc.client.Connect(bsc.servers[bsc.serverNbr]) // Send request again, on new client ch = bsc.client.RequestTimeout(name, payload, handler, timeout) } } }
func main() { server := gomsg.NewServer() server.SetTimeout(time.Second) server.Listen(":7777") cli := gomsg.NewClient() cli2 := gomsg.NewClient() fmt.Println("=========== STICKY PUSH =============") cli.Handle("PUSHING", func(ctx *gomsg.Request, m string) { fmt.Println("<=== processing PUSHING (1):", m, "from", ctx.Connection().RemoteAddr()) }) cli.Handle("NOISE", func(ctx *gomsg.Request, m string) { fmt.Println("<=== processing NOISE (21):", m, "from", ctx.Connection().RemoteAddr()) }) cli2.Handle("PUSHING", func(ctx *gomsg.Request, m string) { fmt.Println("<=== processing PUSHING (2):", m, "from", ctx.Connection().RemoteAddr()) }) cli2.Handle("NOISE", func(ctx *gomsg.Request, m string) { fmt.Println("<=== processing NOISE (22):", m, "from", ctx.Connection().RemoteAddr()) }) cli.Connect("localhost:7777") cli2.Connect("localhost:7777") wait() // note the FILTER_TOKEN at the end. This way we can define a range of Stickyness server.Stick("PUSH"+gomsg.FILTER_TOKEN, time.Millisecond*500) server.Push("PUSHING", "ping") wait() server.Push("PUSHING", "ping") wait() server.Push("NOISE", "---noise--- will provoque the rotation of the general cursor") wait() server.Push("PUSHING", "ping") wait() server.Push("NOISE", "---noise--- will provoque the rotation of the general cursor") wait() server.Push("PUSHING", "ping") time.Sleep(time.Second) server.Push("PUSHING", "change wire") wait() fmt.Println("=========== STICKY REQUEST =============") cli.Handle("REVERSE", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== processing REVERSE (1):", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[1]=%s", reverse(m)), nil }) cli2.Handle("REVERSE", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== processing REVERSE (2):", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[2]=%s", reverse(m)), nil }) wait() server.Stick("REVERSE", time.Millisecond*500) // Warning: when requesting many in a server, the last response (end mark) will have a null connection var resultFn = func(ctx gomsg.Response, r string) { fmt.Println("===> reply:", r, ", last?", ctx.Last()) } server.Request("REVERSE", "hello", resultFn) wait() server.Request("REVERSE", "world", resultFn) wait() server.Request("REVERSE", "ola", resultFn) wait() server.Request("REVERSE", "mundo", resultFn) time.Sleep(time.Second) server.Request("REVERSE", "change wire", resultFn) wait() time.Sleep(time.Second * 2) fmt.Println("I: close...") cli.Destroy() time.Sleep(time.Second * 5) }
func main() { server := gomsg.NewServer() server.Handle("HELLO", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== processing:", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("Hello %s", m), nil }) server.Handle("XPTO", func(m string) { fmt.Println("<=== handling pull:", m) }) server.Listen(":7777") cli := gomsg.NewClient() cli.Handle("REVERSE", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== processing (1):", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[1]=%s", reverse(m)), nil }) cli.Handle("SUB", func(m string) { fmt.Println("<=== handling pub-sub:", m) }) cli.Connect("localhost:7777") cli2 := gomsg.NewClient() cli2.Handle("REVERSE", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== processing (2):", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[2]=%s", reverse(m)), nil }) cli2.Handle("SUB", func(m string) { fmt.Println("<=== handling pub-sub:", m) }) cli2.Connect("localhost:7777") //var err error /* messages := []string{"Hello", "World", "Paulo"} for _, m := range messages { err = <-cli.Request("HELLO", m, func(ctx gomsg.IResponse, r string) { fmt.Println("===> reply:", r, "from", ctx.Connection().RemoteAddr()) }) if err != nil { fmt.Println("===> error:", err) } } */ time.Sleep(time.Millisecond * 100) // Warning: when requesting many in a server, the last response (end mark) will have a null connection server.RequestAll("REVERSE", "hello", func(ctx gomsg.Response, r string) { fmt.Println("===> reply:", r) }, time.Second) /* server.Request("REVERSE", "hello", func(ctx gomsg.IResponse, r string) { fmt.Println("===> reply:", r, "from", ctx.Connection().RemoteAddr()) }) server.Request("REVERSE", "hello", func(ctx gomsg.IResponse, r string) { fmt.Println("===> reply:", r, "from", ctx.Connection().RemoteAddr()) }) server.Request("REVERSE", "hello", func(ctx gomsg.IResponse, r string) { fmt.Println("===> reply:", r, "from", ctx.Connection().RemoteAddr()) }) */ //server.Publish("SUB", "PUB: La") /* err = <-cli.Publish("XPTO", "PUB: La") err = <-cli.Publish("XPTO", "PUB: Vida") err = <-cli.Publish("XPTO", "PUB: Loca") */ //cli.Push("XPTO", "One") /* err = <-cli.Push("XPTO", "PUSH: Two") err = <-cli.Push("XPTO", "PUSH: Three") err = <-cli.Push("XPTO", "PUSH: Four") time.Sleep(time.Millisecond * 100) err = <-cli.Push("FAIL", 123) fmt.Println("I: error:", err) if err == nil { fmt.Println("E: Should have returned an error") } */ time.Sleep(time.Millisecond * 100) fmt.Println("I: close...") cli.Destroy() time.Sleep(time.Millisecond * 100) }
func main() { // all messages arriving to the server are routed to the clients server := gomsg.NewServer() server.Listen(":7777") server.Route("*", time.Second, nil, nil) cli := gomsg.NewClient() cli.Handle("HELLO", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== [1] processing:", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[1] Hello %s", m), nil }) // sends multi reply cli.Handle("PIPE", func(ctx *gomsg.Request) { ctx.SendReply([]byte("\"Pipe #1\"")) ctx.SendReply([]byte("\"Pipe #2\"")) ctx.Terminate() }) cli.Connect("localhost:7777") // just to get in the way cli3 := gomsg.NewClient() cli3.Connect("localhost:7777") cli2 := gomsg.NewClient() cli2.Handle("HELLO", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== [2] processing:", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[2] Hello %s", m), nil }) cli2.Handle("PIPE", func(ctx *gomsg.Request) string { return "Pipe #201" }) cli2.Connect("localhost:7777") <-cli3.RequestAll("HELLO", "World!", func(ctx gomsg.Response, r string, e error) { fmt.Println("===HELLO===> reply:", r, e, "from", ctx.Connection().RemoteAddr()) }) fmt.Println("===============") <-cli3.RequestAll("PIPE", nil, func(ctx gomsg.Response, s string) { fmt.Println("===PIPE===> reply:", ctx.Kind, string(ctx.Reply()), s) }) fmt.Println("===============") <-cli3.Request("PIPE", nil, func(ctx gomsg.Response, s string) { fmt.Println("===PIPE===> reply:", ctx.Kind, string(ctx.Reply()), s) }) /* cli.Request("HELLO", "World!", func(ctx gomsg.IResponse, r string, e error) { fmt.Println("=================> reply:", r, e, "from", ctx.Connection().RemoteAddr()) }) // check to see if the server is working server.Request("HELLO", "World!", func(ctx gomsg.IResponse, r string, e error) { fmt.Println("=================> reply:", r, e, "from", ctx.Connection().RemoteAddr()) }) server.Request("HELLO", "World!", func(ctx gomsg.IResponse, r string, e error) { fmt.Println("=================> reply:", r, e, "from", ctx.Connection().RemoteAddr()) }) */ time.Sleep(time.Millisecond * 100) cli.Destroy() time.Sleep(time.Millisecond * 100) }
func main() { server := gomsg.NewServer() // keep alive var timeout = gomsg.NewTimeout(CLEAN_CYCLE, time.Second, func(o interface{}) { c := o.(net.Conn) fmt.Println("=====> killing connection from", c.RemoteAddr()) server.Wires.Kill(c) }) server.OnConnect = func(w *gomsg.Wired) { // starts monitoring timeout.Delay(w.Conn()) } // for PING messages the server will reply immediatly, // without relaying the message to the clients. server.Route("*", time.Second, func(ctx *gomsg.Request) bool { // any message received, delays the timeout timeout.Delay(ctx.Connection()) if ctx.Name == "PING" { ctx.SetReply([]byte("PONG")) return false } return true }, nil) server.Listen(":7777") cli := gomsg.NewClient() cli.SetReconnectInterval(0) cli.Handle("HELLO", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== [1] processing:", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[1] Hello %s", m), nil }) cli.Connect("localhost:7777") // just to get in the way cli3 := gomsg.NewClient() cli3.SetReconnectInterval(0) cli3.Connect("localhost:7777") cli2 := gomsg.NewClient() cli2.SetReconnectInterval(0) cli2.Handle("HELLO", func(ctx *gomsg.Request, m string) (string, error) { fmt.Println("<=== [2] processing:", m, "from", ctx.Connection().RemoteAddr()) return fmt.Sprintf("[2] Hello %s", m), nil }) cli2.Connect("localhost:7777") <-cli3.RequestAll("HELLO", "World!", func(ctx gomsg.Response, r string, e error) { fmt.Println("===HELLO===> reply:", r, e, "from", ctx.Connection().RemoteAddr()) }) time.Sleep(time.Millisecond * 2000) <-cli3.RequestAll("HELLO", "World!", func(ctx gomsg.Response, r string, e error) { fmt.Println("===HELLO===> reply:", r, e, "from", ctx.Connection().RemoteAddr()) }) time.Sleep(time.Millisecond * 1000) }
func main() { // all messages arriving to the server are routed to the clients server := gomsg.NewServer() server.Listen(":7777") server.Route("*", time.Second, nil, nil) ungrouped := 0 cli := gomsg.NewClient() cli.Handle("HELLO", func(m string) { fmt.Println("<=== [0] processing:", m) ungrouped++ }) <-cli.Connect("localhost:7777") group1 := 0 // Group HA subscriber cli1 := gomsg.NewClient() cli1.SetGroupId("HA") cli1.Handle("HELLO", func(m string) { fmt.Println("<=== [1] processing:", m) group1++ }) <-cli1.Connect("localhost:7777") // Group HA subscriber group2 := 0 cli2 := gomsg.NewClient() cli2.SetGroupId("HA") cli2.Handle("HELLO", func(m string) { fmt.Println("<=== [2] processing:", m) group2++ }) <-cli2.Connect("localhost:7777") // publisher cli3 := gomsg.NewClient() <-cli3.Connect("localhost:7777") // Only one element of the group HA will process each message, alternately (round robin). // cli3.Publish("HELLO", "Hello World!") // cli3.Publish("HELLO", "Olá Mundo!") // cli3.Publish("HELLO", "YESSSS!") cli3.Publish("HELLO", "one") wait() cli3.Publish("HELLO", "two") wait() cli3.Publish("HELLO", "three") wait() cli3.Publish("HELLO", "four") wait() if ungrouped != 4 { fmt.Println("ERROR: RECEIVED", ungrouped, "UNGROUPED EVENTS. EXPECTED 4.") } if group1 != 2 { fmt.Println("ERROR: RECEIVED", group1, "GROUP EVENTS. EXPECTED 2.") } if group2 != 2 { fmt.Println("ERROR: RECEIVED", group2, "GROUP EVENTS. EXPECTED 2.") } wait() cli.Destroy() wait() }
// Connect binds a to a local address to provide services // and connect to the directory remove addresses func (node *Node) Connect(bindAddr string, dirAddrs ...string) error { var err = node.local.Listen(bindAddr) if err != nil { return err } node.remoteDirs = make([]*gomsg.Client, len(dirAddrs)) for k, dirAddr := range dirAddrs { var dir = gomsg.NewClient() node.remoteDirs[k] = dir dir.Handle(C_PEERREADY, func(provider Provider) { fmt.Println("I: > node:", bindAddr, "C_PEERREADY notified of a new peer:", provider) node.mu.Lock() node.providers[provider.Endpoint] = &provider node.mu.Unlock() }) dir.Handle(C_ADDSERVICE, func(service Service) { fmt.Println("I: > node:", bindAddr, "C_ADDSERVICE notified of a new service:", service) node.mu.Lock() for _, v := range node.providers { if v.Endpoint == service.Endpoint { v.AddService(service.Name) break } } node.mu.Unlock() }) dir.Handle(C_CANCELSERVICE, func(service Service) { fmt.Println("I: > node:", bindAddr, "C_CANCELSERVICE notified of canceled service:", service) node.mu.Lock() var empty = false for _, v := range node.providers { if v.Endpoint == service.Endpoint { empty = v.RemoveService(service.Name) break } } node.mu.Unlock() if empty { node.disconnectPeer(service.Endpoint) } }) dir.Handle(C_DROPPEER, func(endpoint string) { fmt.Println("I: > node:", bindAddr, "C_DROPPEER peer:", endpoint) node.mu.Lock() delete(node.providers, endpoint) node.mu.Unlock() node.disconnectPeer(endpoint) }) dir.OnConnect = func(w *gomsg.Wired) { // this will ping the service directory, // and if there is no reply after some attempts it will reconnect go func() { var ticker = time.NewTicker(node.PingInterval) var retries = node.PingFailures for _ = range ticker.C { if dir.Active() { var pong = "" var err = <-dir.RequestTimeout(PING, nil, func(ctx gomsg.Response, reply string) { pong = reply }, time.Millisecond*10) if _, ok := err.(gomsg.TimeoutError); ok || pong != PONG { retries-- fmt.Println("D: > PING failed. retries left:", retries) if retries == 0 { ticker.Stop() } } else { retries = node.PingFailures } } else { ticker.Stop() } } dir.Reconnect() }() node.dirs.Put(w.Conn(), w.Wire()) // only want for the first established connection to get the list of providers if node.dirs.Size() > 1 { return } node.mu.RLock() var services = make([]string, len(node.provides)) var i = 0 for k := range node.provides { services[i] = k i++ } node.mu.RUnlock() var provider = NewProvider(strconv.Itoa(node.local.BindPort())) provider.Services = services dir.Request(S_PEERREADY, provider, func(ctx gomsg.Response, providers []Provider) { node.mu.Lock() defer node.mu.Unlock() for _, v := range providers { node.providers[v.Endpoint] = &v } }) } dir.OnClose = func(c net.Conn) { node.dirs.Kill(c) for k, v := range node.remoteDirs { if v.Connection() == c { // since the slice has a non-primitive, we have to zero it copy(node.remoteDirs[k:], node.remoteDirs[k+1:]) node.remoteDirs[len(node.remoteDirs)-1] = nil // zero it node.remoteDirs = node.remoteDirs[:len(node.remoteDirs)-1] } } } dir.Connect(dirAddr) } return nil }