github.com/chain5j/chain5j-pkg@v1.0.7/eventbus/client.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  const (
    13  	// PublishService - Client service method
    14  	PublishService = "ClientService.PushEvent"
    15  )
    16  
    17  // ClientArg - object containing event for client to publish locally
    18  type ClientArg struct {
    19  	Args  []interface{}
    20  	Topic string
    21  }
    22  
    23  // Client - object capable of subscribing to a remote event bus
    24  type Client struct {
    25  	eventBus Bus
    26  	address  string
    27  	path     string
    28  	service  *ClientService
    29  }
    30  
    31  // NewClient - create a client object with the address and server path
    32  func NewClient(address, path string, eventBus Bus) *Client {
    33  	client := new(Client)
    34  	client.eventBus = eventBus
    35  	client.address = address
    36  	client.path = path
    37  	client.service = &ClientService{client, &sync.WaitGroup{}, false}
    38  	return client
    39  }
    40  
    41  // EventBus - returns the underlying event bus
    42  func (client *Client) EventBus() Bus {
    43  	return client.eventBus
    44  }
    45  
    46  func (client *Client) doSubscribe(topic string, fn interface{}, serverAddr, serverPath string, subscribeType SubscribeType) {
    47  	defer func() {
    48  		if r := recover(); r != nil {
    49  			fmt.Println("Server not found -", r)
    50  		}
    51  	}()
    52  
    53  	rpcClient, err := rpc.DialHTTPPath("tcp", serverAddr, serverPath)
    54  	defer rpcClient.Close()
    55  	if err != nil {
    56  		fmt.Errorf("dialing: %v", err)
    57  	}
    58  	args := &SubscribeArg{client.address, client.path, PublishService, subscribeType, topic}
    59  	reply := new(bool)
    60  	err = rpcClient.Call(RegisterService, args, reply)
    61  	if err != nil {
    62  		fmt.Errorf("Register error: %v", err)
    63  	}
    64  	if *reply {
    65  		client.eventBus.Subscribe(topic, fn)
    66  	}
    67  }
    68  
    69  //Subscribe subscribes to a topic in a remote event bus
    70  func (client *Client) Subscribe(topic string, fn interface{}, serverAddr, serverPath string) {
    71  	client.doSubscribe(topic, fn, serverAddr, serverPath, Subscribe)
    72  }
    73  
    74  //SubscribeOnce subscribes once to a topic in a remote event bus
    75  func (client *Client) SubscribeOnce(topic string, fn interface{}, serverAddr, serverPath string) {
    76  	client.doSubscribe(topic, fn, serverAddr, serverPath, SubscribeOnce)
    77  }
    78  
    79  // Start - starts the client service to listen to remote events
    80  func (client *Client) Start() error {
    81  	var err error
    82  	service := client.service
    83  	if !service.started {
    84  		server := rpc.NewServer()
    85  		server.Register(service)
    86  		server.HandleHTTP(client.path, "/debug"+client.path)
    87  		l, err := net.Listen("tcp", client.address)
    88  		if err == nil {
    89  			service.wg.Add(1)
    90  			service.started = true
    91  			go http.Serve(l, nil)
    92  		}
    93  	} else {
    94  		err = errors.New("Client service already started")
    95  	}
    96  	return err
    97  }
    98  
    99  // Stop - signal for the service to stop serving
   100  func (client *Client) Stop() {
   101  	service := client.service
   102  	if service.started {
   103  		service.wg.Done()
   104  		service.started = false
   105  	}
   106  }
   107  
   108  // ClientService - service object listening to events published in a remote event bus
   109  type ClientService struct {
   110  	client  *Client
   111  	wg      *sync.WaitGroup
   112  	started bool
   113  }
   114  
   115  // PushEvent - exported service to listening to remote events
   116  func (service *ClientService) PushEvent(arg *ClientArg, reply *bool) error {
   117  	service.client.eventBus.Publish(arg.Topic, arg.Args...)
   118  	*reply = true
   119  	return nil
   120  }