[
  {
    "path": ".gitignore",
    "content": "\n# Created by https://www.gitignore.io/api/linux,macos,windows\n\n### Linux ###\n*~\n\n# temporary files which can be created if a process still has a handle open of a deleted file\n.fuse_hidden*\n\n# KDE directory preferences\n.directory\n\n# Linux trash folder which might appear on any partition or disk\n.Trash-*\n\n# .nfs files are created when an open file is removed but is still being accessed\n.nfs*\n\n### macOS ###\n*.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n### Windows ###\n# Windows thumbnail cache files\nThumbs.db\nehthumbs.db\nehthumbs_vista.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n\n# End of https://www.gitignore.io/api/linux,macos,windows\nBinaries\nGrpcIncludes\nGrpcLibraries\nGrpcPrograms\nIntermediate\n\n# grpc source codes\ngrpc\n"
  },
  {
    "path": "InfraworldRuntime.uplugin",
    "content": "{\n\t\"FileVersion\": 3,\n\t\"Version\": 1,\n\t\"VersionName\": \"1.0\",\n\t\"FriendlyName\": \"Infraworld Runtime\",\n\t\"Description\": \"Infraworld is a solution that enables Unreal Engine 4 to work with Google gRPC services from either C++ or Blueprints\",\n\t\"Category\": \"Networking\",\n\t\"CreatedBy\": \"Vizor Games LLC\",\n\t\"CreatedByURL\": \"http://vizor-interactive.com/en/\",\n\t\"DocsURL\": \"http://vizor-interactive.com/en/\",\n\t\"MarketplaceURL\": \"\",\n\t\"SupportURL\": \"mailto:roman.chehowski@vizor-games.com\",\n\t\"CanContainContent\": false,\n\t\"IsBetaVersion\": false,\n\t\"Installed\": false,\n\t\"Modules\": [\n\t\t{\n\t\t\t\"Name\": \"InfraworldRuntime\",\n\t\t\t\"Type\": \"Runtime\",\n\t\t\t\"LoadingPhase\": \"PreDefault\"\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2018 Vizor Games LLC\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "Vizor Infraworld\n================\n\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Maintainability](https://api.codeclimate.com/v1/badges/d8740022fdc1bbc8277b/maintainability)](https://codeclimate.com/github/vizor-games/InfraworldRuntime/maintainability)\n\nWelcome to the Infraworld source code!\n\n![](icon.png)\n\nInfraworld is a solution that enables [Unreal Engine 4](https://www.unrealengine.com/en-US) to work with [Google gRPC](https://gRPC.io) services using either **C++** or **Blueprints**.\n\nInfraworld is a fast, robust and cross platform.\nIt fits any stage of development: either prototyping or production. Saving a tons of your team's time, you need to write your gRPC wrappers by hand no more.\n[A special converter utility](https://github.com/vizor-games/infraworld-cornerstone) will do it for you, producing high quality, debuggable and multi-threaded code, gaining lowest possible overhead to your game logic thread.\nYou may also work with either generated or shipped with gRPC C functions and C++ classes in your own way, even completely ignoring runtime classes, since the InfraworldRuntime adds all required headers and wires all required libraries.\n\nAlso, you may want to use a [protobuild](https://github.com/vizor-games/infraworld-protobuild) utility to automate cross-language gRPC wrapper generation.\n\n\nGetting started\n===============\n\n##### Building gRPC support\n\nAt the first step, you need to build gRPC runtime libraries.\nJust run `Setup.sh` for Linux, `Setup.bat` for Windows or `Setup.command` for macOS (please don't use `Setup.sh` on macOS, because Linux and macOS build pipelines are completely different!). OR you may want to use our sweet [pre-compiled binaries](../../releases) to avoid manual building and save our planet from carbon emission disaster! The runtime uses gRPC branch `v1.23.x`.\n\n* For Windows, we recommend you to use [chocolatey](https://chocolatey.org) to install packages into your system.\n**Note** that you do need all these programs in your system's `PATH` ([See how to edit PATH on Windows](https://www.computerhope.com/issues/ch000549.htm)):\n  * [Git VCS](https://git-scm.com/download/win)\n  * [Visual Studio 2017](https://visualstudio.microsoft.com/downloads/) with VC++ tools v141 installed\n  * [CMake](https://cmake.org) is used to generate a Visual Studio solution from the `CMakeLists.txt` provided with gRPC\n  * [Strawberry perl](http://strawberryperl.com) 64bit version\n  * [NASM](https://www.nasm.us)\n  * [Golang](https://golang.org/doc/install)\n* For any distribution of Linux and for macOS systems you need (use `apt`, `pacman`, `emerge` or any other package manager to install this software):\n  * git\n  * automake, autoconf and libtool\n  * make\n  * strip\n  * go\n  * [Unreal Engine 4.22 installed](https://github.com/EpicGames/UnrealEngine/tree/4.22), additionally you need to `export UE_ROOT=/path/to/root/ue4/directory`, because you need UE4 to build GRPC for linux.\n* For macOS (use `homebrew` or `macports` to install this software):\n  * git\n  * xCode 10.0+\n  * go\n\n**Note** that required programs for Linux and MacOS systems are being checked in run-time.\n\nThen you may (or may not) import `GrpcIncludes` and `GrpcLibraries` folders into your VCS, but you need to build them manually at least one time for each platform.\nThe build process requires an access to the Internet.\n\n##### Installing the plugin\nJust copy the resulting folder into the your project’s Plugins folder (create it if you don’t have one).\nThen, after that project is being opened, a dialog box, telling that the plugin is need to be compiled should appear. Then confirm the dialog by clicking `Yes`.\n\n##### Building and the converter\nPlease take a look at the [infraworld-cornerstone documentation](https://github.com/vizor-games/infraworld-cornerstone) for details.\n\n##### Using generated code.\nPlease take a look at the [example project](https://drive.google.com/open?id=13EZzP_9033vBC7VzJf9LFrygg42LHaOW) for tutorial.\n\nRunning the example project\n===========================\n\nYou should copy built plugin's folder into `InfraworldRuntimeExample/Plugins` folder.\nThen just open `InfraworldDemo.uproject`. Server code is in `DemoServer` folder.\nYou are required to install dependencies using `pip` and `requirements.txt` file.\nFor more details please check our [**InfraworldExample**](https://github.com/vizor-games/InfraworldRuntimeExample) repository\n\nDebugging\n=========\n\nSince the plugin itself is an open source software, you may want to debug it or add some extra functionality.\nSince it is distributed as an Unreal Engine plugin, you can add it into your own game\nand then generate **Visual Studio solution**, **XCode project** or **CMakeLists**. Use `Development` or `DebugGame` run configuration!\n\nContribution\n============\n\nPlease feel free to report known bugs, propose new features and improve tests using Github's pull request system.\nPlease do not add either build libraries for an any platform or header files into your commits. Thank you very much for contributing into free software.\n\nReferences\n==========\n* [Introduction to UE4 Plugins](https://wiki.unrealengine.com/An_Introduction_to_UE4_Plugins)\n* [gRPC API docs](https://gRPC.io/docs/)\n"
  },
  {
    "path": "Setup.bat",
    "content": "@echo off\n\n::#####################################VARS#############################################################################\nset SCRIPT_FOLDER=%cd%\n\nset GRPC_ROOT=%SCRIPT_FOLDER%\\grpc\nset GRPC_INCLUDE_DIR=%SCRIPT_FOLDER%\\GrpcIncludes\nset GRPC_LIBRARIES_DIR=%SCRIPT_FOLDER%\\GrpcLibraries\\Win64\nset GRPC_PROGRAMS_DIR=%SCRIPT_FOLDER%\\GrpcPrograms\\Win64\n\nset CMAKE_BUILD_DIR=%GRPC_ROOT%\\.build\n\nset REMOTE_ORIGIN=https://github.com/grpc/grpc.git\nset BRANCH=v1.23.x\n::#####################################VARS#############################################################################\n\n:GET_UE_ROOT\nIF \"%UE_ROOT%\" == \"\" (echo \"UE_ROOT directory does not exist, please set correct UE_ROOT via SET UE_ROOT=<PATH_TO_UNREAL_ENGINE_FOLDER>\" && GOTO ABORT)\n\n:CLEAN\necho \">>>>>>>>>> clean\"\nIF EXIST \"%GRPC_ROOT%\" (cd \"%GRPC_ROOT%\" && git clean -fdx && git submodule foreach git clean -fdx && cd \"%SCRIPT_FOLDER%\") \nIF EXIST \"%GRPC_INCLUDE_DIR%\" (rmdir \"%GRPC_INCLUDE_DIR%\" /s /q)\nIF EXIST \"%GRPC_LIBRARIES_DIR%\" (rmdir \"%GRPC_LIBRARIES_DIR%\" /s /q)\nIF EXIST \"%GRPC_PROGRAMS_DIR%\" (rmdir \"%GRPC_PROGRAMS_DIR%\" /s /q)\n\n:CLONE_OR_PULL\necho \">>>>>>>>>> clone git\"\nif EXIST \"%GRPC_ROOT%\" (cd \"%GRPC_ROOT%\" && echo Pulling repo && git pull) else (call git clone \"%REMOTE_ORIGIN%\" && cd \"%GRPC_ROOT%\")\n\ngit fetch\ngit checkout -f\ngit checkout -t origin/%BRANCH%\ngit submodule update --init\n\n:BUILD_ALL\nmkdir \"%CMAKE_BUILD_DIR%\" && cd \"%CMAKE_BUILD_DIR%\"\ncall cmake .. -G \"Visual Studio 16 2019\" -A x64 ^\n    -DCMAKE_CXX_STANDARD_LIBRARIES=\"Crypt32.Lib User32.lib Advapi32.lib\" ^\n    -DCMAKE_BUILD_TYPE=Release ^\n    -DCMAKE_CONFIGURATION_TYPES=Release ^\n    -Dprotobuf_BUILD_TESTS=OFF ^\n    -DgRPC_ZLIB_PROVIDER=package ^\n    -DZLIB_INCLUDE_DIR=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\zlib\\v1.2.8\\include\\Win64\\VS2015\" ^\n    -DZLIB_LIBRARY_DEBUG=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\zlib\\v1.2.8\\lib\\Win64\\VS2015\\Debug\\zlibstatic.lib\" ^\n    -DZLIB_LIBRARY_RELEASE=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\zlib\\v1.2.8\\lib\\Win64\\VS2015\\Release\\zlibstatic.lib\" ^\n    -DgRPC_SSL_PROVIDER=package ^\n    -DLIB_EAY_LIBRARY_DEBUG=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\OpenSSL\\1.1.1\\Lib\\Win64\\VS2015\\Debug\\libcrypto.lib\" ^\n    -DLIB_EAY_LIBRARY_RELEASE=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\OpenSSL\\1.1.1\\Lib\\Win64\\VS2015\\Release\\libcrypto.lib\" ^\n    -DLIB_EAY_DEBUG=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\OpenSSL\\1.1.1\\Lib\\Win64\\VS2015\\Debug\\libcrypto.lib\" ^\n    -DLIB_EAY_RELEASE=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\OpenSSL\\1.1.1\\Lib\\Win64\\VS2015\\Release\\libcrypto.lib\" ^\n    -DOPENSSL_INCLUDE_DIR=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\OpenSSL\\1.1.1\\include\\Win64\\VS2015\" ^\n    -DSSL_EAY_DEBUG=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\OpenSSL\\1.1.1\\Lib\\Win64\\VS2015\\Debug\\libssl.lib\" ^\n    -DSSL_EAY_LIBRARY_DEBUG=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\OpenSSL\\1.1.1\\Lib\\Win64\\VS2015\\Debug\\libssl.lib\" ^\n    -DSSL_EAY_LIBRARY_RELEASE=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\OpenSSL\\1.1.1\\Lib\\Win64\\VS2015\\Release\\libssl.lib\" ^\n    -DSSL_EAY_RELEASE=\"%UE_ROOT%\\Engine\\Source\\ThirdParty\\OpenSSL\\1.1.1\\Lib\\Win64\\VS2015\\Release\\libssl.lib\"\ncall cmake --build . --target ALL_BUILD --config Release\n\n:COPY_HEADERS\necho \">>>>>>>>>> copy headers\"\nrobocopy \"%GRPC_ROOT%\\include\" \"%GRPC_INCLUDE_DIR%\\include\" /E\nrobocopy \"%GRPC_ROOT%\\third_party\\protobuf\\src\" \"%GRPC_INCLUDE_DIR%\\third_party\\protobuf\\src\" /E\n\n:PATCH_HEADERS\necho \">>>>>>>>>> copy headers\"\nset GENERATED_MESSAGE_TABLE_DRIVEN_FILE=\"%SCRIPT_FOLDER%\\third_party\\protobuf\\src\\google\\protobuf\\\"\n\n:COPY_LIBRARIES\necho \">>>>>>>>>> copy libraries\"\nrobocopy \"%CMAKE_BUILD_DIR%\\Release\" \"%GRPC_LIBRARIES_DIR%\" *.lib /R:0 /S\nrobocopy \"%CMAKE_BUILD_DIR%\\third_party\\cares\\cares\\lib\\Release\" \"%GRPC_LIBRARIES_DIR%\" *.lib /R:0 /S\nrobocopy \"%CMAKE_BUILD_DIR%\\third_party\\benchmark\\src\\Release\" \"%GRPC_LIBRARIES_DIR%\" *.lib /R:0 /S\nrobocopy \"%CMAKE_BUILD_DIR%\\third_party\\gflags\\Release\" \"%GRPC_LIBRARIES_DIR%\" *.lib /R:0 /S\nrobocopy \"%CMAKE_BUILD_DIR%\\third_party\\protobuf\\Release\" \"%GRPC_LIBRARIES_DIR%\" *.lib /R:0 /S\n\n:COPY_PROGRAMS\necho \">>>>>>>>>> copy programs\"\nrobocopy \"%CMAKE_BUILD_DIR%\\Release\" \"%GRPC_PROGRAMS_DIR%\" *.exe /R:0 /S\ncopy \"%CMAKE_BUILD_DIR%\\third_party\\protobuf\\Release\\protoc.exe\" \"%GRPC_PROGRAMS_DIR%\\protoc.exe\"\n\n:REMOVE_USELESS_LIBRARIES\necho \">>>>>>>>>> remove useless libraries\"\ndel \"%GRPC_LIBRARIES_DIR%\\grpc_csharp_ext.lib\"\ndel \"%GRPC_LIBRARIES_DIR%\\gflags_static.lib\"\ndel \"%GRPC_LIBRARIES_DIR%\\gflags_nothreads_static.lib\"\ndel \"%GRPC_LIBRARIES_DIR%\\benchmark.lib\"\n\n:Finish\necho \">>>>>>>>>> finish\"\ncd \"%SCRIPT_FOLDER%\"\nGOTO GRACEFULEXIT\n\n:ABORT\npause\necho Aborted...\n\n:GRACEFULEXIT\necho Build done!\n"
  },
  {
    "path": "Setup.command",
    "content": "#!/bin/bash\n\n# Exit on errors if any\nset -e\n\n###############################################################################\n# Should be defined as an environment variable, will be v1.3.x otherwise\nbranch=${branch:-v1.23.x}\nclean=${clean:-true}\n\nVAR_GIT_BRANCH=$branch\nVAR_CLEAR_REPO=$clean\n\nREMOTE_ORIGIN=\"https://github.com/grpc/grpc.git\"\nGOSUPPORT_REMOTE_ORIGIN=\"https://github.com/golang/protobuf.git\"\n\nSCRIPT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nGRPC_FOLDER_NAME=grpc\nGRPC_ROOT=\"${SCRIPT_DIR}/${GRPC_FOLDER_NAME}\"\n\nCMAKE_BUILD_DIR=\"${GRPC_ROOT}/.build\"\n\nDEPS=(git automake autoconf libtool make strip clang++ go)\n###############################################################################\n\necho \"SCRIPT_DIR=${SCRIPT_DIR}\"\necho \"GRPC_ROOT=${GRPC_ROOT}\"\n\nUE_ROOT=${UE_ROOT:-\"/var/lib/jenkins/UE_4.20.2-release\"}\n\nif [ ! -d \"$UE_ROOT\" ]; then\n    echo \"UE_ROOT directory ${UE_ROOT} does not exist, please set correct UE_ROOT\"\n    exit 1\nfi;\n\n# Check if all tools are installed\nfor i in ${DEPS[@]}; do\n    if [ ! \"$(which ${i})\" ];then\n       echo \"${i} not found, install via 'brew install ${i}'\" && exit 1\n    fi\ndone\n\n# Check if ran under Darwin\nif [ $(uname) != 'Darwin' ]; then\n    echo \"Can not work under $(uname) operating system, should be Darwin! Exiting...\"\n    exit 1\nfi;\n\n# Clone or pull\nif [ ! -d \"$GRPC_ROOT\" ]; then\n    echo \"Cloning repo into ${GRPC_ROOT}\"\n    git clone $REMOTE_ORIGIN $GRPC_ROOT\nelse\n    # [[ ${VAR_CLEAR_REPO} ]] && cd $GRPC_ROOT && git merge --abort || true; git clean -fdx && git checkout -f .\n    echo \"Pulling repo\"\n    (cd $GRPC_ROOT && git pull)\nfi\n\necho \"Checking out branch ${VAR_GIT_BRANCH}\"\n(cd $GRPC_ROOT && git fetch)\n(cd $GRPC_ROOT && git checkout -f)\n(cd $GRPC_ROOT && git checkout -t origin/$VAR_GIT_BRANCH || true)\n\n# Update submodules\n(cd $GRPC_ROOT && git submodule update --init)\n\nif [ \"$VAR_CLEAR_REPO\" = \"true\" ]; then\n    echo \"Cleaning repo and submodules because VAR_CLEAR_REPO is set to ${VAR_CLEAR_REPO}\"\n    (cd $GRPC_ROOT && make clean)\n    (cd $GRPC_ROOT && git clean -fdx)\n    (cd $GRPC_ROOT && git submodule foreach git clean -fdx)\nelif [ \"$VAR_CLEAR_REPO\" = \"false\" ]; then\n    echo \"Cleaning is not needed!\"\nelse\n    echo \"Undefined behaviour, VAR_CLEAR_REPO is ${VAR_CLEAR_REPO}!\"\n    exit 1\nfi\n\n# Copy INCLUDE folders, should copy:\n#   - grpc/include\n#   - grpc/third_party/protobuf/src\nHEADERS_DIR=\"${SCRIPT_DIR}/GrpcIncludes\"\nPROTOBUF_SRC_DIR=\"${HEADERS_DIR}/third_party/protobuf\"\n\n# (re)-create headers directory\nif [ -d \"$HEADERS_DIR\" ]; then\n    printf '%s\\n' \"Removing old $HEADERS_DIR\"\n    rm -rf \"$HEADERS_DIR\"\nfi\n\nmkdir $HEADERS_DIR\nmkdir -p $PROTOBUF_SRC_DIR\n\ncp -R \"${GRPC_ROOT}/include\" $HEADERS_DIR\ncp -R \"${GRPC_ROOT}/third_party/protobuf/src\" $PROTOBUF_SRC_DIR\n\n# Build all\nif [ -d \"${CMAKE_BUILD_DIR}\" ]; then\n    printf '%s\\n' \"Removing old ${CMAKE_BUILD_DIR}\"\n    rm -rf \"${CMAKE_BUILD_DIR}\"\nfi\nmkdir -p ${CMAKE_BUILD_DIR} && cd ${CMAKE_BUILD_DIR}\necho \"BUILD STARTED!\"\ncmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CONFIGURATION_TYPES=Release -Dprotobuf_BUILD_TESTS=OFF -DgRPC_ZLIB_PROVIDER=package -DZLIB_INCLUDE_DIR=${UE_ROOT}/Engine/Source/ThirdParty/zlib/v1.2.8/include/Mac -DZLIB_LIBRARY_DEBUG=${UE_ROOT}/Engine/Source/ThirdParty/zlib/v1.2.8/lib/Mac/libz.a -DZLIB_LIBRARY_RELEASE=${UE_ROOT}/Engine/Source/ThirdParty/zlib/v1.2.8/lib/Mac/libz.a -DgRPC_SSL_PROVIDER=package -DLIB_EAY_LIBRARY_DEBUG=${UE_ROOT}/Engine/Source/ThirdParty/OpenSSL/1.0.2g/lib/Mac/Debug/libcrypto.a -DLIB_EAY_LIBRARY_RELEASE=${UE_ROOT}/Engine/Source/ThirdParty/OpenSSL/1.0.2g/lib/Mac/Release/libcrypto.a -DLIB_EAY_DEBUG=${UE_ROOT}/Engine/Source/ThirdParty/OpenSSL/1.0.2g/lib/Mac/Debug/libcrypto.a -DLIB_EAY_RELEASE=${UE_ROOT}/Engine/Source/ThirdParty/OpenSSL/1.0.2g/lib/Mac/Release/libcrypto.a -DOPENSSL_INCLUDE_DIR=${UE_ROOT}/Engine/Source/ThirdParty/OpenSSL/1.0.2g/include/Mac -DSSL_EAY_DEBUG=${UE_ROOT}/Engine/Source/ThirdParty/OpenSSL/1.0.2g/lib/Mac/Debug/libssl.a -DSSL_EAY_LIBRARY_DEBUG=${UE_ROOT}/Engine/Source/ThirdParty/OpenSSL/1.0.2g/lib/Mac/Debug/libssl.a -DSSL_EAY_LIBRARY_RELEASE=${UE_ROOT}/Engine/Source/ThirdParty/OpenSSL/1.0.2g/lib/Mac/Release/libssl.a -DSSL_EAY_RELEASE=${UE_ROOT}/Engine/Source/ThirdParty/OpenSSL/1.0.2g/lib/Mac/Release/libssl.a\nmake\ncd ${SCRIPT_DIR}\n\n# Copy artifacts\nLIBS_DIR=\"${SCRIPT_DIR}/GrpcLibraries\"\nBIN_DIR=\"${SCRIPT_DIR}/GrpcPrograms\"\n\necho \"LIBS_DIR is ${LIBS_DIR}\"\necho \"BIN_DIR is ${BIN_DIR}\"\n\nARCH_LIBS_DIR=\"${LIBS_DIR}/Mac\"\nARCH_BIN_DIR=\"${BIN_DIR}/Mac\"\n\necho \"ARCH_LIBS_DIR is ${ARCH_LIBS_DIR}\"\necho \"ARCH_BIN_DIR is ${ARCH_BIN_DIR}\"\n\n# Remove old libs and binaries directories\nif [ -d \"$ARCH_LIBS_DIR\" ]; then\n    printf '%s\\n' \"Removing old $ARCH_LIBS_DIR\"\n    rm -rf \"$ARCH_LIBS_DIR\"\nfi\nif [ -d \"$ARCH_BIN_DIR\" ]; then\n    printf '%s\\n' \"Removing old $ARCH_BIN_DIR\"\n    rm -rf \"$ARCH_BIN_DIR\"\nfi\n\n# Create platform-specific artifacts directory\nmkdir -p $ARCH_LIBS_DIR\nmkdir -p $ARCH_BIN_DIR\n\nSRC_LIBS_FOLDER=${CMAKE_BUILD_DIR}\necho \"SRC_LIBS_FOLDER=${SRC_LIBS_FOLDER}\"\nif [ -d \"$SRC_LIBS_FOLDER\" ]; then\n    echo \"Copying grpc libraries from ${SRC_LIBS_FOLDER} to ${ARCH_LIBS_DIR}\"\n    (cd $SRC_LIBS_FOLDER && find . -name '*.a' -exec cp -vf '{}' $ARCH_LIBS_DIR \";\")\nfi\n\n# Strip all symbols from libraries\n(cd $ARCH_LIBS_DIR && strip -S *.a)\n\n# Copy binaries (plugins & protoc)\necho \"Copying executables to ${ARCH_BIN_DIR}\"\ncp ${SRC_LIBS_FOLDER}/grpc_cpp_plugin ${ARCH_BIN_DIR}/\ncp ${SRC_LIBS_FOLDER}/grpc_csharp_plugin ${ARCH_BIN_DIR}/\ncp ${SRC_LIBS_FOLDER}/grpc_node_plugin ${ARCH_BIN_DIR}/\ncp ${SRC_LIBS_FOLDER}/grpc_objective_c_plugin ${ARCH_BIN_DIR}/\ncp ${SRC_LIBS_FOLDER}/grpc_php_plugin ${ARCH_BIN_DIR}/\ncp ${SRC_LIBS_FOLDER}/grpc_python_plugin ${ARCH_BIN_DIR}/\ncp ${SRC_LIBS_FOLDER}/grpc_ruby_plugin ${ARCH_BIN_DIR}/\ncp ${SRC_LIBS_FOLDER}/third_party/protobuf/protoc ${ARCH_BIN_DIR}/\n\nGOROOT_DIR=\"${GRPC_ROOT}/go_packages\"\nGOPROTO_DIR=\"${GOROOT_DIR}/src/github.com/golang/protobuf\"\n\necho \"Building golang support in ${GOPROTO_DIR}\"\n\nif [ ! -d \"${GOPROTO_DIR}\" ]; then\n    (cd $GRPC_ROOT && git clone $GOSUPPORT_REMOTE_ORIGIN $GOPROTO_DIR)\nelse\n    (cd $GOPROTO_DIR && git pull)\nfi\n\n# Add gopath with protobuf libs\nexport GOPATH=$GOROOT_DIR\n\n# Run go build\n(cd \"${GOPROTO_DIR}/protoc-gen-go\" && go build)\n(cp \"${GOPROTO_DIR}/protoc-gen-go/protoc-gen-go\" $ARCH_BIN_DIR)\n\n# Finally, strip binaries (programs)\n(cd $ARCH_BIN_DIR && strip -S *)\n\necho 'BUILD DONE!'\n"
  },
  {
    "path": "Setup.sh",
    "content": "#!/bin/bash\n\n# Exit on errors if any\nset -e\n\n###############################################################################\n# Should be defined as an environment variable, will be v1.3.x otherwise\nbranch=${branch:-v1.23.x}\nclean=${clean:-true}\n\nVAR_GIT_BRANCH=$branch\nVAR_CLEAR_REPO=$clean\n\nREMOTE_ORIGIN=\"https://github.com/grpc/grpc.git\"\nGOSUPPORT_REMOTE_ORIGIN=\"https://github.com/golang/protobuf.git\"\n\nSCRIPT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nGRPC_FOLDER_NAME=grpc\nGRPC_ROOT=\"${SCRIPT_DIR}/${GRPC_FOLDER_NAME}\"\n\nDEPS=(git automake autoconf libtool make strip go pkg-config)\n\n# Linux needs an existing UE installation\nUE_ROOT=${UE_ROOT:-\"/var/lib/jenkins/UE_4.20.2-release\"}\n\nif [ ! -d \"$UE_ROOT\" ]; then\n    echo \"UE_ROOT directory ${UE_ROOT} does not exist, please set correct UE_ROOT\"\n    exit 1\nfi;\n\nUE_PREREQUISITES=\"${UE_ROOT}/Engine/Extras/ThirdPartyNotUE/SDKs/HostLinux/Linux_x64/v13_clang-7.0.1-centos7/x86_64-unknown-linux-gnu\"\n###############################################################################\n\nOPENSSL_LIB=\"${UE_ROOT}/Engine/Source/ThirdParty/OpenSSL/1_0_2h/lib/Linux/x86_64-unknown-linux-gnu\"\nOPENSSL_INCLUDE=\"${UE_ROOT}/Engine/Source/ThirdParty/OpenSSL/1_0_2h/include/Linux/x86_64-unknown-linux-gnu\"\n\necho \"SCRIPT_DIR=${SCRIPT_DIR}\"\necho \"GRPC_ROOT=${GRPC_ROOT}\"\n\n# Check if all tools are installed\nfor i in ${DEPS[@]}; do\n    if [ ! \"$(which ${i})\" ];then\n       echo \"${i} not found, install via 'apt-get install ${i}'\" && exit 1\n    fi\ndone\n\n# Check if ran under Linux\nif [ $(uname) != 'Linux' ]; then\n    echo \"Can not work under $(uname) operating system, should be Linux! Exiting...\"\n    exit 1\nfi;\n\n# Clone or pull\nif [ ! -d \"$GRPC_ROOT\" ]; then\n    echo \"Cloning repo into ${GRPC_ROOT}\"\n    git clone $REMOTE_ORIGIN $GRPC_ROOT\nelse\n    # [[ ${VAR_CLEAR_REPO} ]] && cd $GRPC_ROOT && git merge --abort || true; git clean -fdx && git checkout -f .\n    echo \"Pulling repo\"\n    (cd $GRPC_ROOT && git pull)\nfi\n\necho \"Checking out branch ${VAR_GIT_BRANCH}\"\n(cd $GRPC_ROOT && git fetch)\n(cd $GRPC_ROOT && git checkout -f)\n(cd $GRPC_ROOT && git checkout -t origin/$VAR_GIT_BRANCH || true)\n\n# Update submodules\n(cd $GRPC_ROOT && git submodule update --init)\n\nif [ \"$VAR_CLEAR_REPO\" = \"true\" ]; then\n    echo \"Cleaning repo and submodules because VAR_CLEAR_REPO is set to ${VAR_CLEAR_REPO}\"\n    (cd $GRPC_ROOT && make clean)\n    (cd $GRPC_ROOT && git clean -fdx)\n    (cd $GRPC_ROOT && git submodule foreach git clean -fdx)\nelif [ \"$VAR_CLEAR_REPO\" = \"false\" ]; then\n    echo \"Cleaning is not needed!\"\nelse\n    echo \"Undefined behaviour, VAR_CLEAR_REPO is ${VAR_CLEAR_REPO}!\"\n    exit 1\nfi\n\n# Copy INCLUDE folders, should copy:\n#   - grpc/include\n#   - grpc/third_party/protobuf/src\nHEADERS_DIR=\"${SCRIPT_DIR}/GrpcIncludes\"\nPROTOBUF_SRC_DIR=\"${HEADERS_DIR}/third_party/protobuf\"\n\n# (re)-create headers directory\nif [ -d \"$HEADERS_DIR\" ]; then\n    printf '%s\\n' \"Removing old $HEADERS_DIR\"\n    rm -rf \"$HEADERS_DIR\"\nfi\n\nmkdir $HEADERS_DIR\nmkdir -p $PROTOBUF_SRC_DIR\n\ncp -R \"${GRPC_ROOT}/include\" $HEADERS_DIR\ncp -R \"${GRPC_ROOT}/third_party/protobuf/src\" $PROTOBUF_SRC_DIR\n\n# Compute arch string using uname\nUNAME_MACH=$(echo $(uname -m) | tr '[:upper:]' '[:lower:]')\nUNAME_OS=$(echo $(uname) | tr '[:upper:]' '[:lower:]')\nUNAME_ARCH=\"${UNAME_MACH}-unknown-${UNAME_OS}-gnu\"\n\nLIBCXX_UE_DIR=\"${UE_ROOT}/Engine/Source/ThirdParty/Linux/LibCxx/include\"\nLIBC_UE_DIR=\"${UE_ROOT}/Engine/Source/ThirdParty/Linux/LibCxx/include\"\n\nexport CC=\"${UE_PREREQUISITES}/bin/clang\"\nexport CC_FOR_BUILD=${CC}\nexport CXX=\"${UE_PREREQUISITES}/bin/clang++\"\nexport CXX_FOR_BUILD=${CXX}\n\n# we need this to avoid 'unknow flavor: old-gnu' error\nif [ ! -e \"${UE_PREREQUISITES}/bin/lld-gnu\" ]; then\n    ln -s \"${UE_PREREQUISITES}/bin/ld.lld\" \"${UE_PREREQUISITES}/bin/lld-gnu\"\nfi\n\nfind \"${UE_PREREQUISITES}/usr/lib64\" -name '*.o' -exec cp -vfs '{}' \"${UE_PREREQUISITES}/lib64\" \";\"\n\n# this thing avoid us from gcc usage, we don't need it\nexport VALID_CONFIG_gcov=0\n\n# force compile protobuf, libz and libares\nexport HAS_SYSTEM_CARES=false\nexport HAS_SYSTEM_PROTOBUF=false\nexport HAS_SYSTEM_ZLIB=false\n\n# funny, but in grpc Makefile LD and LDXX associated with compilers\nexport LD=\"${CC}\"\nexport LDXX=\"${CXX}\"\n\nexport DEFAULT_CC=\"${CC}\"\nexport DEFAULT_CXX=\"${CXX}\"\n\nexport CFLAGS=\"-fPIC -Wno-error --sysroot=${UE_PREREQUISITES}\"\nexport CFLAGS_FOR_BUILD=${CFLAGS}\nexport CXXFLAGS=\"-std=c++14 -fPIC -nostdinc++ -Wno-expansion-to-defined -Wno-error -I${LIBCXX_UE_DIR} -I${LIBCXX_UE_DIR}/c++/v1 -I${OPENSSL_INCLUDE}\"\nexport CXXFLAGS_FOR_BUILD=${CXXFLAGS}\n\nexport LIBRARY_PATH=\"${UE_PREREQUISITES}/usr/lib64\"\n\nexport LDFLAGS=\"-L${UE_ROOT}/Engine/Source/ThirdParty/Linux/LibCxx/lib/Linux/${UNAME_ARCH} -L${OPENSSL_LIB} -fuse-ld=${UE_PREREQUISITES}/bin/lld-gnu\"\nexport LDFLAGS_FOR_BUILD=${LDFLAGS}\n\nexport LDLIBS=\"-lc++ -lc++abi -lc\"\n\nexport PROTOBUF_LDFLAGS_EXTRA=\"${LDFLAGS} ${LDLIBS}\"\n\n# Create an alias 'clocale -> xlocale.h' (if does not exist)\nif [ ! -e \"${LIBCXX_UE_DIR}/c++/v1/xlocale.h\" ]; then\n    if [ ! -e \"${LIBCXX_UE_DIR}/c++/v1/clocale\" ]; then\n        echo \"${LIBCXX_UE_DIR}/c++/v1/clocale must exist in UE src dir. Exiting...\" && exit 1\n    fi\n\n    (cd \"${LIBCXX_UE_DIR}/c++/v1\" && ln -s clocale xlocale.h)\n    echo \"Created an alias to xlocale.h\"\nfi\n\necho \"CFLAGS=${CFLAGS}, CXXFLAGS=${CXXFLAGS}, LDFLAGS=${LDFLAGS}, LDLIBS=${LDLIBS}, PROTOBUF_LDFLAGS_EXTRA=${PROTOBUF_LDFLAGS_EXTRA}\"\n\n# Build GRPC\n(cd $GRPC_ROOT && make CC=${CC} CXX=${CXX})\n\n# Copy artifacts\nLIBS_DIR=\"${SCRIPT_DIR}/GrpcLibraries\"\nBIN_DIR=\"${SCRIPT_DIR}/GrpcPrograms\"\n\necho \"LIBS_DIR is ${LIBS_DIR}\"\necho \"BIN_DIR is ${BIN_DIR}\"\n\nif [ $(uname) != 'Darwin' ]; then\n    ARCH_LIBS_DIR=\"${LIBS_DIR}/\"$(uname)\n    ARCH_BIN_DIR=\"${BIN_DIR}/\"$(uname)\nelse\n    ARCH_LIBS_DIR=\"${LIBS_DIR}/Mac\"\n    ARCH_BIN_DIR=\"${BIN_DIR}/Mac\"\nfi\n\necho \"ARCH_LIBS_DIR is ${ARCH_LIBS_DIR}\"\necho \"ARCH_BIN_DIR is ${ARCH_BIN_DIR}\"\n\n# Remove old libs and binaries directories\nif [ -d \"$ARCH_LIBS_DIR\" ]; then\n    printf '%s\\n' \"Removing old $ARCH_LIBS_DIR\"\n    rm -rf \"$ARCH_LIBS_DIR\"\nfi\nif [ -d \"$ARCH_BIN_DIR\" ]; then\n    printf '%s\\n' \"Removing old $ARCH_BIN_DIR\"\n    rm -rf \"$ARCH_BIN_DIR\"\nfi\n\n# Create platform-specific artifacts directory\nmkdir -p $ARCH_LIBS_DIR\nmkdir -p $ARCH_BIN_DIR\n\nSRC_LIBS_FOLDER_GRPC=$GRPC_ROOT/libs/opt\nSRC_LIBS_FOLDER_PROTOBUF=$PROTOBUF_ROOT/src/.libs\n\n# Force recursively copy\nif [ -d \"$SRC_LIBS_FOLDER_PROTOBUF\" ]; then\n    echo \"Copying protobuf libraries from ${SRC_LIBS_FOLDER_PROTOBUF} to ${ARCH_LIBS_DIR}\"\n    (cd $SRC_LIBS_FOLDER_PROTOBUF && find . -name '*.a' -exec cp -vf '{}' $ARCH_LIBS_DIR \";\")\nfi\n\nif [ -d \"$SRC_LIBS_FOLDER_GRPC\" ]; then\n    echo \"Copying grpc libraries from ${SRC_LIBS_FOLDER_GRPC} to ${ARCH_LIBS_DIR}\"\n    (cd $SRC_LIBS_FOLDER_GRPC && find . -name '*.a' -exec cp -vf '{}' $ARCH_LIBS_DIR \";\")\nfi\n\n# Strip all symbols from libraries\n(cd $ARCH_LIBS_DIR && strip -S *.a)\n\n# Copy binaries (plugins & protoc)\necho \"Copying executables to ${ARCH_BIN_DIR}\"\n(cp -a \"${GRPC_ROOT}/bins/opt/.\" $ARCH_BIN_DIR)\n(cp -a \"${GRPC_ROOT}/bins/opt/protobuf/.\" $ARCH_BIN_DIR)\n\n# This seems to be a hack, should modify (cp -a \"${GRPC_ROOT}/bins/opt/.\" $BIN_DIR) to copy only files, bot dirs\n(cd $ARCH_BIN_DIR && rm -rf protobuf)\n\n#\n# Build go support\nGOROOT_DIR=\"${GRPC_ROOT}/go_packages\"\nGOPROTO_DIR=\"${GOROOT_DIR}/src/github.com/golang/protobuf\"\n\necho \"Building golang support in ${GOPROTO_DIR}\"\nif [ ! -d \"${GOPROTO_DIR}\" ]; then\n    (cd $GRPC_ROOT && git clone $GOSUPPORT_REMOTE_ORIGIN $GOPROTO_DIR)\nelse\n    (cd $GOPROTO_DIR && git pull)\nfi\n\n# Add gopath with protobuf libs\nexport GOPATH=$GOROOT_DIR\n\n#\n# Run go build\n(cd \"${GOPROTO_DIR}/protoc-gen-go\" && go build)\n(cp \"${GOPROTO_DIR}/protoc-gen-go/protoc-gen-go\" $ARCH_BIN_DIR)\n\n# Strip binaries (programs)\n(cd $ARCH_BIN_DIR && strip -S *)\n\n# Finnaly, clean all stuff\nrm \"${LIBCXX_UE_DIR}/c++/v1/xlocale.h\"\nrm \"${UE_PREREQUISITES}/bin/lld-gnu\"\nfind \"${UE_PREREQUISITES}/lib64\" -name '*.o' -type f -delete\n\n# Copy source\necho 'BUILD DONE!'\n"
  },
  {
    "path": "Source/InfraworldRuntime/InfraWorldRuntime.Build.cs",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n// #define TRACE\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Net.NetworkInformation;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing UnrealBuildTool;\n\npublic class InfraworldRuntime : ModuleRules\n{\n    private UnrealTargetPlatform Platform;\n    private UnrealTargetConfiguration Configuration;\n\n    // name of root folders in the project folder\n    private static readonly string GRPC_STRIPPED_FOLDER = \"GrpcIncludes\";\n    private static readonly string GRPC_LIBS_FOLDER = \"GrpcLibraries\";\n\n    private string INCLUDE_ROOT;\n    private string LIB_ROOT;\n\n    public class ModuleDepPaths\n    {\n        public readonly string[] HeaderPaths;\n        public readonly string[] LibraryPaths;\n\n        public ModuleDepPaths(string[] headerPaths, string[] libraryPaths)\n        {\n            HeaderPaths = headerPaths;\n            LibraryPaths = libraryPaths;\n        }\n\n        public override string ToString()\n        {\n            return \"Headers:\\n\" + string.Join(\"\\n\", HeaderPaths) + \"\\nLibs:\\n\" + string.Join(\"\\n\", LibraryPaths);\n        }\n    }\n\n    [Conditional(\"DEBUG\")]\n    [Conditional(\"TRACE\")]\n    private void clog(params object[] objects)\n    {\n        Console.WriteLine(string.Join(\", \", objects));\n    }\n\n    private IEnumerable<string> FindFilesInDirectory(string dir, string suffix = \"\")\n    {\n        List<string> matches = new List<string>();\n        if (Directory.Exists(dir))\n        {\n            string[] files = Directory.GetFiles(dir);\n            Regex regex = new Regex(\".+\\\\.\" + suffix);\n\n            foreach (string file in files)\n            {\n                if (regex.Match(file).Success)\n                    matches.Add(file);\n            }\n        }\n\n        return matches;\n    }\n\n    private string GetConfigurationString()\n    {\n        return (Configuration == UnrealTargetConfiguration.Shipping) ? \"Release\" : \"Debug\";\n    }\n\n    public ModuleDepPaths GatherDeps()\n    {\n        string RootPath = Path.GetFullPath(Path.Combine(ModuleDirectory, \"../../\"));\n\n        INCLUDE_ROOT = Path.Combine(RootPath, GRPC_STRIPPED_FOLDER);\n        LIB_ROOT = Path.Combine(RootPath, GRPC_LIBS_FOLDER);\n\n\n        List<string> headers = new List<string>();\n        List<string> libs = new List<string>();\n\n        string PlatformLibRoot = \"\";\n\n\n        if (Platform == UnrealTargetPlatform.Win64)\n        {\n            PlatformLibRoot = Path.Combine(LIB_ROOT, Platform.ToString());\n            libs.AddRange(FindFilesInDirectory(PlatformLibRoot, \"lib\"));\n        }\n        else\n        {\n            PlatformLibRoot = Path.Combine(LIB_ROOT, Platform.ToString());\n            libs.AddRange(FindFilesInDirectory(PlatformLibRoot, \"a\"));\n        }\n\n        clog(\"PlatformLibRoot: \" + PlatformLibRoot);\n\n        headers.Add(Path.Combine(INCLUDE_ROOT, \"include\"));\n        headers.Add(Path.Combine(INCLUDE_ROOT, \"third_party\", \"protobuf\", \"src\"));\n\n        return new ModuleDepPaths(headers.ToArray(), libs.ToArray());\n\n    }\n\n    public InfraworldRuntime(ReadOnlyTargetRules Target) : base(Target)\n    {\n        PublicDefinitions.Add(\"GOOGLE_PROTOBUF_NO_RTTI\");\n        PublicDefinitions.Add(\"GPR_FORBID_UNREACHABLE_CODE\");\n        PublicDefinitions.Add(\"GRPC_ALLOW_EXCEPTIONS=0\");\n\n        //TODO: We do this because in file generated_message_table_driven.h that located in protobuf sources \n        //TODO: line 174: static_assert(std::is_pod<AuxillaryParseTableField>::value, \"\");\n        //TODO: causes С4647 level 3 warning __is_pod behavior change\n        //TODO: UE4 threading some warnings as errors, and we have no chance to suppress this stuff\n        //TODO: So, we don't want to change any third-party code, this why we add this definition\n        PublicDefinitions.Add(\"__NVCC__\");\n\n        Platform = Target.Platform;\n        Configuration = Target.Configuration;\n\n        ModuleDepPaths moduleDepPaths = GatherDeps();\n        Console.WriteLine(moduleDepPaths.ToString());\n\n        PublicIncludePaths.AddRange(moduleDepPaths.HeaderPaths);\n        PublicAdditionalLibraries.AddRange(moduleDepPaths.LibraryPaths);\n\n        PublicDependencyModuleNames.AddRange(new string[] {\n            \"Core\"\n        });\n\n        AddEngineThirdPartyPrivateStaticDependencies(Target, \"OpenSSL\");\n        AddEngineThirdPartyPrivateStaticDependencies(Target, \"zlib\");\n\n        PrivateDependencyModuleNames.AddRange(new string[] { \"CoreUObject\", \"Engine\" });\n\n    }\n}\n"
  },
  {
    "path": "Source/InfraworldRuntime/Private/ChannelCredentials.cpp",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#include \"ChannelCredentials.h\"\n#include \"InfraworldRuntime.h\"\n\n#include \"GrpcIncludesBegin.h\"\n\n#include <grpc++/security/credentials.h>\n\n#include \"GrpcIncludesEnd.h\"\n\nUChannelCredentials* UChannelCredentials::MakeGoogleDefaultCredentials()\n{\n    return NewObject<UGoogleDefaultCredentials>();\n}\n\nUChannelCredentials* UChannelCredentials::MakeSslCredentials(FString PemRootCerts, FString PemPrivateKey, FString PemCertChain)\n{\n    USslCredentials* const SslCredentials = NewObject<USslCredentials>();\n\n    SslCredentials->PemRootCerts = PemRootCerts;\n    SslCredentials->PemPrivateKey = PemPrivateKey;\n    SslCredentials->PemCertChain = PemCertChain;\n\n    return SslCredentials;\n}\n\nUChannelCredentials* UChannelCredentials::MakeInsecureChannelCredentials()\n{\n    return NewObject<UInsecureChannelCredentials>();\n}\n\n#if PLATFORM_WINDOWS\n#include \"Windows/HideWindowsPlatformTypes.h\"\n#endif\n"
  },
  {
    "path": "Source/InfraworldRuntime/Private/GrpcUriValidator.cpp",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n#include \"GrpcUriValidator.h\"\n#include \"InfraworldRuntime.h\"\n#include \"Misc/DefaultValueHelper.h\"\n\nclass FGrpcUriValidator_Internal\n{\npublic:\n    static bool ValidatePort(const FString& MaybePort, FString& OutError);\n    static bool ValidateIp(const FString& MaybeIpAddress, FString& OutError);\n    static bool ValidateDomainName(const FString& MaybeDomainName, FString& OutError);\n    \n    static bool DoesHostLookLikeIp(const FString& MaybeIpAddress);\n    \nprivate:\n    static bool TCharIsLetter(TCHAR character);\n    static bool TCharIsDigit(TCHAR character);\n};\n\n\n/// FGrpcUriValidator_Internal interface\n\nbool FGrpcUriValidator_Internal::ValidatePort(const FString& MaybePort, FString& OutError)\n{\n    int32 PortAsInteger;\n    if (FDefaultValueHelper::ParseInt(MaybePort, PortAsInteger))\n    {\n        const TRange<int32> ValidPortRange(0, 0xFFFF);\n        \n        if (!ValidPortRange.Contains(PortAsInteger))\n        {\n            OutError = FString::Printf(TEXT(\"Invalid port number: \\\"%d\\\", must be within [%d - %d)\"), PortAsInteger, 0, 0xFFFF);\n            return false;\n        }\n    }\n    else\n    {\n        OutError = FString::Printf(TEXT(\"Can not parse port \\\"%s\\\" into an integer. The format is invalid.\"), *MaybePort);\n        return false;\n    }\n    \n    return true;\n}\n\nbool FGrpcUriValidator_Internal::ValidateIp(const FString& MaybeIpAddress, FString& OutError)\n{\n    TArray<FString> Octets;\n    MaybeIpAddress.ParseIntoArray(Octets, TEXT(\".\"));\n    \n    if (Octets.Num() == 4)\n    {\n        const TRange<int32> OctetRange(0, 0xFF);\n        for (const FString& Octet : Octets)\n        {\n            int32 Out;\n            if (FDefaultValueHelper::ParseInt(Octet, Out))\n            {\n                if (!OctetRange.Contains(Out))\n                {\n                    OutError = FString::Printf(TEXT(\"An octet \\\"%s\\\" in the IPv4 address (which is \\\"%s\\\") is of range [0 - 256)\"), *Octet, *MaybeIpAddress);\n                    return false;\n                }\n            }\n            else\n            {\n                OutError = FString::Printf(TEXT(\"\\\"%s\\\" in \\\"%s\\\" does not seems to be int32\"), *Octet, *MaybeIpAddress);\n                return false;\n            }\n        }\n    }\n    else\n    {\n        OutError = FString::Printf(TEXT(\"Can not parse IPv4 address (which is \\\"%s\\\") into TArray<FString>, or invalid number of octets\"), *MaybeIpAddress);\n        return false;\n    }\n    \n    return true;\n}\n\nbool FGrpcUriValidator_Internal::ValidateDomainName(const FString& MaybeDomainName, FString& OutError)\n{\n    for (TCHAR Character : MaybeDomainName)\n    {\n        if (!TCharIsLetter(Character) && !TCharIsDigit(Character) && (Character != TEXT('-')) && (Character != TEXT('.')))\n        {\n            OutError = FString::Printf(TEXT(\"\\\"%s\\\" domain name contains forbidden character: \\\"%c\\\"\"), *MaybeDomainName, Character);\n            return false;\n        }\n    }\n    \n    return true;\n}\n\nbool FGrpcUriValidator_Internal::DoesHostLookLikeIp(const FString& MaybeIpAddress)\n{\n    for (TCHAR Character : MaybeIpAddress)\n    {\n        if (!TCharIsDigit(Character) && (Character != TEXT('.')))\n            return false;\n    }\n    \n    return true;\n}\n\nbool FGrpcUriValidator_Internal::TCharIsLetter(TCHAR character)\n{\n    const bool bUpperCase = (character >= TEXT('A')) && (character <= TEXT('Z'));\n    const bool bLowerCase = (character >= TEXT('a')) && (character <= TEXT('z'));\n    \n    return bUpperCase || bLowerCase;\n}\n\nbool FGrpcUriValidator_Internal::TCharIsDigit(TCHAR character)\n{\n    return (character >= TEXT('0')) && (character <= TEXT('9'));\n}\n\n\n/// FGrpcUriValidator interface\n\nbool FGrpcUriValidator::Validate(const FString& MaybeGrpcUri, FString& OutError)\n{\n    static const FString SchemeSeparator(TEXT(\"://\"));\n    \n    const int32 IndexOfSchemeSeparator = MaybeGrpcUri.Find(SchemeSeparator);\n    if (IndexOfSchemeSeparator >= 0)\n    {\n        const FString& Scheme = MaybeGrpcUri.Mid(0, IndexOfSchemeSeparator);\n        \n        OutError = FString::Printf(TEXT(\"GRPC URI \\\"%s\\\" must not contain a URL scheme (\\\"%s\\\" provided). GRPC forbids explicit schemes.\"), *MaybeGrpcUri, *Scheme);\n        return false;\n    }\n    \n    const int32 PathSeparatorIndex = MaybeGrpcUri.Find(TEXT(\"/\"));\n    const bool bHasPathSeparator = PathSeparatorIndex >= 0;\n    \n    const int32 PortSeparatorIndex = MaybeGrpcUri.Find(TEXT(\":\"), ESearchCase::IgnoreCase, ESearchDir::FromEnd, (PathSeparatorIndex >= 0) ? PathSeparatorIndex : INDEX_NONE);\n    const bool bHasPortSeparator = PortSeparatorIndex >= 0;\n    \n    FString GrpcHostName = TEXT(\"\");\n    FString GrpcPort = TEXT(\"80\");\n    \n    if (bHasPortSeparator)\n    {\n        GrpcHostName = MaybeGrpcUri.Mid(0, PortSeparatorIndex);\n        \n        const int32 PortSubstringStart = PortSeparatorIndex + 1;\n        if (bHasPathSeparator)\n        {\n            GrpcPort = MaybeGrpcUri.Mid(PortSubstringStart, (PathSeparatorIndex - PortSubstringStart));\n        }\n        else\n        {\n            GrpcPort = MaybeGrpcUri.Mid(PortSubstringStart);\n        }\n    }\n    else\n    {\n        if (bHasPathSeparator)\n        {\n            GrpcHostName = MaybeGrpcUri.Mid(0, PathSeparatorIndex);\n        }\n        else\n        {\n            GrpcHostName = MaybeGrpcUri;\n        }\n    }\n    \n    if (bHasPathSeparator)\n    {\n        const FString& RestOfAddress = MaybeGrpcUri.Mid(PathSeparatorIndex);\n        if (!RestOfAddress.IsEmpty())\n        {\n            OutError = FString::Printf(TEXT(\"Path of the \\\"%s\\\" uri, must be empty. Actually it is: \\\"%s\\\"\"), *MaybeGrpcUri, *RestOfAddress);\n            return false;\n        }\n    }\n    \n    if (FGrpcUriValidator_Internal::DoesHostLookLikeIp(GrpcHostName))\n    {\n        // Validate as IP address\n        if (!FGrpcUriValidator_Internal::ValidateIp(GrpcHostName, OutError))\n            return false;\n    }\n    else\n    {\n        // Validate as domain name\n        if (!FGrpcUriValidator_Internal::ValidateDomainName(GrpcHostName, OutError))\n            return false;\n    }\n    \n    // Anyway, validate port\n    if (!FGrpcUriValidator_Internal::ValidatePort(GrpcPort, OutError))\n        return false;\n    \n    return true;\n}\n"
  },
  {
    "path": "Source/InfraworldRuntime/Private/InfraworldRuntime.cpp",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#include \"InfraworldRuntime.h\"\n\nDEFINE_LOG_CATEGORY(LogInfraworldRuntime);\n\n#define LOCTEXT_NAMESPACE \"FInfraworldRuntimeModule\"\n\nvoid FInfraworldRuntimeModule::StartupModule()\n{\n\t// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module\n}\n\nvoid FInfraworldRuntimeModule::ShutdownModule()\n{\n\t// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,\n\t// we call this function before unloading the module.\n}\n\n#undef LOCTEXT_NAMESPACE\n\nIMPLEMENT_MODULE(FInfraworldRuntimeModule, InfraworldRuntime)\n"
  },
  {
    "path": "Source/InfraworldRuntime/Private/RpcClient.cpp",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#include \"RpcClient.h\"\n\n#include \"InfraworldRuntime.h\"\n#include \"RpcClientWorker.h\"\n#include \"GrpcUriValidator.h\"\n\n#include \"Containers/Ticker.h\"\n#include \"Misc/CoreDelegates.h\"\n\n#include \"Misc/DefaultValueHelper.h\"\n#include \"HAL/RunnableThread.h\"\n#include \"Kismet/KismetStringLibrary.h\"\n\n// ============ RpcClient implementation ===========\n\nbool URpcClient::Init(const FString& URI, UChannelCredentials* ChannelCredentials)\n{\n    if (bCanSendRequests)\n    {\n        UE_LOG(LogInfraworldRuntime, Error, TEXT(\"You're trying to initialize an RPC Client more than once\"));\n        return true;\n    }\n    \n    FString ErrorMessage;\n    if (!FGrpcUriValidator::Validate(URI, ErrorMessage))\n    {\n        UE_LOG(LogInfraworldRuntime, Error, TEXT(\"%s Unable to validate URI: %s\"), *(GetClass()->GetName()), *ErrorMessage);\n    }\n\n    // Do it if and only if the thread is not yet created.\n    if (Thread == nullptr)\n    {\n    \tUE_LOG(LogInfraworldRuntime, Log, TEXT(\"RpcClient at [%p], Thread == nullptr, initializing\"), this);\n\n    \t\n        // Launch 'chaining' hierarchical init, which will init a superclass (a concrete implementation).\n        HierarchicalInit();\n\n    \tUE_LOG(LogInfraworldRuntime, Log, TEXT(\"RpcClient at [%p], finished HierarchicalInit\"), this);\n\n    \t\n        // Retrieve and set an Error Message Queue\n        if (InnerWorker)\n        {\n    \t\tUE_LOG(LogInfraworldRuntime, Log, TEXT(\"RpcClient at [%p], InnerWorker = %p\"), this, InnerWorker.Get());\n        \t\n            InnerWorker->URI = URI;\n            InnerWorker->ChannelCredentials = ChannelCredentials;\n\n            InnerWorker->ErrorMessageQueue = &ErrorMessageQueue;\n\n            const FString ThreadName(FString::Printf(TEXT(\"RPC Client Thread %s %d\"), *(GetClass()->GetName()), FMath::RandRange(0, TNumericLimits<int32>::Max())));\n            Thread = FRunnableThread::Create(InnerWorker.Get(), *ThreadName);\n\n            bCanSendRequests = true;\n            UE_LOG(LogInfraworldRuntime, Log, TEXT(\"Just made a thread: %s, address %p\"), *ThreadName, InnerWorker.Get());\n        }\n        else\n        {\n            UE_LOG(LogInfraworldRuntime, Fatal, TEXT(\"An inner worker of %s wasn't initialized\"), *(GetClass()->GetName()));\n        }\n    }\n\n    if (CanSendRequests())\n    {\n        TickDelegateHandle = FTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateLambda([this](float)\n        {\n            if (!ErrorMessageQueue.IsEmpty())\n            {\n                FRpcError ReceivedError;\n                ErrorMessageQueue.Dequeue(ReceivedError);\n                EventRpcError.Broadcast(this, ReceivedError);\n\n                // No need to call URpcClient::HierarchicalUpdate() if got any errors (Errors first)\n            }\n            else\n            {\n                HierarchicalUpdate();\n            }\n\n            return true;\n        }));\n    }\n\n    return bCanSendRequests;\n}\n\nURpcClient::URpcClient() : InnerWorker(nullptr), TickDelegateHandle()\n{\n}\n\nURpcClient::~URpcClient()\n{\n    UE_LOG(LogInfraworldRuntime, Verbose, TEXT(\"An instance of RPC Client has been destroyed. Still can send requests: %s\"),\n           *UKismetStringLibrary::Conv_BoolToString(CanSendRequests()));\n}\n\nvoid URpcClient::Update()\n{\n    // Occasionally left blank\n}\n\nbool URpcClient::CanSendRequests() const\n{\n    return bCanSendRequests;\n}\n\nURpcClient* URpcClient::CreateRpcClient(TSubclassOf<URpcClient> Class, FRpcClientInstantiationParameters InstantiationParameters, UObject* Outer)\n{\n    const FString& URI = FString::Printf(TEXT(\"%s:%d\"), *(InstantiationParameters.Ip), InstantiationParameters.Port);\n    return CreateRpcClientUri(Class, URI, InstantiationParameters.ChannelCredentials, Outer);\n}\n\nURpcClient* URpcClient::CreateRpcClientUri(TSubclassOf<URpcClient> Class, const FString& URI, UChannelCredentials* ChannelCredentials, UObject* Outer)\n{\n    UObject* const RealOuter = Outer ? Outer : (UObject*)GetTransientPackage();\n    \n    if (URpcClient* const CreatedClient = NewObject<URpcClient>(RealOuter, *Class))\n    {\n\t\tUE_LOG(LogInfraworldRuntime, Log, TEXT(\"Created RpcClient at [%p] with outer [%p]\"), CreatedClient, RealOuter);\n    \t\n        bool IsClientInitialized = CreatedClient->Init(URI, ChannelCredentials);\n        if (!IsClientInitialized)\n        {\n            UE_LOG(LogInfraworldRuntime, Error, TEXT(\"Unable to initialize an RPC client (%s::Init() failed\"), *(Class->GetName()));\n            return nullptr;\n        }\n        else\n        {\n            UE_LOG(LogInfraworldRuntime, Verbose, TEXT(\"An instance of %s has been created and initialized\"), *(Class->GetName()));\n            return CreatedClient;\n        }\n    }\n    else\n    {\n        UE_LOG(LogInfraworldRuntime, Fatal, TEXT(\"Unable to create an instance of RPC client (NewObject<%s>() failed)\"), *(Class->GetName()));\n        return nullptr;\n    }\n}\n\nvoid URpcClient::BeginDestroy()\n{\n    // Being called when GC'ed, should be called synchronously.\n    if (CanSendRequests())\n    {\n        Stop(true);\n    }\n\n    Super::BeginDestroy();\n}\n\nvoid URpcClient::Stop(bool bSynchronous)\n{\n    FRunnableThread* ThreadToStop = Thread.Exchange(nullptr);\n\n    if (ThreadToStop)\n    {\n        if (!InnerWorker->IsPendingStopped())\n            InnerWorker->MarkPendingStopped();\n\n        bCanSendRequests = false;\n        UE_LOG(LogInfraworldRuntime, Verbose, TEXT(\"Scheduled to stop %s via setting 'bCanSendRequests = false', address %p\"), *(GetClass()->GetName()), InnerWorker.Get());\n\n        // Should be synchronous in (almost) any case\n        ThreadToStop->Kill(bSynchronous);\n\n        delete ThreadToStop;\n        ThreadToStop = nullptr;\n        \n        FTicker::GetCoreTicker().RemoveTicker(TickDelegateHandle);\n    }\n    else\n    {\n        UE_LOG(LogInfraworldRuntime, Error, TEXT(\"Can not call Stop() for an already stopped (or penfing asinchronously stopped) instance of '%s'\"), *(GetClass()->GetName()));\n    }\n}\n"
  },
  {
    "path": "Source/InfraworldRuntime/Private/RpcClientWorker.cpp",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#include \"RpcClientWorker.h\"\n\n#include \"InfraworldRuntime.h\"\n\n#include \"HAL/PlatformTime.h\"\n#include \"GenUtils.h\"\n\n#include \"GrpcIncludesBegin.h\"\n\n#include <grpc++/channel.h>\n#include <grpc++/create_channel.h>\n\n#include \"GrpcIncludesEnd.h\"\n#include \"WorkerUtils.h\"\n\n// ========= RpcClientWorker implementation ========\n\nRpcClientWorker::RpcClientWorker() : WorkerState(ERpcWorkerState::PendingInitialization)\n{\n}\n\nRpcClientWorker::~RpcClientWorker()\n{\n}\n\nuint32 RpcClientWorker::Run()\n{\n    // If channel has not been created - we set bPendingStopped = true to StopBackground.\n\tif (!ensureAlways(WorkerState.Exchange(ERpcWorkerState::Initializing) == ERpcWorkerState::PendingInitialization))\n\t{\n\t\treturn 2;\n\t}\n\t\n    if (HierarchicalInit())\n\t{\n        UE_LOG(LogInfraworldRuntime, Log, TEXT(\"Finished initialization via HierarchicalInit!\"));\n\n\t\tERpcWorkerState ExpectedState = ERpcWorkerState::Initializing;\n\n    \t// this will set WorkerState to Working only if no one overwrote it from Initializing\n    \tif (!WorkerState.CompareExchange(ExpectedState, ERpcWorkerState::Working))\n    \t{\n\t\t\tUE_LOG(LogInfraworldRuntime, Log, TEXT(\"Worker already marked pending stopped. Its state is %d\"), static_cast<int>(ExpectedState));\n    \t}\n\t}\n    else\n        return 1;\n\n    // Update until not pending stopped\n    while (WorkerState == ERpcWorkerState::Working)\n    {\n        UE_LOG(LogInfraworldRuntime, Verbose, TEXT(\"Updating via HierarchicalUpdate()\"));\n\n        HierarchicalUpdate();\n        FPlatformProcess::Sleep(0.1f);\n    }\n\n\tWorkerState.Exchange(ERpcWorkerState::Shutdown);\n\n    return 0;\n}\n\nvoid RpcClientWorker::DispatchError(const FString& ErrorMessage)\n{\n    UE_CLOG(!ErrorMessageQueue, LogInfraworldRuntime, Fatal, TEXT(\"Can not dispatch an error message, because ErrorMessageQueue is null\"));\n\n    FRpcError Error;\n    Error.ErrorMessage = ErrorMessage;\n\n    ErrorMessageQueue->Enqueue(Error);\n}\n\n#if PLATFORM_WINDOWS\n#include \"Windows/HideWindowsPlatformTypes.h\"\n#endif\n"
  },
  {
    "path": "Source/InfraworldRuntime/Public/CastUtils.h",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#pragma once\n\n#include \"CoreMinimal.h\"\n\n#include <string>\n#include <functional>\n#include <chrono>\n\n#include \"GrpcIncludesBegin.h\"\n\n#include <google/protobuf/repeated_field.h>\n#include <google/protobuf/map.h>\n#include <grpc++/client_context.h>\n\n#include \"GrpcIncludesEnd.h\"\n\n// Should be imported to avoid long chrono-related instructions.\nusing std::chrono::milliseconds;\nusing std::chrono::system_clock;\n\n//\n// Generic casts. Should be specified in each header file for each generated structure.\n//\nnamespace casts\n{\n    // ~~~~~ Unreal TMap and TArray, protobuf google::protobuf::RepeatedField and google::protobuf::Map) ~~~~~\n\n    template<class OutT, class InT>\n    using _UnrealMap = TMap<OutT, InT>;\n\n    template<class OutT, class InT>\n    using _ProtobufMap = google::protobuf::Map<OutT, InT>;\n\n    template<class OutT>\n    using _UnrealArray = TArray<OutT>;\n\n    template<class OutT>\n    using _ProtobufArray = google::protobuf::RepeatedField<OutT>;\n\n    template<class OutT>\n    using _ProtobufPtrArray = google::protobuf::RepeatedPtrField<OutT>;\n\n\n    // ~~~~~ CAST PROTOTYPES (GENERIC) ~~~~~\n\n    template<class OutT, class InT>\n    FORCEINLINE OutT Proto_Cast(const InT &Item)\n    {\n        // WARNING!!!\n        // If you're receiving an error message, telling you something like:\n        //\n        // error: no matching conversion for static_cast from 'xxx' to 'yyy'\n        // return (OutT) t;\n        //        ^~~~~\n        // error: no matching function for call to 'Proto_Cast'\n        // consider creating your own template specification of Proto_Cast<?>()\n        // because by default it can only cast statically\n\n        return static_cast<OutT>(Item);\n    }\n\n    // ~~~~~ CAST FUNCTIONS (MAPS) ~~~~~\n\n    // TMap -> Protobuf Map\n    template<class OutK, class OutV, class InK, class InV>\n    FORCEINLINE _UnrealMap<OutK, OutV> Proto_MapCast(const _ProtobufMap<InK, InV>& Map)\n    {\n        _UnrealMap<OutK, OutV> OutMap;\n\n        for (auto It = Map.cbegin(); It != Map.cend(); ++It)\n            OutMap.Add(Proto_Cast<OutK>(It->first), Proto_Cast<OutV>(It->second));\n\n        return OutMap;\n    }\n\n    // Protobuf Map -> TMap\n    template<class OutK, class OutV, class InK, class InV>\n    FORCEINLINE _ProtobufMap<OutK, OutV> Proto_MapCast(const _UnrealMap<InK, InV>& Map)\n    {\n        _ProtobufMap<OutK, OutV> OutMap;\n\n        for (const TPair<InK, InV>& Pair : Map)\n            OutMap.insert(google::protobuf::MapPair<OutK, OutV>(Proto_Cast<OutK>(Pair.Key), Proto_Cast<OutV>(Pair.Value)));\n\n        return OutMap;\n    }\n\n    // ~~~~~ CAST FUNCTIONS (ARRAYS) ~~~~~\n\n    template<class OutT, class InT>\n    FORCEINLINE _ProtobufArray<OutT> Proto_ArrayCast(const _UnrealArray<InT>& Array)\n    {\n        // Allocate a protobuf array and reserve capacity\n        _ProtobufArray<OutT> OutArray;\n        OutArray.Reserve((int32)Array.Num());\n\n        // Each item shall be individually casted to OutT\n        for (const InT& Item : Array)\n            OutArray.Add(Proto_Cast<OutT>(Item));\n\n        return OutArray;\n    }\n\n    template<class OutT, class InT>\n    FORCEINLINE _UnrealArray<OutT> Proto_ArrayCast(const _ProtobufArray<InT>& Array)\n    {\n        // Allocate a TArray<OutT> and reserve capacity\n        _UnrealArray<OutT> OutArray;\n        OutArray.Reserve((int32)Array.size());\n\n        // Each item shall be individually casted to OutT\n        std::for_each(Array.cbegin(), Array.cend(), [&OutArray](InT Item) {\n            OutArray.Add(Proto_Cast<OutT>(Item));\n        });\n\n        return OutArray;\n    }\n\n    // Overload for _ProtobufPtrArray (google::protobuf::RepeatedPtrField<?>)\n    // _ProtobufPtrArray (aka google::protobuf::RepeatedPtrField<OutT>)\n    // is the same as RepeatedField<?>, but used for repeated strings or messages\n\n    template<class OutT, class InT>\n    FORCEINLINE _ProtobufPtrArray<OutT> Proto_PtrArrayCast(const _UnrealArray<InT>& Array)\n    {\n        // Allocate a protobuf array and reserve capacity\n        _ProtobufPtrArray<OutT> OutArray;\n        OutArray.Reserve((int32)Array.Num());\n\n        // Each item shall be individually casted to OutT\n        for (const InT& Item : Array)\n        {\n            const OutT& cast_result = Proto_Cast<OutT>(Item);\n            \n            // We need to create a new instance of OutT to be posessed by the OutArray.\n            OutArray.AddAllocated(new OutT(cast_result));\n        }\n\n        return OutArray;\n    }\n\n    template<class OutT, class InT>\n    FORCEINLINE _UnrealArray<OutT> Proto_PtrArrayCast(const _ProtobufPtrArray<InT>& Array)\n    {\n        // Allocate a TArray<OutT> and reserve capacity\n        _UnrealArray<OutT> OutArray;\n        OutArray.Reserve((int32)Array.size());\n\n        // Each item shall be individually casted to OutT\n        std::for_each(Array.cbegin(), Array.cend(), [&OutArray](InT Item) {\n            OutArray.Add(Proto_Cast<OutT>(Item));\n        });\n\n        return OutArray;\n    }\n\n    // Casting enums value-wise does not require any specialization. Thou can override the template function.\n    template<typename OutT, typename InT>\n    FORCEINLINE OutT Proto_EnumCast(const InT &Item)\n    {\n        return static_cast<OutT>((int)Item);\n    };\n\n    // ~~~~~ CAST FUNCTIONS (BYTE ARRAY), in protobuf byte arrays are std::strings ~~~~~\n\n    template <>\n    FORCEINLINE FByteArray Proto_Cast(const std::string& String)\n    {\n        // Allocate a TArray<uint8>\n        TArray<uint8> OutArray;\n        \n        // Put String's content into the array. We can not (and do not need) to cast away const qualifier.\n        OutArray.Insert(reinterpret_cast<const uint8*>(String.c_str()), String.size(), 0);\n\n        // Finally, wrap all data into FByteArray\n        return FByteArray(OutArray);\n    }\n\n    template <>\n    FORCEINLINE std::string Proto_Cast(const FByteArray& Item)\n    {\n        const TArray<uint8>& Arr = Item.Bytes;\n        return std::string(reinterpret_cast<const char*>(Arr.GetData()), Arr.Num());\n    }\n\n    // ~~~~~ CAST FUNCTIONS (UNREAL STRING and PROTOBUF STRING) ~~~~~\n\n    template <>\n    FORCEINLINE std::string Proto_Cast(const FString& String)\n    {\n        return std::string(TCHAR_TO_UTF8(*String));\n    }\n\n    template <>\n    FORCEINLINE FString Proto_Cast(const std::string& String)\n    {\n        return FString(String.c_str());\n    }\n\n    /**\n     * Casts an UE4-compatible client context to the GRPC-compatible context.\n     *\n     * @note That grpc::ClientContext doesn't have a copy constructor, so grpc::ClientContext can not be returned from a\n     *       ProtoCast<?>(). Thus the method should set an instance of grpc::ClientContext that already exist.\n     * @param InContext Input UE4-compatible client context.\n     * @param OutContext Output GRPC-compatible client context.\n     */\n    FORCEINLINE void CastClientContext(const FGrpcClientContext &InContext, grpc::ClientContext &OutContext)\n    {\n        // Cast and set metadata, checking for errors.\n        for (const TPair<FString, FString>& Pair : InContext.Metadata)\n        {\n            if (Pair.Key.IsEmpty())\n            {\n                UE_LOG(LogTemp, Error, TEXT(\"Metadata key is empty for mapping '%s'->'%s' and thus won't be added to the client context. Behaviour is restricted by %s\"),\n                    *Pair.Key, *Pair.Value, TEXT(\"grpc/core/lib/surface/validate_metadata:80\"));\n            }\n            else if (Pair.Key.StartsWith(\":\"))\n            {\n                UE_LOG(LogTemp, Error, TEXT(\"Metadata key statrs with ':' for mapping '%s'->'%s' and thus won't be added to the client context. Behaviour is restricted by %s\"),\n                    *Pair.Key, *Pair.Value, TEXT(\"grpc/core/lib/surface/validate_metadata:84\"));\n            }\n            else\n            {\n                OutContext.AddMetadata(casts::Proto_Cast<std::string>(Pair.Key), casts::Proto_Cast<std::string>(Pair.Value));\n            }\n\n            // TODO: Add some other validation checks if necessary.\n        }\n\n        // Set deadline (Only if it has a positive value. It is -1 by default)\n        if (InContext.DeadlineSeconds > .0f)\n        {\n            const int64 Milliseconds = static_cast<int64>(((double)InContext.DeadlineSeconds * 1000.0));\n            OutContext.set_deadline(system_clock::now() + milliseconds(Milliseconds));\n        }\n\n        // Set boolean parameters\n        OutContext.set_idempotent(InContext.bIdempotent);\n        OutContext.set_cacheable(InContext.bCacheable);\n        OutContext.set_wait_for_ready(InContext.bWaitForReady);\n\n        // Set authority\n        OutContext.set_authority(casts::Proto_Cast<std::string>(InContext.Authority));\n\n        // Set Compression Algorithm\n        OutContext.set_compression_algorithm(Proto_EnumCast<grpc_compression_algorithm>(InContext.GrpcCompressionAlgorithm));\n\n        // Set Initial Metadata Corked\n        OutContext.set_initial_metadata_corked(InContext.bInitialMetadataCorked);\n    }\n\n    FORCEINLINE void CastStatus(const grpc::Status& InStatus, FGrpcStatus& OutStatus)\n    {\n        OutStatus.ErrorCode = Proto_EnumCast<EGrpcStatusCode>(InStatus.error_code());\n        OutStatus.ErrorMessage = Proto_Cast<FString>(InStatus.error_message());\n        OutStatus.ErrorDetails = Proto_Cast<FString>(InStatus.error_details());\n    }\n\n    // Since we have no support for unsigned types in Blueprints, we need to\n\n    template <>\n    FORCEINLINE _UnrealArray<int32> Proto_ArrayCast(const _ProtobufArray<uint32>& Array)\n    {\n        // Allocate a TArray<OutT> and reserve capacity\n        _UnrealArray<int32> OutArray;\n        OutArray.Reserve((int32)Array.size());\n\n        // Each item shall be individually casted to OutT\n        std::for_each(Array.cbegin(), Array.cend(), [&OutArray](uint32 Item) {\n            OutArray.Add(Proto_Cast<int32>(Item));\n        });\n\n        return OutArray;\n    }\n\n    template <>\n    FORCEINLINE _ProtobufArray<uint32> Proto_ArrayCast(const _UnrealArray<int32>& Array)\n    {\n        // Allocate a protobuf array and reserve capacity\n        _ProtobufArray<uint32> OutArray;\n        OutArray.Reserve((int32)Array.Num());\n\n        // Each item shall be individually casted to OutT\n        for (const int32 Item : Array)\n            OutArray.Add(Proto_Cast<uint32>(Item));\n\n        return OutArray;\n    }\n}\n"
  },
  {
    "path": "Source/InfraworldRuntime/Public/ChannelCredentials.h",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n\n#include <memory>\n\n#include \"ChannelCredentials.generated.h\"\n\n// namespace grpc\n// {\n//     class ChannelCredentials;\n// }\n\nUSTRUCT(BlueprintType)\nstruct INFRAWORLDRUNTIME_API FRpcError\n{\n    GENERATED_USTRUCT_BODY()\n\n    UPROPERTY(BlueprintReadOnly, Category=Grpc)\n    FString ErrorMessage;\n};\n\n\n/**\n * A channel credentials object encapsulates all the state needed by a client\n * to authenticate with a server for a given channel.\n * It can make various assertions, e.g., about the client’s identity, role\n * for all the calls on that channel.\n */\nUCLASS(NotBlueprintable, NotBlueprintType, notplaceable, noteditinlinenew, hidedropdown, Transient, Abstract)\nclass INFRAWORLDRUNTIME_API UChannelCredentials : public UObject\n{\n    GENERATED_BODY()\n\npublic:\n    /**\n     * Builds credentials with reasonable defaults.\n     *\n     * \\warning Only use these credentials when connecting to a Google endpoint.\n     * Using these credentials to connect to any other service may result in this\n     * service being able to impersonate your client for requests to Google\n     * services.\n     * @return Google Default Credentials\n     */\n    UFUNCTION(BlueprintCallable, BlueprintPure, Category=\"Vizor|RPC Credentials\")\n    static UChannelCredentials* MakeGoogleDefaultCredentials();\n\n    /**\n     * Builds SSL Credentials given SSL specific options.\n     *\n     * @param PemRootCerts\n     *        The buffer containing the PEM encoding of the server root certificates. If\n     *        this parameter is empty, the default roots will be used.  The default\n     *        roots can be overridden using the \\a GRPC_DEFAULT_SSL_ROOTS_FILE_PATH\n     *        environment variable pointing to a file on the file system containing the\n     *        roots.\n     * @param PemPrivateKey\n     *        The buffer containing the PEM encoding of the client's private key. This\n     *        parameter can be empty if the client does not have a private key.\n     * @param PemCertChain\n     *        The buffer containing the PEM encoding of the client's certificate chain.\n     *        This parameter can be empty if the client does not have a certificate\n     *        chain.\n     * @return Ssl Credentials\n     */\n    UFUNCTION(BlueprintCallable, BlueprintPure, Category=\"Vizor|RPC Credentials\")\n    static UChannelCredentials* MakeSslCredentials(\n        UPARAM(DisplayName=\"PEM Root Certificates\") FString PemRootCerts,\n        UPARAM(DisplayName=\"PEM Private Key\") FString PemPrivateKey,\n        UPARAM(DisplayName=\"PEM Certificate Chain\") FString PemCertChain\n    );\n\n    /**\n     * Builds credentials for an unencrypted, unauthenticated channel.\n     *\n     * @return Insecure Channel Credentials\n     */\n    UFUNCTION(BlueprintCallable, BlueprintPure, Category=\"Vizor|RPC Credentials\")\n    static UChannelCredentials* MakeInsecureChannelCredentials();\n};\n\n/**\n * Builds credentials with reasonable defaults.\n *\n * \\warning Only use these credentials when connecting to a Google endpoint.\n * Using these credentials to connect to any other service may result in this\n * service being able to impersonate your client for requests to Google\n * services.\n */\nUCLASS()\nclass INFRAWORLDRUNTIME_API UGoogleDefaultCredentials : public UChannelCredentials\n{\n    GENERATED_BODY()\n\npublic:\n};\n\n/**\n * Builds SSL Credentials given SSL specific options\n */\nUCLASS()\nclass INFRAWORLDRUNTIME_API USslCredentials : public UChannelCredentials\n{\n    GENERATED_BODY()\n\npublic:\n    UPROPERTY(BlueprintReadOnly, Transient, DisplayName=\"PEM Root Certificates\", Category=GrpcCerts)\n    FString PemRootCerts;\n\n    UPROPERTY(BlueprintReadOnly, Transient, DisplayName=\"PEM Private Key\", Category=GrpcCerts)\n    FString PemPrivateKey;\n\n    UPROPERTY(BlueprintReadOnly, Transient, DisplayName=\"PEM Certificate Chain\", Category=GrpcCerts)\n    FString PemCertChain;\n};\n\n/**\n * Credentials for an unencrypted, unauthenticated channel\n */\nUCLASS()\nclass INFRAWORLDRUNTIME_API UInsecureChannelCredentials : public UChannelCredentials\n{\n    GENERATED_BODY()\n\npublic:\n};\n\n/**\n * Instantiation parameters are used to create an RPC client.\n */\nUSTRUCT(BlueprintType)\nstruct INFRAWORLDRUNTIME_API FRpcClientInstantiationParameters\n{\n    GENERATED_BODY()\n\n    /**\n     * The IP address of the endpoint to connect to.\n     */\n    UPROPERTY(BlueprintReadWrite, Category=Endpoint)\n    FString Ip;\n\n    /**\n     * The port of the endpoint to connect to.\n     */\n    UPROPERTY(BlueprintReadWrite, Category=EndpointPort)\n    int32 Port;\n\n    /**\n     * Credentials to use for the created RPC client. If it does not hold\n     * an object or is invalid, an error will be thrown.\n     */\n    UPROPERTY(BlueprintReadWrite, Category=Credentials)\n    UChannelCredentials* ChannelCredentials;\n\n    /**\n     * Gets a GRPC URI for current ip address and port.\n     *\n     * @return URI for channel instantiation.\n     */\n    FString GetURI() const\n    {\n        return FString::Printf(TEXT(\"%s:%d\"), *Ip, Port);\n    }\n\n    /**\n     * Gets a string representation of current FRpcClientInstantiationParameters.\n     *\n     * @return FRpcClientInstantiationParameters string representation.\n     */\n    FString GetName() const\n    {\n        const FString& ParamsURI = GetURI();\n        const FString& CredentialsClassName = ChannelCredentials ? *(ChannelCredentials->GetClass()->GetName()) : TEXT(\"nullptr (DANGER!)\");\n\n        return FString::Printf(TEXT(\"URI: %s, Credentials: %s\"), *ParamsURI, *CredentialsClassName);\n    }\n};\n"
  },
  {
    "path": "Source/InfraworldRuntime/Public/ChannelProvider.h",
    "content": "﻿/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#pragma once\n\n#include <grpc++/channel.h>\n#include <grpc++/create_channel.h>\n#include <grpc++/security/credentials.h>\n\n#include \"RpcClientWorker.h\"\n#include \"ChannelCredentials.h\"\n\nnamespace channel\n{\n\tFORCEINLINE bool WaitUntilChannelIsReady(const std::shared_ptr<grpc::Channel>& Channel, std::chrono::system_clock::time_point Deadline)\n\t{\n\t\tgrpc_connectivity_state State = Channel->GetState(true);\n\n\t\twhile (State != GRPC_CHANNEL_READY)\n\t\t{\n\t\t\tif (!Channel->WaitForStateChange(State, Deadline))\n\t\t\t\treturn false;\n\n\t\t\tState = Channel->GetState(true);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tFORCEINLINE bool WaitForConnection(float Seconds, const std::shared_ptr<grpc::Channel>& Channel)\n\t{\n\t\tbool IsConnected = false;\n\n\t\tconst int64 Milliseconds = (int64)((double) Seconds * 1000.0);\n\n\t\tstd::chrono::system_clock::time_point start_tp = std::chrono::system_clock::now();\n\t\tstd::chrono::system_clock::time_point end_tp = std::chrono::system_clock::now() + std::chrono::milliseconds(Milliseconds);\n\n\t\tstd::chrono::system_clock::time_point current_tp = start_tp;\n\n\t\twhile (!IsConnected)\n\t\t{\n\t\t\tstd::chrono::system_clock::time_point delta_tp = std::chrono::system_clock::now() + std::chrono::milliseconds(100);\n\n\t\t\tif (current_tp < end_tp)\n\t\t\t\tIsConnected = WaitUntilChannelIsReady(Channel, delta_tp);\n\t\t\telse\n\t\t\t\tbreak;\n\n\t\t\tcurrent_tp = std::chrono::system_clock::now();\n\t\t}\n\n\t\treturn IsConnected;\n\t}\n\n\tFORCEINLINE std::shared_ptr<grpc::ChannelCredentials> GetGrpcCredentials(UChannelCredentials* const Credentials)\n\t{\n\t\t// Check whether provided credentails are null.\n\t\tif (!Credentials)\n\t\t{\n\t\t\tUE_LOG(LogTemp, Error,\n\t\t\t\tTEXT(\"Provided credentials are NULL. (Did you forget to pass ChannelCredentials to instantiation parameters?). Replacement is \"\n\t\t\t\t\t \"grpc::InsecureChannelCredentials().\"));\n\t\t\treturn grpc::InsecureChannelCredentials();\n\t\t}\n\n\t\t// Classify the credentials\n\t\tif (Credentials->IsA<UGoogleDefaultCredentials>())\n\t\t{\n\t\t\treturn grpc::GoogleDefaultCredentials();\n\t\t}\n\t\telse if (Credentials->IsA<UInsecureChannelCredentials>())\n\t\t{\n\t\t\treturn grpc::InsecureChannelCredentials();\n\t\t}\n\t\telse if (const USslCredentials* const SslCredentials = Cast<USslCredentials>(Credentials))\n\t\t{\n\t\t\tgrpc::SslCredentialsOptions Options;\n\n\t\t\tif (SslCredentials->PemRootCerts.Len() > 0)\n\t\t\t\tOptions.pem_root_certs = TCHAR_TO_ANSI(*(SslCredentials->PemRootCerts));\n\t\t\tif (SslCredentials->PemPrivateKey.Len() > 0)\n\t\t\t\tOptions.pem_private_key = TCHAR_TO_ANSI(*(SslCredentials->PemPrivateKey));\n\t\t\tif (SslCredentials->PemCertChain.Len() > 0)\n\t\t\t\tOptions.pem_cert_chain = TCHAR_TO_ANSI(*(SslCredentials->PemCertChain));\n\n\t\t\treturn grpc::SslCredentials(Options);\n\t\t}\n\n\t\t// Unknown credentials\n\t\tUE_LOG(LogTemp, Error, TEXT(\"Don't know how to process credentials:'%s'. Replacement is grpc::InsecureChannelCredentials().\"),\n\t\t\t*(Credentials->GetClass()->GetName()));\n\t\treturn grpc::InsecureChannelCredentials();\n\t}\n\n\tFORCEINLINE std::shared_ptr<grpc::Channel> CreateChannel(RpcClientWorker* Worker)\n\t{\n\t\tUChannelCredentials* const ChannelCredentials = Worker->ChannelCredentials;\n\t\tUE_CLOG(!ChannelCredentials, LogTemp, Fatal, TEXT(\"Channel Credentials mustn't be null\"));\n\n\t\tconst FString& URI = Worker->URI;\n\t\tUE_LOG(LogTemp, Display, TEXT(\"The following Channel Credentials is used: \\\"%s\\\". Connecting to: \\\"%s\\\"\"), *(ChannelCredentials->GetName()), *URI);\n\n\t\tstd::shared_ptr<grpc::ChannelCredentials> GrpcCredentials = GetGrpcCredentials(ChannelCredentials);\n\t\tstd::shared_ptr<grpc::Channel> Channel = grpc::CreateChannel(TCHAR_TO_ANSI(*URI), GrpcCredentials);\n\n\t\tbool bConnectionWasSuccessful = WaitForConnection(3, Channel);\n\n\t\tif (!bConnectionWasSuccessful)\n\t\t{\n\t\t\tWorker->DispatchError(\n\t\t\t\tNSLOCTEXT(\"InfraworldChannelProvider\", \"InfraworldChannelProviderGrpcServiceConnectionError\", \"Service connection failure!\").ToString());\n\t\t\treturn std::shared_ptr<grpc::Channel>(nullptr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tUE_LOG(LogTemp, Verbose, TEXT(\"%s\"),\n\t\t\t\t*NSLOCTEXT(\"InfraworldChannelProvider\", \"InfraworldChannelProviderGrpcServiceConnectionSuccess\", \"Service connection established!\").ToString());\n\t\t}\n\n\t\treturn Channel;\n\t}\n}\t"
  },
  {
    "path": "Source/InfraworldRuntime/Public/Conduit.h",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"HAL/PlatformTLS.h\"\n#include \"Containers/Queue.h\"\n\n/**\n * A conduit is a combination of two channel: The Request channel, and the Response channel, representing bidirectional queue.\n * A conduit is optimized to work efficiently and lock-free between two threads: the 'Request writer' thread and the\n *  'Response writer' thread.\n * One should call Acquire(Requests/Response)Producer() in the thread, which should produce Requests or Responses.\n */\ntemplate<class TRequest, class TResponse>\nclass TConduit\n{\n    FORCEINLINE uint32 ThreadID() const { return FPlatformTLS::GetCurrentThreadId(); }\n\npublic:\n    TConduit() : RequestsProducerID(-1), ResponsesProducerID(-1)\n    {\n    }\n\n    ~TConduit();\n\n    /**\n     * Should be called from a Request producer thread.\n     * After that:\n     *  - Only THIS thread can call Enqueue(Request),\n     *  - Only THIS thread can call Dequeue(Response),\n     *  - Calling IsEmpty() will tell whether the Request channel is empty.\n     */\n    void AcquireRequestsProducer()\n    {\n        RequestsProducerID = ThreadID();\n    }\n\n    /**\n     * Should be called from a Response producer thread.\n     * After that:\n     *  - Only THIS thread can call Enqueue(Response),\n     *  - Only THIS thread can call Dequeue(Request),\n     *  - Calling IsEmpty() will tell whether the Response channel is empty.\n     */\n    void AcquireResponsesProducer()\n    {\n        ResponsesProducerID = ThreadID();\n    }\n\n// Enqueue:\n    bool Enqueue(const TRequest& Item)\n    {\n        UE_CLOG(ThreadID() != RequestsProducerID, LogTemp, Fatal, TEXT(\"Can't call Enqueue(const TRequest&), invalid thread. Expected: %u, got: %u\"), ResponsesProducerID, ThreadID());\n        return Requests.Enqueue(Item);\n    }\n\n    bool Enqueue(const TResponse& Item)\n    {\n        UE_CLOG(ThreadID() != ResponsesProducerID, LogTemp, Fatal, TEXT(\"Can't call Enqueue(const TResponse&), invalid thread. Expected: %u, got: %u\"), RequestsProducerID, ThreadID());\n        return Responses.Enqueue(Item);\n    }\n\n    bool Enqueue(TRequest&& Item)\n    {\n        UE_CLOG(ThreadID() != RequestsProducerID, LogTemp, Fatal, TEXT(\"Can't call Enqueue(const TRequest&), invalid thread. Expected: %u, got: %u\"), ResponsesProducerID, ThreadID());\n        return Requests.Enqueue(Item);\n    }\n\n    bool Enqueue(TResponse&& Item)\n    {\n        UE_CLOG(ThreadID() != ResponsesProducerID, LogTemp, Fatal, TEXT(\"Can't call Enqueue(const TResponse&), invalid thread. Expected: %u, got: %u\"), RequestsProducerID, ThreadID());\n        return Responses.Enqueue(Item);\n    }\n\n// Dequeue\n    bool Dequeue(TRequest& OutItem)\n    {\n        UE_CLOG(ThreadID() != ResponsesProducerID, LogTemp, Fatal, TEXT(\"Can't call Dequeue(TRequest& OutItem), invalid thread. Expected: %u, got: %u\"), ResponsesProducerID, ThreadID());\n        return Requests.Dequeue(OutItem);\n    }\n\n    bool Dequeue(TResponse& OutItem)\n    {\n        UE_CLOG(ThreadID() != RequestsProducerID, LogTemp, Fatal, TEXT(\"Can't call Dequeue(TResponse& OutItem), invalid thread. Expected: %u, got: %u\"), RequestsProducerID, ThreadID());\n        return Responses.Dequeue(OutItem);\n    }\n\n// Is Empty?\n    bool IsEmpty() const\n    {\n        const uint32 Id = ThreadID();\n\n        if (Id == RequestsProducerID)\n            return Responses.IsEmpty();\n        else if (Id == ResponsesProducerID)\n            return Requests.IsEmpty();\n        else\n        {\n            UE_LOG(LogTemp, Fatal, TEXT(\"Can't call IsEmpty(), from an unknown thread: %d, RequestsProducerID: %u, ResponsesProducerID: %u\"), Id, RequestsProducerID, ResponsesProducerID);\n            return false;\n        }\n    }\n\nprivate:\n    TQueue<TRequest> Requests;\n    TQueue<TResponse> Responses;\n\n    volatile uint32 RequestsProducerID;\n    volatile uint32 ResponsesProducerID;\n};\n\ntemplate<class TRequest, class TResponse>\nTConduit<TRequest, TResponse>::~TConduit()\n{\n\n}\n"
  },
  {
    "path": "Source/InfraworldRuntime/Public/GenUtils.h",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"GenUtils.generated.h\"\n\n// XX - major version\n// YY - minor version\n// ZZ - patch\n#define INFRAWORLD_RUNTIME_VERSION 010000\n\n/**\n * A wrapper for a TArray<uint8> used to avoid inner generics.\n */\nUSTRUCT(BlueprintType)\nstruct INFRAWORLDRUNTIME_API FByteArray\n{\n    GENERATED_USTRUCT_BODY()\n\n    UPROPERTY(BlueprintReadWrite, Category=ArrayWrapper)\n    TArray<uint8> Bytes;\n\n    FByteArray()\n    {\n    }\n\n    FByteArray(const TArray<uint8> &InBytes) :\n        Bytes(InBytes)\n    {\n    }\n};\n\n// ~~~~~ Network CONTEXT ~~~~~\n\n/**\n * The various compression algorithms supported by gRPC.\n */\nUENUM(BlueprintType)\nenum class EGrpcCompressionAlgorithm : uint8\n{\n    CompressNone,\n    CompressDeflate,\n    CompressGzip\n};\n\n/**\n * A ClientContext allows the person implementing a service client to:\n *\n * @todo Implement census/context if necessary.\n *\n * - Add custom metadata key-value pairs that will propagated to the server side.\n * - Control call settings such as compression and authentication.\n * - Initial and trailing metadata coming from the server.\n * - Get performance metrics (ie, census).\n *\n * Context settings are only relevant to the call they are invoked with, that\n * is to say, they aren't sticky. Some of these settings, such as the\n * compression options, can be made persistent at channel construction time\n * @see grpc::CreateCustomChannel()\n *\n * @warning ClientContext instances should not be reused across rpcs.\n * @see https://grpc.io/grpc/cpp/classgrpc_1_1_client_context.html#details\n */\nUSTRUCT(BlueprintType)\nstruct INFRAWORLDRUNTIME_API FGrpcClientContext\n{\n    GENERATED_USTRUCT_BODY()\n\n    /**\n     * Whether the optional Metadata attribute of the context is set.\n     */\n    UPROPERTY(EditAnywhere, meta=(InlineEditConditionToggle), Category=Metadata)\n    bool bOverride_Metadata = false;\n\n    /**\n     * Note: Toggle an 'eye' if you DON'T NEED metadata at all.\n     *\n     * Add the (Key -> Value) pair to the metadata associated with a client call. These are made available at the server\n     * side by the grpc::ServerContext::client_metadata() method.\n     *\n     * Restrictions:\n     *  - Metadata keys can't be empty.\n     *  - Metadata keys can't start with ':'.\n     *\n     * Note: This method should only be called before invoking the rpc.\n     * Note: Keys are metadata keys. If meta_value is binary data, it must end in \"-bin\".\n     * Note: Value The metadata value. If its value is binary, it must be base64-encoding\n     *       https://tools.ietf.org/html/rfc4648#section-4 and Key must end in \"-bin\".\n     */\n    UPROPERTY(BlueprintReadWrite, meta=(editcondition=bOverride_Metadata), Category=Metadata)\n    TMap<FString, FString> Metadata;\n\n    /**\n     * Set the deadline for the client call. Won't apply any deadline if values are (-INF, 0].\n     * @warning This method should only be called before invoking the rpc.\n     */\n    UPROPERTY(BlueprintReadWrite, Category=Metadata)\n    float DeadlineSeconds = -1.0f;\n\n    /**\n     * Set the per call authority header.\n     * @see https://tools.ietf.org/html/rfc7540#section-8.1.2.3.\n     */\n    UPROPERTY(BlueprintReadWrite, Category=Metadata)\n    FString Authority;\n\n    /**\n     * Set an algorithm to be the compression algorithm used for the client call.\n     */\n    UPROPERTY(BlueprintReadWrite, AdvancedDisplay, Category=Metadata)\n    EGrpcCompressionAlgorithm GrpcCompressionAlgorithm;\n\n    /**\n     * EXPERIMENTAL: Set this request to be idempotent.\n     */\n    UPROPERTY(BlueprintReadWrite, AdvancedDisplay, Category=Metadata)\n    bool bIdempotent;\n\n    /**\n     * EXPERIMENTAL: Set this request to be cacheable.\n     */\n    UPROPERTY(BlueprintReadWrite, AdvancedDisplay, Category=Metadata)\n    bool bCacheable;\n\n    /**\n     * EXPERIMENTAL: Trigger wait-for-ready or not on this request.\n     */\n    UPROPERTY(BlueprintReadWrite, AdvancedDisplay, Category=Metadata)\n    bool bWaitForReady;\n\n    /**\n     * Flag whether the initial metadata should be corked. If corked is true, then the initial metadata will be colasced\n     * with the write of first message in the stream.\n     */\n    UPROPERTY(BlueprintReadWrite, AdvancedDisplay, Category=Metadata)\n    bool bInitialMetadataCorked;\n};\n\n\n// ~~~~~ Wrappers for CONTEXT and STATUS ~~~~~\n\ntemplate<class TRequestType>\nstruct TRequestWithContext\n{\n    TRequestType Request;\n    FGrpcClientContext Context;\n\n    TRequestWithContext()\n    {\n    }\n\n    TRequestWithContext(const TRequestType& InRequest, const FGrpcClientContext& InContext) :\n        Request(InRequest),\n        Context(InContext)\n    {\n    }\n};\n\n// Special constructor, automatically inferring arguments.\ntemplate<class T>\nTRequestWithContext<T> TRequestWithContext$New(const T& InRequest, const FGrpcClientContext& InContext)\n{\n    return TRequestWithContext<T>(InRequest, InContext);\n}\n\n/**\n * GRPC error code.\n *\n * @see https://grpc.io/grpc/cpp/namespacegrpc.html#aff1730578c90160528f6a8d67ef5c43b\n */\nUENUM(BlueprintType)\nenum class EGrpcStatusCode : uint8\n{\n    /**\n     * Not an error, returned on success.\n     */\n    Ok = 0,\n\n    /**\n     * The operation was cancelled (typically by the caller).\n     */\n    Cancelled = 1,\n\n    /**\n     * Unknown error. An example of where this error may be returned is if a\n     * Status value received from another address space belongs to an error-space\n     * that is not known in this address space. Also errors raised by APIs that\n     * do not return enough error information may be converted to this error.\n     */\n    Unknown = 2,\n\n    /**\n     * Client specified an invalid argument. Note that this differs from\n     * FailedPrecondition. InvalidArgument indicates arguments that are\n     * problematic regardless of the state of the system (e.g., a malformed file\n     * name).\n     */\n    InvalidArgument = 3,\n\n    /**\n     * Deadline expired before operation could complete. For operations that\n     * change the state of the system, this error may be returned even if the\n     * operation has completed successfully. For example, a successful response\n     * from a server could have been delayed long enough for the deadline to\n     * expire.\n     */\n    DeadlineExceeded = 4,\n\n    /**\n     * Some requested entity (e.g., file or directory) was not found.\n     */\n    NotFound = 5,\n\n    /**\n     * Some entity that we attempted to create (e.g., file or directory) already\n     * exists.\n     */\n    AlreadyExists = 6,\n\n    /**\n     * The caller does not have permission to execute the specified operation.\n     * PermissionDenied must not be used for rejections caused by exhausting\n     * some resource (use ResourceExhausted instead for those errors).\n     * PermissionDenied must not be used if the caller can not be identified\n     * (use Unauthenticated instead for those errors).\n     */\n    PermissionDenied = 7,\n\n    /**\n     * The request does not have valid authentication credentials for the\n     * operation.\n     */\n    Unauthenticated = 16,\n\n    /**\n     * Some resource has been exhausted, perhaps a per-user quota, or perhaps the\n     * entire file system is out of space.\n     */\n    ResourceExhausted = 8,\n\n    /**\n     * Operation was rejected because the system is not in a state required for\n     * the operation's execution. For example, directory to be deleted may be\n     * non-empty, an rmdir operation is applied to a non-directory, etc.\n     *\n     * A litmus test that may help a service implementor in deciding\n     * between FailedPrecondition, Aborted, and Unavailable:\n     *  (a) Use Unavailable if the client can retry just the failing call.\n     *  (b) Use Aborted if the client should retry at a higher-level\n     *      (e.g., restarting a read-modify-write sequence).\n     *  (c) Use FailedPrecondition if the client should not retry until\n     *      the system state has been explicitly fixed. E.g., if an \"rmdir\"\n     *      fails because the directory is non-empty, FailedPrecondition\n     *      should be returned since the client should not retry unless\n     *      they have first fixed up the directory by deleting files from it.\n     *  (d) Use FailedPrecondition if the client performs conditional\n     *      REST Get/Update/Delete on a resource and the resource on the\n     *      server does not match the condition. E.g., conflicting\n     *      read-modify-write on the same resource.\n     */\n    FailedPrecondition = 9,\n\n    /**\n     * The operation was aborted, typically due to a concurrency issue l *\n     * sequencer check failures, transaction aborts, etc.\n     *\n     * See litmus test above for deciding between FailedPrecondition, Aborted,\n     * and Unavailable.\n     */\n    Aborted = 10,\n\n    /**\n     * Operation was attempted past the valid range. E.g., seeking or reading\n     * past end of file.\n     *\n     * Unlike InvalidArgument, this error indicates a problem that may be fixed\n     * if the system state changes. For example, a 32-bit file system will\n     * generate InvalidArgument if asked to read at an offset that is not in the\n     * range [0,2^32-1], but it will generate OutOfRange if asked to read from\n     * an offset past the current file size.\n     *\n     * There is a fair bit of overlap between FailedPrecondition and\n     * OutOfRange. We recommend using OutOfRange (the more specific error)\n     * when it applies so that callers who are iterating through a space can\n     * easily look for an OutOfRange error to detect when they are done.\n     */\n    OutOfRange = 11,\n\n    /**\n     * Operation is not implemented or not supported/enabled in this service.\n     */\n    Unimplemented = 12,\n\n    /**\n     * Internal errors. Means some invariants expected by underlying System has\n     * been broken. If you see one of these errors, Something is very broken.\n     */\n    Internal = 13,\n\n    /**\n     * The service is currently unavailable. This is a most likely a transient\n     * condition and may be corrected by retrying with a backoff.\n     */\n\n    /**\n     * See litmus test above for deciding between FailedPrecondition, Aborted,\n     * and Unavailable.\n     */\n    Unavailable = 14,\n\n    /**\n     * Unrecoverable data loss or corruption.\n     */\n    DataLoss = 15\n};\n\n/**\n * Did it work? If it didn't, why?\n *\n * @see https://grpc.io/grpc/cpp/classgrpc_1_1_status.html#details\n */\nUSTRUCT(BlueprintType)\nstruct INFRAWORLDRUNTIME_API FGrpcStatus\n{\n    GENERATED_USTRUCT_BODY()\n\n    /**\n     * Return the instance's error code.\n     */\n    UPROPERTY(BlueprintReadOnly, Category=Status)\n    EGrpcStatusCode ErrorCode;\n\n    /**\n     * Return the instance's error message.\n     */\n    UPROPERTY(BlueprintReadOnly, Category=Status)\n    FString ErrorMessage;\n\n    /**\n     * The (binary) error details. Usually it contains a serialized google.rpc.Status proto.\n     */\n    UPROPERTY(BlueprintReadOnly, Category=Status)\n    FString ErrorDetails;\n};\n\ntemplate<class TResponseType>\nstruct TResponseWithStatus\n{\n    TResponseType Response;\n    FGrpcStatus Status;\n\n    TResponseWithStatus()\n    {\n    }\n\n    TResponseWithStatus(const TResponseType& InResponse, const FGrpcStatus& InStatus) :\n        Response(InResponse),\n        Status(InStatus)\n    {\n    }\n};\n"
  },
  {
    "path": "Source/InfraworldRuntime/Public/GrpcIncludesBegin.h",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n// Disable some warnings in GRPC\n#if PLATFORM_WINDOWS\n\t#pragma warning(push)\n\t#pragma warning (disable : 4125)// decimal digit terminates...\n\t#pragma warning (disable : 4647)// behavior change __is_pod...\n\t#pragma warning (disable : 4668)// 'symbol' is not defined as a preprocessor macro...\n\t#pragma warning (disable : 4456)// declaration of 'size' hides previous local declaration\n\t#pragma warning (disable : 4577)// 'noexcept' used with no exception handling mode specified\n\t#pragma warning (disable : 4946)// reinterpret_cast used between related classes\n\t#pragma warning (disable : 4005)// 'TEXT': macro redefinition\n\t#pragma warning (disable : 4582)// constructor is not implicitly called\n\t#pragma warning (disable : 4583)// destructor is not implicitly called\n\t#pragma warning (disable : 4800)// Implicit conversion from 'type' to bool. Possible information loss\n\n\t#ifdef WINDOWS_PLATFORM_TYPES_GUARD\n\t\t#pragma warning(push)\n\t\t#include \"Windows/HideWindowsPlatformTypes.h\"\n\t#endif\n#elif PLATFORM_COMPILER_CLANG\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic ignored \"-Wundef\"\n\t#pragma clang diagnostic ignored \"-Wshadow\"\n#endif\n"
  },
  {
    "path": "Source/InfraworldRuntime/Public/GrpcIncludesEnd.h",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n// Since GRPC actively uses winapi, we need to forbid windows macros\n// (such as GetMessage, MemoryBarrier, etc.) in our remaining code.\n// To do it, we 'wrap' all the C++ file's including ANY GRPC header files\n// content into Allow/Hide WindowsPlatformTypes.\n// We're unable to 'isolate' the WinAPI usage within a single C++ file thanks to Unity Build.\n#if PLATFORM_WINDOWS\n\t#pragma warning(pop)\n\t#ifndef UE4_MINIMAL_WINDOWS_INCLUDE\n\t\t#define UE4_MINIMAL_WINDOWS_INCLUDE\n\t#endif\n\t#include \"Windows/AllowWindowsPlatformTypes.h\"\n#elif PLATFORM_COMPILER_CLANG\n\t#pragma clang diagnostic pop\n#endif\n"
  },
  {
    "path": "Source/InfraworldRuntime/Public/GrpcUriValidator.h",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#pragma once\n\n#include \"CoreMinimal.h\"\n\nclass FGrpcUriValidator\n{\npublic:\n    /**\n     * Attempts to validate a URI, further provided to grpc::CreateChannel function.\n     * It does not tries to establish any kind of connections, so it checks only format.\n     *\n     * @param MaybeGrpcUri Grpc URI to validate.\n     * @param OutError Error message if any.\n     *\n     * @return True if the URI is valid and thus could be used, false otherwise.\n     */\n    static bool Validate(const FString& MaybeGrpcUri, FString& OutError);\n};\n"
  },
  {
    "path": "Source/InfraworldRuntime/Public/InfraworldRuntime.h",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#pragma once\n\n#include \"Modules/ModuleManager.h\"\n\nDECLARE_LOG_CATEGORY_EXTERN(LogInfraworldRuntime, Log, All);\n\nclass FInfraworldRuntimeModule : public IModuleInterface\n{\npublic:\n\n\t/** IModuleInterface implementation */\n\tvirtual void StartupModule() override;\n\tvirtual void ShutdownModule() override;\n};\n"
  },
  {
    "path": "Source/InfraworldRuntime/Public/RpcClient.h",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n\n\n#include \"Containers/Queue.h\"\n#include \"Templates/SubclassOf.h\"\n#include \"Templates/Atomic.h\"\n\n#include \"RpcClientWorker.h\"\n#include \"ChannelCredentials.h\"\n\n#include \"RpcClient.generated.h\"\n\n\nDECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FRpcErrorSignature, URpcClient*, Dispatcher, const FRpcError&, Error);\n\n/**\n * An RPC client used to interact with GRPC services from Blueprints and UE-compatible C++ code.\n * Being used as a base class for generated RPC clients, an RPC Client contains a set of methods to manage an RPC Channel.\n *\n * @note You should never instantiate it directly.\n *\n * You should use a Proto2Cpp converter to create GRPC wrappers for an every single service.\n */\nUCLASS(Abstract, BlueprintType, Blueprintable)\nclass INFRAWORLDRUNTIME_API URpcClient : public UObject\n{\n\tGENERATED_BODY()\n\n    bool Init(const FString& URI, UChannelCredentials* ChannelCredentials);\n\npublic:\n\tURpcClient();\n\tvirtual ~URpcClient();\n\n    // Being called in implementations\n    virtual void HierarchicalInit() PURE_VIRTUAL(URpcClient::HierarchicalInit,);\n\n    // Being called in implementations\n    virtual void HierarchicalUpdate() PURE_VIRTUAL(URpcClient::HierarchicalUpdate,);\n\n    /**\n     * Stops and disables this instance of RPC Client.\n     * This operation is irreversible, you can't either send or receive requests and responses after doing so.\n     *\n     * @param bSynchronous\n     *        Stop and wait a sec. Oh when you look at me like that my darling - What did you expect?\n     *        If seriously - you should think thousand times before unchecking this option, because\n     *        you can experience heavy and unpredictable racing hazard.\n     */\n    UFUNCTION(BlueprintCallable, Category=\"Vizor|RPC Client\")\n    void Stop(bool bSynchronous = true);\n\n    /**\n     * An update function, used to tell a Client, when to check queries and dispatch messages.\n     * In widget (for example) you should call it every update (or redraw/invalidate).\n     *\n     * @note that frequency, you're calling this method won't ever affect the speed of message processing.\n     * @deprecated No need to call this function anymore.\n     */\n    UFUNCTION(BlueprintCallable, Category = \"Vizor|RPC Client\", meta = (DeprecatedFunction, DeprecationMessage = \"No need to call this function anymore: Updates now are being dispatched automatically\"))\n    void Update();\n\n    /**\n     * Checks whether the RPC Client could send requests.\n     *\n     * @return True if the RPC Client is properly initialized and can send requests. If not - all requests will be ignored.\n     */\n    UFUNCTION(BlueprintCallable, BlueprintPure, Category=\"Vizor|RPC Client\", meta=(DisplayName=\"Can Send Requests?\"))\n    bool CanSendRequests() const;\n\n    /**\n     * Instantiates a new RPC Dispatcher. You should use this function, not 'Construct Object from Class', to properly initialize the instance.\n     *\n     * @param Class\n     *        A subclass of RPC Client, that will be instantiated. Please don't select an abstract 'Rpc Client'.\n     * @param InstantiationParameters\n     *        Parameters, will be used for instantiation,\n     * @param Outer\n     *        An outer object, None (or empty) is valid as well, if so, GetTransientPackage() will be used to retrieve a static outer.\n     * @return A newly created instance of RPC Client.\n     */\n    UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category=\"Vizor|RPC Client\", meta=(DisplayName=\"Create RPC Client\", DeterminesOutputType=\"Class\", DeprecatedFunction, DeprecationMessage=\"Use function, accepting URI and ChannelCredentials instead\"))\n    static URpcClient* CreateRpcClient(TSubclassOf<URpcClient> Class, FRpcClientInstantiationParameters InstantiationParameters, UObject* Outer = nullptr);\n    \n    /**\n     * Instantiates a new RPC Dispatcher. You should use this function, not 'Construct Object from Class', to properly initialize the instance.\n     *\n     * @param Class\n     *        A subclass of RPC Client, that will be instantiated. Please don't select an abstract 'Rpc Client'.\n     * @param URI\n     *        Endpoint URI, will be used to establish connection.\n     *        Must not start with 'http://' or 'https://' or any URL scheme.\n     *        Must not have URL path, such as 'www.hello.eu/paths/are/not/allowed'\n     *        Must be either a domain name or an IP address with or without an explicit port. 80'th port is used by default.\n     * @param ChannelCredentials\n     *        Credentials to use for the created RPC client.\n     * @param Outer\n     *        An outer object, None (or empty) is valid as well, if so, GetTransientPackage() will be used to retrieve a static outer.\n     * @return A newly created instance of RPC Client.\n     */\n    UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category=\"Vizor|RPC Client\", meta=(DisplayName=\"Create RPC Client\", DeterminesOutputType=\"Class\"))\n    static URpcClient* CreateRpcClientUri(TSubclassOf<URpcClient> Class, const FString& URI, UChannelCredentials* ChannelCredentials, UObject* Outer = nullptr);\n\n    /**\n     * Called when did received any kind of error.\n     */\n    UPROPERTY(BlueprintAssignable, Category=\"Vizor|RPC Client\", meta=(DisplayName=\"Event RPC Error\"))\n    FRpcErrorSignature EventRpcError;\n\nprotected:\n    /** A pointer to an inner RpcClientWorker sending and receiving messages */\n    TUniquePtr<RpcClientWorker> InnerWorker;\n\nprivate:\n    virtual void BeginDestroy() override;\n\n    /** Whether the RPC Client could send requests or not */\n    bool bCanSendRequests = false;\n\n    /** A thread, where RPC client worker will reside */\n\tTAtomic<FRunnableThread*> Thread = { nullptr };\n\n    /** An accumulator for error messages */\n    TQueue<FRpcError> ErrorMessageQueue;\n\n    /**\n     * Global engine ticker handler\n     * Only \"IsValid() -> true\" if this RPC client \"CanSendRequests() -> true\"\n     */\n    FDelegateHandle TickDelegateHandle;\n};\n\ntemplate <class T>\nFORCEINLINE T* NewRpcClient(const FString& URI, UChannelCredentials* ChannelCredentials, UObject* Outer = nullptr)\n{\n    static_assert(TIsDerivedFrom<T, URpcClient>::IsDerived, \"T must derive URpcClient\");\n    static_assert(!TIsSame<T, URpcClient>::Value, \"T must derive URpcClient, but mustn't be a bare URpcClient\");\n\n    return Cast<T>(URpcClient::CreateRpcClientUri(T::StaticClass(), URI, ChannelCredentials, Outer));\n}\n"
  },
  {
    "path": "Source/InfraworldRuntime/Public/RpcClientWorker.h",
    "content": "/*\n * Copyright 2018 Vizor Games LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n#pragma once\n\n#include \"CoreMinimal.h\"\n\n#include \"Containers/Queue.h\"\n#include \"ChannelCredentials.h\"\n#include \"HAL/Runnable.h\"\n#include \"InfraworldRuntime.h\"\n#include <memory>\n#include <chrono>\n\n#include \"Templates/Atomic.h\"\n\nenum class ERpcWorkerState : uint8\n{\n\tPendingInitialization,\n\tInitializing,\n\tWorking,\n\tPendingShutdown,\n\tShutdown\n};\n\nclass FGenAsyncRequest;\n\n/**\n * Base RPC Client Worker, it 'lives' in a separate thread and updates all conduits with responses.\n */\nclass INFRAWORLDRUNTIME_API RpcClientWorker : public FRunnable\n{\npublic:\n    RpcClientWorker();\n\tvirtual ~RpcClientWorker();\n\n    virtual uint32 Run() override;\n\n    FORCEINLINE bool IsPendingStopped() const\n    {\n        return WorkerState.Load() == ERpcWorkerState::PendingShutdown;\n    }\n\n    FORCEINLINE void MarkPendingStopped()\n    {\n\t\tUE_LOG(LogInfraworldRuntime, Log, TEXT(\"RpcClientWorker at [%p] Marking pending stopped\"), this);\n\t\tconst ERpcWorkerState PreviousWorkerState = WorkerState.Exchange(ERpcWorkerState::PendingShutdown);\n\t\tstatic const TSet<ERpcWorkerState> ExpectedWorkerStates = {\n\t\t\tERpcWorkerState::PendingInitialization, ERpcWorkerState::Initializing, ERpcWorkerState::Working\n\t\t};\n\t\tensureAlways(ExpectedWorkerStates.Contains(PreviousWorkerState));    \n    }\n\t\n    virtual bool HierarchicalInit() = 0;\n\tvirtual void HierarchicalUpdate() = 0;\n\n    void DispatchError(const FString& ErrorMessage);\n\n//public:\n    FString URI;\n    UChannelCredentials* ChannelCredentials;\n\n    TQueue<FRpcError>* ErrorMessageQueue;\n\t\nprotected:\n\tTAtomic<ERpcWorkerState> WorkerState;\n};\n"
  },
  {
    "path": "Source/InfraworldRuntime/Public/WorkerUtils.h",
    "content": "#pragma once\n\n#include \"GenUtils.h\"\n#include \"CastUtils.h\"\n#include \"Templates/Invoke.h\"\n#include \"RpcClientWorker.h\"\n\n#include \"GrpcIncludesBegin.h\"\n\n#include \"ChannelProvider.h\"\n#include <grpc/support/log.h>\n#include <grpc++/channel.h>\n#include <grpc++/client_context.h>\n#include <grpc++/completion_queue.h>\n#include <grpcpp/impl/codegen/async_unary_call.h>\n\n#include \"GrpcIncludesEnd.h\"\n\ntemplate <class TStub>\nclass TStubbedRpcWorker : public RpcClientWorker\n{\npublic:\n\ttemplate <class TUnrealRequest, class TProtoRequest, class TUnrealResponse, class TProtoResponse, class TStubRequestFunctionPointer>\n\tTResponseWithStatus<TUnrealResponse> AsyncRequest(const TUnrealRequest Request, const FGrpcClientContext Context, const TStubRequestFunctionPointer MemberPointer)\n\t{\n\t\tconst TProtoRequest ClientRequest = casts::Proto_Cast<TProtoRequest>(Request);\n\t\t\n\t\tgrpc::ClientContext ClientContext;\n\t\tcasts::CastClientContext(Context, ClientContext);\n\n\t\tgrpc::CompletionQueue Queue;\n\t    grpc::Status Status;\n\t\t\n\t    std::unique_ptr<grpc::ClientAsyncResponseReader<TProtoResponse>> Rpc(Invoke(MemberPointer, Stub.get(), &ClientContext, ClientRequest, &Queue));\n\n\t    TProtoResponse Response;\n\t    Rpc->Finish(&Response, &Status, (void*)1);\n\n\t    void* got_tag;\n\t    bool ok = false;\n\n\t    while (true)\n\t\t{\n\t\t\tconst std::chrono::seconds SingleWaitDuration = std::chrono::seconds(1);\n\t\t\tconst std::chrono::time_point<system_clock> Deadline = std::chrono::system_clock::now() +\n\t\t\t\tSingleWaitDuration;\n    \t\t\n\t        const grpc::CompletionQueue::NextStatus NextStatus = Queue.AsyncNext(&got_tag, &ok, Deadline);\n\n\t\t\tif (NextStatus == grpc::CompletionQueue::NextStatus::GOT_EVENT)\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n    \t\t\n\t\t\tif (IsPendingStopped())\n\t\t\t{\n\t\t\t\tClientContext.TryCancel();\n\t\t\t}\n\t\t}\n\t\t\n\t    GPR_ASSERT(got_tag == (void*)1);\n\t    GPR_ASSERT(ok);\n\n\t    FGrpcStatus GrpcStatus;\n\n\t    casts::CastStatus(Status, GrpcStatus);\n\t    TResponseWithStatus<TUnrealResponse> Result(casts::Proto_Cast<TUnrealResponse>(Response), GrpcStatus);\n\n\t    return Result;\n\t}\n\nprotected:\n\tstd::unique_ptr<TStub> Stub;\n};\n"
  }
]