github.com/chain5j/chain5j-pkg@v1.0.7/eventbus/server.go (about) 1 package EventBus 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "net/http" 8 "net/rpc" 9 "sync" 10 ) 11 12 // SubscribeType - how the client intends to subscribe 13 type SubscribeType int 14 15 const ( 16 // Subscribe - subscribe to all events 17 Subscribe SubscribeType = iota 18 // SubscribeOnce - subscribe to only one event 19 SubscribeOnce 20 ) 21 22 const ( 23 // RegisterService - Server subscribe service method 24 RegisterService = "ServerService.Register" 25 ) 26 27 // SubscribeArg - object to hold subscribe arguments from remote event handlers 28 type SubscribeArg struct { 29 ClientAddr string 30 ClientPath string 31 ServiceMethod string 32 SubscribeType SubscribeType 33 Topic string 34 } 35 36 // Server - object capable of being subscribed to by remote handlers 37 type Server struct { 38 eventBus Bus 39 address string 40 path string 41 subscribers map[string][]*SubscribeArg 42 service *ServerService 43 } 44 45 // NewServer - create a new Server at the address and path 46 func NewServer(address, path string, eventBus Bus) *Server { 47 server := new(Server) 48 server.eventBus = eventBus 49 server.address = address 50 server.path = path 51 server.subscribers = make(map[string][]*SubscribeArg) 52 server.service = &ServerService{server, &sync.WaitGroup{}, false} 53 return server 54 } 55 56 // EventBus - returns wrapped event bus 57 func (server *Server) EventBus() Bus { 58 return server.eventBus 59 } 60 61 func (server *Server) rpcCallback(subscribeArg *SubscribeArg) func(args ...interface{}) { 62 return func(args ...interface{}) { 63 client, connErr := rpc.DialHTTPPath("tcp", subscribeArg.ClientAddr, subscribeArg.ClientPath) 64 defer client.Close() 65 if connErr != nil { 66 fmt.Errorf("dialing: %v", connErr) 67 } 68 clientArg := new(ClientArg) 69 clientArg.Topic = subscribeArg.Topic 70 clientArg.Args = args 71 var reply bool 72 err := client.Call(subscribeArg.ServiceMethod, clientArg, &reply) 73 if err != nil { 74 fmt.Errorf("dialing: %v", err) 75 } 76 } 77 } 78 79 // HasClientSubscribed - True if a client subscribed to this server with the same topic 80 func (server *Server) HasClientSubscribed(arg *SubscribeArg) bool { 81 if topicSubscribers, ok := server.subscribers[arg.Topic]; ok { 82 for _, topicSubscriber := range topicSubscribers { 83 if *topicSubscriber == *arg { 84 return true 85 } 86 } 87 } 88 return false 89 } 90 91 // Start - starts a service for remote clients to subscribe to events 92 func (server *Server) Start() error { 93 var err error 94 service := server.service 95 if !service.started { 96 rpcServer := rpc.NewServer() 97 rpcServer.Register(service) 98 rpcServer.HandleHTTP(server.path, "/debug"+server.path) 99 l, e := net.Listen("tcp", server.address) 100 if e != nil { 101 err = e 102 fmt.Errorf("listen error: %v", e) 103 } 104 service.started = true 105 service.wg.Add(1) 106 go http.Serve(l, nil) 107 } else { 108 err = errors.New("Server bus already started") 109 } 110 return err 111 } 112 113 // Stop - signal for the service to stop serving 114 func (server *Server) Stop() { 115 service := server.service 116 if service.started { 117 service.wg.Done() 118 service.started = false 119 } 120 } 121 122 // ServerService - service object to listen to remote subscriptions 123 type ServerService struct { 124 server *Server 125 wg *sync.WaitGroup 126 started bool 127 } 128 129 // Register - Registers a remote handler to this event bus 130 // for a remote subscribe - a given client address only needs to subscribe once 131 // event will be republished in local event bus 132 func (service *ServerService) Register(arg *SubscribeArg, success *bool) error { 133 subscribers := service.server.subscribers 134 if !service.server.HasClientSubscribed(arg) { 135 rpcCallback := service.server.rpcCallback(arg) 136 switch arg.SubscribeType { 137 case Subscribe: 138 service.server.eventBus.Subscribe(arg.Topic, rpcCallback) 139 case SubscribeOnce: 140 service.server.eventBus.SubscribeOnce(arg.Topic, rpcCallback) 141 } 142 var topicSubscribers []*SubscribeArg 143 if _, ok := subscribers[arg.Topic]; ok { 144 topicSubscribers = []*SubscribeArg{arg} 145 } else { 146 topicSubscribers = subscribers[arg.Topic] 147 topicSubscribers = append(topicSubscribers, arg) 148 } 149 subscribers[arg.Topic] = topicSubscribers 150 } 151 *success = true 152 return nil 153 }