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  }