github.com/vmware/transport-go@v1.3.4/examples/need-refactoring/transport.go (about)

     1  // Copyright 2019-2021 VMware, Inc.
     2  // SPDX-License-Identifier: BSD-2-Clause
     3  
     4  package need_refactoring
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"github.com/google/uuid"
    10  	"github.com/urfave/cli"
    11  	"github.com/vmware/transport-go/bridge"
    12  	"github.com/vmware/transport-go/bus"
    13  	"github.com/vmware/transport-go/model"
    14  	"github.com/vmware/transport-go/service"
    15  	"github.com/vmware/transport-go/stompserver"
    16  	"log"
    17  	"math/rand"
    18  	"os"
    19  	"reflect"
    20  	"strconv"
    21  	"sync"
    22  	"time"
    23  )
    24  
    25  var addr = "localhost:8090"
    26  
    27  func main() {
    28  	bus.EnableLogging(true)
    29  	app := cli.NewApp()
    30  	app.Name = "VMware Transport demo app"
    31  	app.Usage = "Demonstrates different features of the Transport bus"
    32  	app.Commands = []cli.Command{
    33  
    34  		{
    35  			Name:  "demo",
    36  			Usage: "Run Demo - Connect to local service. You first need to start the service with 'service' command.",
    37  			Flags: []cli.Flag{
    38  				&cli.BoolFlag{
    39  					Name:  "tcp",
    40  					Usage: "Use TCP connection ",
    41  				},
    42  			},
    43  			Action: func(c *cli.Context) error {
    44  				runDemoApp(c)
    45  				return nil
    46  			},
    47  		},
    48  		//{
    49  		//	Name:  "cal",
    50  		//	Usage: "Call Calendar service for the time on appfabric.vmware.com",
    51  		//	Action: func(c *cli.Context) error {
    52  		//		runDemoCal()
    53  		//		return nil
    54  		//	},
    55  		//},
    56  		//{
    57  		//	Name:  "vm-service",
    58  		//	Usage: "Call VmService to create and Power on a new VM on appfabric.vmware.com",
    59  		//	Action: func(c *cli.Context) error {
    60  		//		runDemoVmService(c)
    61  		//		return nil
    62  		//	},
    63  		//	Flags: []cli.Flag{
    64  		//		&cli.BoolFlag{
    65  		//			Name:  "localhost",
    66  		//			Usage: "Connect to localhost:8090 instead of appfabric.vmware.com",
    67  		//		},
    68  		//	},
    69  		//},
    70  		{
    71  			Name:  "service",
    72  			Usage: "Run Service - Run local service",
    73  			Flags: []cli.Flag{
    74  				&cli.BoolFlag{
    75  					Name:  "tcp",
    76  					Usage: "Use TCP connection ",
    77  				},
    78  			},
    79  			Action: func(c *cli.Context) error {
    80  				runLocalFabricBroker(c)
    81  				return nil
    82  			},
    83  		},
    84  		//{
    85  		//	Name:  "store",
    86  		//	Usage: "Open galactic store from appfabric.vmware.com",
    87  		//	Action: func(c *cli.Context) error {
    88  		//		runDemoStore(c)
    89  		//		return nil
    90  		//	},
    91  		//	Flags: []cli.Flag{
    92  		//		&cli.BoolFlag{
    93  		//			Name:  "localhost",
    94  		//			Usage: "Connect to localhost:8090 instead of appfabric.vmware.com",
    95  		//		},
    96  		//	},
    97  		//},
    98  		{
    99  			Name:  "fabric-services",
   100  			Usage: "Starts a couple of demo fabric services locally",
   101  			Flags: []cli.Flag{
   102  				&cli.BoolFlag{
   103  					Name:  "localhost",
   104  					Usage: "Use localhost transport broker",
   105  				},
   106  			},
   107  			Action: func(c *cli.Context) error {
   108  				runDemoFabricServices(c)
   109  				return nil
   110  			},
   111  		},
   112  	}
   113  
   114  	err := app.Run(os.Args)
   115  	if err != nil {
   116  		log.Fatal(err)
   117  	}
   118  }
   119  
   120  func runDemoCal() {
   121  	// get a pointer to the bus.
   122  	b := bus.GetBus()
   123  
   124  	// get a pointer to the channel manager
   125  	cm := b.GetChannelManager()
   126  
   127  	channel := "calendar-service"
   128  	cm.CreateChannel(channel)
   129  
   130  	// create done signal
   131  	var done = make(chan bool)
   132  
   133  	// listen to stream RESPONSE messages coming in.
   134  	h, err := b.ListenStream(channel)
   135  
   136  	if err != nil {
   137  		log.Panicf("unable to listen to channel stream, error: %e", err)
   138  	}
   139  
   140  	// handle response from calendar service.
   141  	h.Handle(
   142  		func(msg *model.Message) {
   143  
   144  			// unmarshal the payload into a Response object (used by fabric services)
   145  			r := &model.Response{}
   146  			d := msg.Payload.([]byte)
   147  			json.Unmarshal(d, &r)
   148  			fmt.Printf("got time response from service: %s\n", r.Payload.(string))
   149  			done <- true
   150  		},
   151  		func(err error) {
   152  			log.Panicf("error received on channel %e", err)
   153  		})
   154  
   155  	// create a broker connector config, in this case, we will connect to the application fabric demo endpoint.
   156  	config := &bridge.BrokerConnectorConfig{
   157  		Username: "guest",
   158  		Password: "guest",
   159  		UseWS:    true,
   160  		WebSocketConfig: &bridge.WebSocketConfig{
   161  			WSPath: "/fabric",
   162  			UseTLS: false,
   163  		},
   164  		ServerAddr: "appfabric.vmware.com"}
   165  
   166  	// connect to broker.
   167  	c, err := b.ConnectBroker(config)
   168  	if err != nil {
   169  		log.Panicf("unable to connect to fabric broker, error: %e", err)
   170  	}
   171  	fmt.Println("Connected to fabric broker!")
   172  
   173  	// mark our local channel as galactic and map it to our connection and the /topic/calendar-service destination
   174  	err = cm.MarkChannelAsGalactic(channel, "/topic/"+channel, c)
   175  	if err != nil {
   176  		log.Panicf("unable to map local channel to broker destination: %e", err)
   177  	}
   178  
   179  	// create request
   180  	id := uuid.New()
   181  	r := &model.Request{}
   182  	r.Request = "time"
   183  	r.Id = &id
   184  	m, _ := json.Marshal(r)
   185  	fmt.Println("Requesting time from calendar service")
   186  
   187  	// send request.
   188  	c.SendJSONMessage("/pub/"+channel, m)
   189  
   190  	// wait for done signal
   191  	<-done
   192  	fmt.Printf("\nDone.\n\n")
   193  
   194  	// mark channel as local (unsubscribe from all mappings)
   195  	err = cm.MarkChannelAsLocal(channel)
   196  	if err != nil {
   197  		log.Panicf("unable to unsubscribe, error: %e", err)
   198  	}
   199  
   200  	err = c.Disconnect()
   201  	if err != nil {
   202  		log.Panicf("unable to disconnect, error: %e", err)
   203  	}
   204  }
   205  
   206  type SampleMessageItem struct {
   207  	From    string `json:"from"`
   208  	Message string `json:"message"`
   209  }
   210  
   211  func (mi SampleMessageItem) print() {
   212  	fmt.Println("FROM:", mi.From)
   213  	fmt.Println("Message:", mi.Message)
   214  }
   215  
   216  func runDemoVmService(ctx *cli.Context) {
   217  	b := bus.GetBus()
   218  	cm := b.GetChannelManager()
   219  	channel := "vm-service"
   220  	cm.CreateChannel(channel)
   221  	// create done signal
   222  	var done = make(chan bool)
   223  	// listen to stream RESPONSE messages coming in.
   224  	h, err := b.ListenStream(channel)
   225  	var lastResponse *model.Response
   226  	// handle response from vm-service.
   227  	h.Handle(
   228  		func(msg *model.Message) {
   229  			// unmarshal the payload into a Response object (used by fabric services)
   230  			r := &model.Response{}
   231  			d := msg.Payload.([]byte)
   232  			json.Unmarshal(d, &r)
   233  			lastResponse = r
   234  
   235  			if r.Payload != nil && r.Payload.(map[string]interface{})["error"] == true {
   236  				fmt.Println("Request failed: ", r.Payload.(map[string]interface{})["errorMessage"])
   237  			}
   238  
   239  			done <- true
   240  		},
   241  		func(err error) {
   242  			log.Panicf("error received on channel %e", err)
   243  		})
   244  
   245  	var addr = "appfabric.vmware.com"
   246  	if ctx.Bool("localhost") {
   247  		addr = "localhost:8090"
   248  	}
   249  
   250  	// create a broker connector config, in this case, we will connect to the application fabric demo endpoint.
   251  	config := &bridge.BrokerConnectorConfig{
   252  		Username: "guest",
   253  		Password: "guest",
   254  		UseWS:    true,
   255  		WebSocketConfig: &bridge.WebSocketConfig{
   256  			WSPath: "/fabric",
   257  			UseTLS: false,
   258  		},
   259  		ServerAddr: addr}
   260  
   261  	// connect to broker.
   262  	c, err := b.ConnectBroker(config)
   263  	if err != nil {
   264  		log.Panicf("unable to connect to fabric broker, error: %e", err)
   265  	}
   266  	fmt.Println("Connected to fabric broker!")
   267  	err = cm.MarkChannelAsGalactic(channel, "/topic/"+channel, c)
   268  	if err != nil {
   269  		log.Panicf("unable to map local channel to broker destination: %e", err)
   270  	}
   271  
   272  	// helper function that sends requests to VmService
   273  	makeVmRequest := func(request string, payload interface{}) {
   274  		id := uuid.New()
   275  		r := &model.Request{
   276  			Id:      &id,
   277  			Request: request,
   278  			Payload: payload,
   279  		}
   280  		m, _ := json.Marshal(r)
   281  		c.SendJSONMessage("/pub/"+channel, m)
   282  
   283  		// wait for done signal
   284  		<-done
   285  	}
   286  
   287  	// Create New VM request
   288  	fmt.Println("Creating VM without name...")
   289  	makeVmRequest("createVm", &VmCreateRequest{})
   290  
   291  	// Create New VM request
   292  	fmt.Println("Creating 'test-vm' VM...")
   293  	makeVmRequest("createVm", &VmCreateRequest{
   294  		Name: "test-vm",
   295  		VirtualHardware: &VirtualHardware{
   296  			MemoryMB: 1024,
   297  			NumCPU:   2,
   298  			Devices: []interface{}{
   299  				VirtualDisk{
   300  					Key:        1,
   301  					DeviceType: "VirtualDisk",
   302  					DeviceName: "virtualDisk-1",
   303  					CapacityMB: 200,
   304  					DiskFormat: "emulated_512",
   305  				},
   306  			},
   307  		},
   308  	})
   309  
   310  	resp, _ := model.ConvertValueToType(lastResponse.Payload, reflect.TypeOf(VmCreateResponse{}))
   311  	vm := resp.(VmCreateResponse).Vm
   312  	fmt.Println("VM created successfully with id:", vm.VmRef.VmId, "on host "+vm.RuntimeInfo.Host)
   313  
   314  	// change power state of the vm
   315  	fmt.Println("Power on 'test-vm'")
   316  	makeVmRequest("changeVmPowerState", &VmPowerOperationRequest{
   317  		VmRefs:         []VmRef{vm.VmRef},
   318  		PowerOperation: powerOperation_powerOn,
   319  	})
   320  
   321  	// List all VMs
   322  	fmt.Println("Requesting all VMs")
   323  	makeVmRequest("listVms", nil)
   324  
   325  	resp, _ = model.ConvertValueToType(lastResponse.Payload, reflect.TypeOf(VmListResponse{}))
   326  	allVms := resp.(VmListResponse)
   327  	fmt.Printf("Received %d VMs:\n", len(allVms.VirtualMachines))
   328  	for _, vm := range allVms.VirtualMachines {
   329  		fmt.Printf("VM: %s (%s)\n", vm.Name, vm.RuntimeInfo.PowerState)
   330  	}
   331  
   332  	// Delete the newly created VM
   333  	fmt.Println("Deleting 'test-vm'")
   334  	makeVmRequest("deleteVm", &VmDeleteRequest{Vm: vm.VmRef})
   335  
   336  	fmt.Printf("\nDone.\n\n")
   337  }
   338  
   339  func runDemoStore(ctx *cli.Context) {
   340  	// get a pointer to the bus.
   341  	b := bus.GetBus()
   342  
   343  	var addr = "appfabric.vmware.com"
   344  	if ctx.Bool("localhost") {
   345  		addr = "localhost:8090"
   346  	}
   347  
   348  	// create a broker connector config, in this case, we will connect to the application fabric demo endpoint.
   349  	config := &bridge.BrokerConnectorConfig{
   350  		Username: "guest",
   351  		Password: "guest",
   352  		UseWS:    true,
   353  		WebSocketConfig: &bridge.WebSocketConfig{
   354  			WSPath: "/fabric",
   355  			UseTLS: false,
   356  		},
   357  		ServerAddr: addr}
   358  
   359  	// connect to broker.
   360  	c, err := b.ConnectBroker(config)
   361  	if err != nil {
   362  		log.Panicf("unable to connect to fabric broker, error: %e", err)
   363  	}
   364  	fmt.Println("Connected to fabric broker:", config.ServerAddr)
   365  
   366  	err = b.GetStoreManager().ConfigureStoreSyncChannel(c, "/topic/", "/pub/")
   367  	if err != nil {
   368  		log.Panicf("unable to configure store sync channel, error: %e", err)
   369  	}
   370  
   371  	var motdStore bus.BusStore
   372  	motdStore, err = b.GetStoreManager().OpenGalacticStoreWithItemType(
   373  		"messageOfTheDayStore", c, reflect.TypeOf(SampleMessageItem{}))
   374  	if err != nil {
   375  		log.Panicf("failed to open galactic store, error: %e", err)
   376  	}
   377  
   378  	wg := sync.WaitGroup{}
   379  	wg.Add(1)
   380  	motdStore.WhenReady(func() {
   381  		wg.Done()
   382  	})
   383  
   384  	wg.Wait()
   385  
   386  	originalItem := motdStore.GetValue("messageOfTheDay").(SampleMessageItem)
   387  	originalItem.print()
   388  
   389  	storeStream := motdStore.OnChange("messageOfTheDay")
   390  	storeStream.Subscribe(func(change *bus.StoreChange) {
   391  		if change.IsDeleteChange {
   392  			fmt.Println("Item removed: ", change.Id)
   393  		} else {
   394  			fmt.Println("Store item changed: ")
   395  			change.Value.(SampleMessageItem).print()
   396  		}
   397  		wg.Done()
   398  	})
   399  
   400  	wg.Add(1)
   401  	motdStore.Put("messageOfTheDay",
   402  		SampleMessageItem{
   403  			Message: "updated sample message",
   404  			From:    "test user",
   405  		}, "update")
   406  	wg.Wait()
   407  
   408  	wg.Add(1)
   409  	motdStore.Put("messageOfTheDay", originalItem, "update")
   410  	wg.Wait()
   411  
   412  	// Local stores
   413  	localStringStore := b.GetStoreManager().CreateStore("localStringStore")
   414  	localMessageStore := b.GetStoreManager().CreateStore("localSampleMessageStore")
   415  
   416  	// use async transaction to wait for the two local stores.
   417  	tr := b.CreateAsyncTransaction()
   418  	tr.WaitForStoreReady(localStringStore.GetName())
   419  	tr.WaitForStoreReady(localMessageStore.GetName())
   420  
   421  	wg.Add(1)
   422  	tr.OnComplete(func(responses []*model.Message) {
   423  		fmt.Println("Local stores initialized")
   424  		fmt.Println("localStringStore:")
   425  		fmt.Println(responses[0].Payload)
   426  		fmt.Println("localSampleMessageStore:")
   427  		fmt.Println(responses[1].Payload)
   428  		wg.Done()
   429  	})
   430  
   431  	fmt.Println("Waiting for local stores...")
   432  	tr.Commit()
   433  
   434  	localStringStore.Populate(map[string]interface{}{
   435  		"key1": "value1",
   436  		"key2": "value2",
   437  		"key3": "value3",
   438  	})
   439  
   440  	// copy the values from the galactic motdStore to the local
   441  	// store
   442  	localMessageStore.Populate(motdStore.AllValuesAsMap())
   443  
   444  	b.GetStoreManager().DestroyStore("messageOfTheDayStore")
   445  
   446  	wg.Wait()
   447  }
   448  
   449  func runDemoApp(ctx *cli.Context) {
   450  
   451  	// ensure unique message ping message ids
   452  	rand.Seed(time.Now().UTC().UnixNano())
   453  
   454  	// get a pointer to the bus.
   455  	b := bus.GetBus()
   456  
   457  	// get a pointer to the channel manager
   458  	cm := b.GetChannelManager()
   459  
   460  	channel := "my-stream"
   461  	cm.CreateChannel(channel)
   462  
   463  	// create done signal
   464  	var done = make(chan bool)
   465  
   466  	// listen to stream of messages coming in on channel.
   467  	h, err := b.ListenStream(channel)
   468  	if err != nil {
   469  		log.Panicf("unable to listen to channel stream, error: %e", err)
   470  	}
   471  
   472  	count := 0
   473  
   474  	// listen for five messages and then exit, send a completed signal on channel.
   475  	h.Handle(
   476  		func(msg *model.Message) {
   477  
   478  			// unmarshal the payload into a Response object (used by fabric services)
   479  			r := &model.Response{}
   480  			d := msg.Payload.([]byte)
   481  			json.Unmarshal(d, &r)
   482  			fmt.Printf("Stream ticked from local broker: %s\n", r.Payload.(string))
   483  			count++
   484  			if count >= 5 {
   485  				done <- true
   486  			}
   487  		},
   488  		func(err error) {
   489  			log.Panicf("error received on channel %e", err)
   490  		})
   491  
   492  	// create a broker connector config, in this case, we will connect to local fabric broker
   493  	var config *bridge.BrokerConnectorConfig
   494  	if ctx.Bool("tcp") {
   495  		config = &bridge.BrokerConnectorConfig{
   496  			Username:   "guest",
   497  			Password:   "guest",
   498  			ServerAddr: addr}
   499  	} else {
   500  		config = &bridge.BrokerConnectorConfig{
   501  			Username: "guest",
   502  			Password: "guest",
   503  			UseWS:    true,
   504  			WebSocketConfig: &bridge.WebSocketConfig{
   505  				WSPath: "/fabric",
   506  				UseTLS: false,
   507  			},
   508  			ServerAddr: addr}
   509  	}
   510  
   511  	// connect to broker.
   512  	c, err := b.ConnectBroker(config)
   513  	if err != nil {
   514  		log.Panicf("unable to connect to local broker, error: %e", err)
   515  	}
   516  	fmt.Println("Connected to local broker!")
   517  
   518  	// mark our local channel as galactic and map it to our connection and the /topic/ping-service
   519  	// running locally
   520  	err = cm.MarkChannelAsGalactic(channel, "/topic/"+PongServiceChan, c)
   521  	if err != nil {
   522  		log.Panicf("unable to map local channel to broker destination: %e", err)
   523  	}
   524  
   525  	fmt.Printf("\nSending 5 public messages to broker, every 500ms\n\n")
   526  	time.Sleep(1 * time.Second)
   527  	for i := 0; i < 5; i++ {
   528  		pl := "ping--" + strconv.Itoa(rand.Intn(10000000))
   529  		r := &model.Request{Request: "basic", Payload: pl}
   530  		m, _ := json.Marshal(r)
   531  		c.SendJSONMessage("/pub/"+PongServiceChan, m)
   532  		time.Sleep(500 * time.Millisecond)
   533  	}
   534  
   535  	// wait for done signal
   536  	<-done
   537  
   538  	fmt.Printf("\nDone.\n\n")
   539  
   540  	// mark channel as local (unsubscribe from all mappings)
   541  	err = cm.MarkChannelAsLocal(channel)
   542  	if err != nil {
   543  		log.Panicf("unable to unsubscribe, error: %e", err)
   544  	}
   545  
   546  	privateChannel := "my-private-channel"
   547  	cm.CreateChannel(privateChannel)
   548  	// mark the privateChannel channel as galactic and map it to /user/queue/ping-service
   549  	err = cm.MarkChannelAsGalactic(privateChannel, "/user/queue/"+PongServiceChan, c)
   550  	if err != nil {
   551  		log.Panicf("unable to map local channel to broker destination: %e", err)
   552  	}
   553  
   554  	// listen to stream of messages coming in on channel.
   555  	ph, err := b.ListenStream(privateChannel)
   556  	if err != nil {
   557  		log.Panicf("unable to listen to channel stream, error: %e", err)
   558  	}
   559  
   560  	count = 0
   561  	// listen for five messages and then exit, send a completed signal on channel.
   562  	ph.Handle(
   563  		func(msg *model.Message) {
   564  			// unmarshal the payload into a Response object (used by fabric services)
   565  			r := &model.Response{}
   566  			d := msg.Payload.([]byte)
   567  			json.Unmarshal(d, &r)
   568  			fmt.Printf("Stream ticked from local broker on private channel: %s\n", r.Payload.(string))
   569  			count++
   570  			if count >= 5 {
   571  				done <- true
   572  			}
   573  		},
   574  		func(err error) {
   575  			log.Panicf("error received on channel %e", err)
   576  		})
   577  
   578  	fmt.Printf("\nSending 5 private messages to broker, every 500ms\n\n")
   579  	time.Sleep(1 * time.Second)
   580  	for i := 0; i < 5; i++ {
   581  
   582  		pl := "ping--" + strconv.Itoa(rand.Intn(10000000))
   583  		r := &model.Request{Request: "full", Payload: pl}
   584  		m, _ := json.Marshal(r)
   585  		c.SendJSONMessage("/pub/queue/"+PongServiceChan, m)
   586  		time.Sleep(500 * time.Millisecond)
   587  	}
   588  
   589  	// wait for done signal
   590  	<-done
   591  
   592  	// mark channel as local (unsubscribe from all mappings)
   593  	err = cm.MarkChannelAsLocal(privateChannel)
   594  	if err != nil {
   595  		log.Panicf("unable to unsubscribe, error: %e", err)
   596  	}
   597  
   598  	err = c.Disconnect()
   599  	if err != nil {
   600  		log.Panicf("unable to disconnect, error: %e", err)
   601  	}
   602  }
   603  
   604  func runDemoFabricServices(c *cli.Context) {
   605  	b := bus.GetBus()
   606  
   607  	fmt.Println("Registering fabric services...")
   608  	service.GetServiceRegistry().RegisterService(&simpleStreamTickerService{}, SimpleStreamChan)
   609  	service.GetServiceRegistry().RegisterService(&calendarService{}, CalendarServiceChan)
   610  	service.GetServiceRegistry().RegisterService(&servbotService{}, ServbotServiceChan)
   611  
   612  	wg := sync.WaitGroup{}
   613  	wg.Add(1)
   614  	fmt.Println("Asking for a joke")
   615  	jh, _ := b.ListenStream(ServbotServiceChan)
   616  	jh.Handle(func(message *model.Message) {
   617  		resp := message.Payload.(*model.Response)
   618  		if resp.Error {
   619  			fmt.Println("Received error response from servbot:", resp.ErrorMessage)
   620  		} else {
   621  			fmt.Println("Received response from servbot service:", resp.Payload.([]string)[0])
   622  		}
   623  		wg.Done()
   624  	}, func(e error) {})
   625  	b.SendRequestMessage(ServbotServiceChan, model.Request{Request: "Joke"}, nil)
   626  	wg.Wait()
   627  
   628  	mh, _ := b.ListenStream(CalendarServiceChan)
   629  	mh.Handle(func(message *model.Message) {
   630  		resp := message.Payload.(*model.Response)
   631  		if resp.Error {
   632  			fmt.Println("Received error response from calendar-service:", resp.ErrorMessage)
   633  		} else {
   634  			fmt.Println("Received response from calendar-service:", resp.Payload)
   635  		}
   636  		wg.Done()
   637  	}, func(e error) {})
   638  
   639  	wg.Add(1)
   640  	fmt.Println("Sending \"time\" request to the calendar service")
   641  	b.SendRequestMessage(CalendarServiceChan, model.Request{Request: "time"}, nil)
   642  	wg.Wait()
   643  	wg.Add(1)
   644  	fmt.Println("Sending \"date\" request to the calendar service")
   645  	b.SendRequestMessage(CalendarServiceChan, model.Request{Request: "date"}, nil)
   646  	wg.Wait()
   647  	wg.Add(1)
   648  	fmt.Println("Sending invalid request to the calendar service")
   649  	b.SendRequestMessage(CalendarServiceChan, model.Request{Request: "invalid-request"}, nil)
   650  	wg.Wait()
   651  
   652  	counter := 0
   653  	wg.Add(10)
   654  	fmt.Println("Subscribing to the simple-stream channel and waiting for 10 messages...")
   655  	tickerMh, _ := b.ListenStream(SimpleStreamChan)
   656  	tickerMh.Handle(func(message *model.Message) {
   657  		resp := message.Payload.(*model.Response)
   658  		if resp.Error {
   659  			fmt.Println("Received error response from simple-stream:", resp.ErrorMessage)
   660  		} else {
   661  			fmt.Println("Received response from simple-stream:", resp.Payload)
   662  		}
   663  		wg.Done()
   664  
   665  		counter++
   666  		if counter == 5 {
   667  			b.SendRequestMessage(SimpleStreamChan, model.Request{Request: "offline"}, nil)
   668  			fmt.Println("Temporary stopping the simple-stream service for 3 seconds...")
   669  			time.Sleep(3 * time.Second)
   670  			fmt.Println("Resuming the simple-stream...")
   671  			b.SendRequestMessage(SimpleStreamChan, model.Request{Request: "online"}, nil)
   672  		}
   673  
   674  	}, func(e error) {})
   675  
   676  	wg.Wait()
   677  }
   678  
   679  func runLocalFabricBroker(c *cli.Context) {
   680  	fmt.Println("Service Starting...")
   681  
   682  	service.GetServiceRegistry().RegisterService(&pongService{}, PongServiceChan)
   683  	service.GetServiceRegistry().RegisterService(&calendarService{}, CalendarServiceChan)
   684  	service.GetServiceRegistry().RegisterService(&simpleStreamTickerService{}, SimpleStreamChan)
   685  	service.GetServiceRegistry().RegisterService(&servbotService{}, ServbotServiceChan)
   686  	service.GetServiceRegistry().RegisterService(&vmService{}, VmServiceChan)
   687  	service.GetServiceRegistry().RegisterService(&vmwCloudServiceService{}, VMWCloudServiceChan)
   688  
   689  	store := bus.GetBus().GetStoreManager().CreateStoreWithType(
   690  		"messageOfTheDayStore", reflect.TypeOf(&SampleMessageItem{}))
   691  	store.Populate(map[string]interface{}{
   692  		"messageOfTheDay": &SampleMessageItem{
   693  			From:    "golang message broker",
   694  			Message: "default message",
   695  		},
   696  	})
   697  
   698  	var err error
   699  	var connectionListener stompserver.RawConnectionListener
   700  	if c.Bool("tcp") {
   701  		connectionListener, err = stompserver.NewTcpConnectionListener(addr)
   702  	} else {
   703  		connectionListener, err = stompserver.NewWebSocketConnectionListener(addr, "/fabric", nil)
   704  	}
   705  
   706  	if err == nil {
   707  		err = bus.GetBus().StartFabricEndpoint(connectionListener, bus.EndpointConfig{
   708  			TopicPrefix:           "/topic",
   709  			AppRequestPrefix:      "/pub",
   710  			UserQueuePrefix:       "/user/queue",
   711  			AppRequestQueuePrefix: "/pub/queue",
   712  			Heartbeat:             60000, // 6 seconds
   713  		})
   714  	}
   715  
   716  	if err != nil {
   717  		fmt.Println("Failed to start local fabric broker", err)
   718  	}
   719  }