|
22 | 22 | - [Server](#server-2)
|
23 | 23 | - [Client](#client-2)
|
24 | 24 | - [Result](#result-1)
|
| 25 | +- [Bidirectional streaming RPC service: `comingBackMode`](#bidirectional-streaming-rpc-service-comingbackmode) |
| 26 | + - [Protocol](#protocol-4) |
| 27 | + - [Server](#server-3) |
| 28 | + - [Client](#client-3) |
| 29 | + - [Result](#result-2) |
25 | 30 |
|
26 | 31 | <!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
27 | 32 |
|
@@ -641,6 +646,266 @@ INFO - * New Temperature 👍 --> Temperature(76.42,TemperatureUnit(Fahrenheit
|
641 | 646 | INFO - * New Temperature 👍 --> Temperature(75.95,TemperatureUnit(Fahrenheit))
|
642 | 647 | ```
|
643 | 648 |
|
| 649 | +## Bidirectional streaming RPC service: `comingBackMode` |
| 650 | + |
| 651 | +To illustrate the bidirectional streaming, we are going to build a new service that makes the server react to real-time info provided by the client. In this case, as we said above, the client (the mobile app) will emit a stream of coordinates (latitude and longitude), and the server (the smart home) will trigger some actions according to the distance. |
| 652 | + |
| 653 | +### Protocol |
| 654 | + |
| 655 | +So let's add this service to the protocol. |
| 656 | + |
| 657 | +**_Messages.scala_** |
| 658 | + |
| 659 | +Adding new models: |
| 660 | + |
| 661 | +```scala |
| 662 | +case class Point(lat: Double, long: Double) |
| 663 | +case class Location(currentLocation: Point, destination: Point, distanceToDestination: Double) |
| 664 | +case class SmartHomeAction(description: String, isDone: Boolean) |
| 665 | +@message |
| 666 | +final case class ComingBackModeResponse(actions: List[SmartHomeAction]) |
| 667 | +``` |
| 668 | + |
| 669 | +**_SmartHomeService.scala_** |
| 670 | + |
| 671 | +And the `comingBackMode` operation: |
| 672 | + |
| 673 | +```scala |
| 674 | +@service(Protobuf) trait SmartHomeService[F[_]] { |
| 675 | + |
| 676 | + def isEmpty(request: IsEmptyRequest): F[IsEmptyResponse] |
| 677 | + |
| 678 | + def getTemperature(empty: Empty.type): Stream[F, Temperature] |
| 679 | + |
| 680 | + def comingBackMode(request: Stream[F, Location]): Stream[F, ComingBackModeResponse] |
| 681 | +} |
| 682 | +``` |
| 683 | + |
| 684 | +### Server |
| 685 | + |
| 686 | +So there is a new function to be implemented in the interpreter: |
| 687 | + |
| 688 | +```scala |
| 689 | +override def comingBackMode(request: Stream[F, Location]): Stream[F, ComingBackModeResponse] = |
| 690 | + for { |
| 691 | + _ <- Stream.eval(Logger[F].info(s"$serviceName - Enabling Coming Back Home mode")) |
| 692 | + location <- request |
| 693 | + _ <- Stream.eval( |
| 694 | + if (location.distanceToDestination > 0.0d) Logger[F].info(s"$serviceName - Distance to destination: ${location.distanceToDestination} mi") |
| 695 | + else Logger[F].info(s"$serviceName - You have reached your destination 🏡")) |
| 696 | + response <- Stream.eval(SmartHomeSupervisor[F].performAction(location)) |
| 697 | + } yield response |
| 698 | +``` |
| 699 | + |
| 700 | +### Client |
| 701 | + |
| 702 | +Again, if the client will emit a stream of locations, we should develop a producer, which as been created at `LocationGenerators`. No big deal, so far. But we have to add this operation in the `SmartHomeServiceApi`: |
| 703 | + |
| 704 | +```scala |
| 705 | +trait SmartHomeServiceApi[F[_]] { |
| 706 | + def isEmpty(): F[Boolean] |
| 707 | + def getTemperature(): Stream[F, Temperature] |
| 708 | + def comingBackMode(locations: Stream[F, Location]): F[Boolean] |
| 709 | +} |
| 710 | +``` |
| 711 | + |
| 712 | +Whose interpretation could be: |
| 713 | + |
| 714 | +```scala |
| 715 | +def comingBackMode(locations: Stream[F, Location]): Stream[F, ComingBackModeResponse] = for { |
| 716 | + client <- Stream.eval(clientF) |
| 717 | + response <- client.comingBackMode(locations) |
| 718 | +} yield response |
| 719 | +``` |
| 720 | + |
| 721 | +Now, we have all the ingredients to proceed in the ClientApp: |
| 722 | + |
| 723 | +```scala |
| 724 | +for { |
| 725 | + serviceApi <- SmartHomeServiceApi.createInstance(config.host.value, config.port.value) |
| 726 | + _ <- Stream.eval(serviceApi.isEmpty) |
| 727 | + summary <- serviceApi.getTemperature |
| 728 | + _ <- Stream.eval(Logger[F].info(s"The average temperature is: ${summary.averageTemperature}")) |
| 729 | + response <- serviceApi.comingBackMode(LocationsGenerator.get[F]) |
| 730 | +} yield response.actions |
| 731 | +``` |
| 732 | + |
| 733 | +### Result |
| 734 | + |
| 735 | +When we run the client now with `sbt runClient` we get: |
| 736 | + |
| 737 | +```bash |
| 738 | +INFO - 👀 - Waiting for a new location... |
| 739 | + |
| 740 | +INFO - 👀 - Waiting for a new location... |
| 741 | + |
| 742 | +INFO - 👀 - Waiting for a new location... |
| 743 | + |
| 744 | +INFO - 👀 - Waiting for a new location... |
| 745 | + |
| 746 | +INFO - 👮 - Enable security cameras |
| 747 | + |
| 748 | +INFO - 👀 - Waiting for a new location... |
| 749 | + |
| 750 | +INFO - 👀 - Waiting for a new location... |
| 751 | + |
| 752 | +INFO - 👀 - Waiting for a new location... |
| 753 | + |
| 754 | +INFO - 👀 - Waiting for a new location... |
| 755 | + |
| 756 | +INFO - 👀 - Waiting for a new location... |
| 757 | + |
| 758 | +INFO - 👀 - Waiting for a new location... |
| 759 | + |
| 760 | +INFO - 💦 - Disable irrigation system |
| 761 | + |
| 762 | +INFO - 🔌 - Send Rumba to the charging dock |
| 763 | + |
| 764 | +INFO - 🛋 - Start heating the living room |
| 765 | + |
| 766 | +INFO - 👀 - Waiting for a new location... |
| 767 | + |
| 768 | +INFO - 👀 - Waiting for a new location... |
| 769 | + |
| 770 | +INFO - 👀 - Waiting for a new location... |
| 771 | + |
| 772 | +INFO - 👀 - Waiting for a new location... |
| 773 | + |
| 774 | +INFO - 👀 - Waiting for a new location... |
| 775 | + |
| 776 | +INFO - 🔥 - Fireplace in ambient mode |
| 777 | + |
| 778 | +INFO - 🗞 - Get news summary |
| 779 | + |
| 780 | +INFO - 👀 - Waiting for a new location... |
| 781 | + |
| 782 | +INFO - 👀 - Waiting for a new location... |
| 783 | + |
| 784 | +INFO - 👀 - Waiting for a new location... |
| 785 | + |
| 786 | +INFO - 👀 - Waiting for a new location... |
| 787 | + |
| 788 | +INFO - 👀 - Waiting for a new location... |
| 789 | + |
| 790 | +INFO - 👀 - Waiting for a new location... |
| 791 | + |
| 792 | +INFO - 💧 - Increase the power of the hot water heater |
| 793 | + |
| 794 | +INFO - 🛁 - Turn the towel heaters on |
| 795 | + |
| 796 | +INFO - 👀 - Waiting for a new location... |
| 797 | + |
| 798 | +INFO - 👀 - Waiting for a new location... |
| 799 | + |
| 800 | +INFO - 👀 - Waiting for a new location... |
| 801 | + |
| 802 | +INFO - 👀 - Waiting for a new location... |
| 803 | + |
| 804 | +INFO - 👀 - Waiting for a new location... |
| 805 | + |
| 806 | +INFO - 👀 - Waiting for a new location... |
| 807 | + |
| 808 | +INFO - 😎 - Low the blinds |
| 809 | + |
| 810 | +INFO - 💡 - Turn on the lights |
| 811 | + |
| 812 | +INFO - 👀 - Waiting for a new location... |
| 813 | + |
| 814 | +INFO - 👀 - Waiting for a new location... |
| 815 | + |
| 816 | +INFO - 👀 - Waiting for a new location... |
| 817 | + |
| 818 | +INFO - 👀 - Waiting for a new location... |
| 819 | + |
| 820 | +INFO - 👀 - Waiting for a new location... |
| 821 | + |
| 822 | +INFO - 👀 - Waiting for a new location... |
| 823 | + |
| 824 | +INFO - 👩 - Connect Alexa |
| 825 | + |
| 826 | +INFO - 📺 - Turn on the TV |
| 827 | + |
| 828 | +INFO - 👀 - Waiting for a new location... |
| 829 | + |
| 830 | +INFO - 👀 - Waiting for a new location... |
| 831 | + |
| 832 | +INFO - 👀 - Waiting for a new location... |
| 833 | + |
| 834 | +INFO - 👀 - Waiting for a new location... |
| 835 | + |
| 836 | +INFO - 👀 - Waiting for a new location... |
| 837 | + |
| 838 | +INFO - 👀 - Waiting for a new location... |
| 839 | + |
| 840 | +INFO - 🔦 - Turn exterior lights on |
| 841 | + |
| 842 | +INFO - 👀 - Waiting for a new location... |
| 843 | + |
| 844 | +INFO - 👀 - Waiting for a new location... |
| 845 | + |
| 846 | +INFO - 👀 - Waiting for a new location... |
| 847 | + |
| 848 | +INFO - 🚪 - Unlock doors |
| 849 | + |
| 850 | +INFO - Removed 1 RPC clients from cache. |
| 851 | +``` |
| 852 | + |
| 853 | +And the server log the request as expected: |
| 854 | + |
| 855 | +```bash |
| 856 | +INFO - SmartHomeService - Enabling Coming Back Home mode |
| 857 | +INFO - SmartHomeService - Distance to destination: 6.39 mi |
| 858 | +INFO - SmartHomeService - Distance to destination: 6.26 mi |
| 859 | +INFO - SmartHomeService - Distance to destination: 6.13 mi |
| 860 | +INFO - SmartHomeService - Distance to destination: 6.0 mi |
| 861 | +INFO - SmartHomeService - Distance to destination: 5.87 mi |
| 862 | +INFO - SmartHomeService - Distance to destination: 5.74 mi |
| 863 | +INFO - SmartHomeService - Distance to destination: 5.61 mi |
| 864 | +INFO - SmartHomeService - Distance to destination: 5.48 mi |
| 865 | +INFO - SmartHomeService - Distance to destination: 5.35 mi |
| 866 | +INFO - SmartHomeService - Distance to destination: 5.22 mi |
| 867 | +INFO - SmartHomeService - Distance to destination: 5.09 mi |
| 868 | +INFO - SmartHomeService - Distance to destination: 4.96 mi |
| 869 | +INFO - SmartHomeService - Distance to destination: 4.83 mi |
| 870 | +INFO - SmartHomeService - Distance to destination: 4.7 mi |
| 871 | +INFO - SmartHomeService - Distance to destination: 4.57 mi |
| 872 | +INFO - SmartHomeService - Distance to destination: 4.44 mi |
| 873 | +INFO - SmartHomeService - Distance to destination: 4.31 mi |
| 874 | +INFO - SmartHomeService - Distance to destination: 4.18 mi |
| 875 | +INFO - SmartHomeService - Distance to destination: 4.05 mi |
| 876 | +INFO - SmartHomeService - Distance to destination: 3.91 mi |
| 877 | +INFO - SmartHomeService - Distance to destination: 3.78 mi |
| 878 | +INFO - SmartHomeService - Distance to destination: 3.65 mi |
| 879 | +INFO - SmartHomeService - Distance to destination: 3.52 mi |
| 880 | +INFO - SmartHomeService - Distance to destination: 3.39 mi |
| 881 | +INFO - SmartHomeService - Distance to destination: 3.26 mi |
| 882 | +INFO - SmartHomeService - Distance to destination: 3.13 mi |
| 883 | +INFO - SmartHomeService - Distance to destination: 3.0 mi |
| 884 | +INFO - SmartHomeService - Distance to destination: 2.87 mi |
| 885 | +INFO - SmartHomeService - Distance to destination: 2.74 mi |
| 886 | +INFO - SmartHomeService - Distance to destination: 2.61 mi |
| 887 | +INFO - SmartHomeService - Distance to destination: 2.48 mi |
| 888 | +INFO - SmartHomeService - Distance to destination: 2.35 mi |
| 889 | +INFO - SmartHomeService - Distance to destination: 2.22 mi |
| 890 | +INFO - SmartHomeService - Distance to destination: 2.09 mi |
| 891 | +INFO - SmartHomeService - Distance to destination: 1.96 mi |
| 892 | +INFO - SmartHomeService - Distance to destination: 1.83 mi |
| 893 | +INFO - SmartHomeService - Distance to destination: 1.7 mi |
| 894 | +INFO - SmartHomeService - Distance to destination: 1.57 mi |
| 895 | +INFO - SmartHomeService - Distance to destination: 1.44 mi |
| 896 | +INFO - SmartHomeService - Distance to destination: 1.3 mi |
| 897 | +INFO - SmartHomeService - Distance to destination: 1.17 mi |
| 898 | +INFO - SmartHomeService - Distance to destination: 1.04 mi |
| 899 | +INFO - SmartHomeService - Distance to destination: 0.91 mi |
| 900 | +INFO - SmartHomeService - Distance to destination: 0.78 mi |
| 901 | +INFO - SmartHomeService - Distance to destination: 0.65 mi |
| 902 | +INFO - SmartHomeService - Distance to destination: 0.52 mi |
| 903 | +INFO - SmartHomeService - Distance to destination: 0.39 mi |
| 904 | +INFO - SmartHomeService - Distance to destination: 0.26 mi |
| 905 | +INFO - SmartHomeService - Distance to destination: 0.13 mi |
| 906 | +INFO - SmartHomeService - You have reached your destination 🏡 |
| 907 | +``` |
| 908 | + |
644 | 909 | <!-- DOCTOC SKIP -->
|
645 | 910 | # Copyright
|
646 | 911 |
|
|
0 commit comments