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 }