{"@attributes":{"version":"2.0"},"channel":{"title":"Radomir Sohlich","link":"https:\/\/sohlich.github.io\/index.xml","description":"Recent content on Radomir Sohlich","generator":"Hugo -- gohugo.io","copyright":"\u00a9 2017 Radomir Sohlich","lastBuildDate":"Mon, 18 Sep 2017 18:32:54 +0200","item":[{"title":"Golang: Don\u2019t afraid of makefiles","link":"https:\/\/sohlich.github.io\/post\/go_makefile\/","pubDate":"Mon, 18 Sep 2017 18:32:54 +0200","guid":"https:\/\/sohlich.github.io\/post\/go_makefile\/","description":"\n\n<p>I&rsquo;m using Golang for a while. During the development, I was used to repeatedly execute &ldquo;go build&rdquo;,&ldquo;go test&rdquo; manually. This was a bad habit on which I resign. It is not so painful if you use simple command without any args. But in case of more complex tasks, naturally, it is going to be a pain. There are few options you can consider as a way out. You can use a bash script to do the work for you. Or better, at least for me, you can write a makefile. The make tool is there for this reason and in the makefile you can keep all your common tasks together. I&rsquo;m not &ldquo;make tool guru&rdquo; to be able to educate how to write the proper one, but in this post, I put together the makefile which works for most of my projects. Let&rsquo;s go through it.<\/p>\n\n<pre><code>    # Go parameters\n    GOCMD=go\n    GOBUILD=$(GOCMD) build\n    GOCLEAN=$(GOCMD) clean\n    GOTEST=$(GOCMD) test\n    GOGET=$(GOCMD) get\n    BINARY_NAME=mybinary\n    BINARY_UNIX=$(BINARY_NAME)_unix\n    \n    all: test build\n    build: \n            $(GOBUILD) -o $(BINARY_NAME) -v\n    test: \n            $(GOTEST) -v .\/...\n    clean: \n            $(GOCLEAN)\n            rm -f $(BINARY_NAME)\n            rm -f $(BINARY_UNIX)\n    run:\n            $(GOBUILD) -o $(BINARY_NAME) -v .\/...\n            .\/$(BINARY_NAME)\n    deps:\n            $(GOGET) github.com\/markbates\/goth\n            $(GOGET) github.com\/markbates\/pop\n    \n    \n    # Cross compilation\n    build-linux:\n            CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(BINARY_UNIX) -v\n    docker-build:\n            docker run --rm -it -v &quot;$(GOPATH)&quot;:\/go -w \/go\/src\/bitbucket.org\/rsohlich\/makepost golang:latest go build -o &quot;$(BINARY_UNIX)&quot; -v\n<\/code><\/pre>\n\n<p>Let\u2019s say I like to keep the idea of the DRY rule. So it is handy to declare commonly used commands and variables at the top of the file. And refer to them further in the file.<\/p>\n\n<pre><code># Basic go commands\nGOCMD=go\nGOBUILD=$(GOCMD) build\nGOCLEAN=$(GOCMD) clean\nGOTEST=$(GOCMD) test\nGOGET=$(GOCMD) get\n\n# Binary names\nBINARY_NAME=mybinary\nBINARY_UNIX=$(BINARY_NAME)_unix\n<\/code><\/pre>\n\n<p>The makefile targets are defined bellow labels like \u201c<name>:\u201d. These are executed by make tool if the parameter for make is given. If no parameter is provided to make tool, the first task is executed. In this case the \u201call\u201d task is executed.<\/p>\n\n<pre><code>&gt; make run \/\/ call specific task\n&gt; make \/\/ make tool calls &quot;all&quot; task\n<\/code><\/pre>\n\n<h2 id=\"basic-commands\">Basic commands<\/h2>\n\n<p>One of the essential parts of the makefile is the build step. Using the variable $(GOBUILD) the \u201cgo build\u201d command is executed. The binary name is defined by \u201c-o $(BINARY_NAME)\u201d and I found useful to switch to the verbose mode with \u201c-v\u201d. With verbose mode, you can see the currently built packages.<\/p>\n\n<pre><code>build:\n  $(GOBUILD) -o $(BINARY_NAME) -v \/\/ expands to: &quot;go build -o mybinary -v&quot;\n<\/code><\/pre>\n\n<p>Just because a lot of us are just lazy, the \u201crun\u201d target is here. The target builds the binary and executes the application consequently.<\/p>\n\n<pre><code>run:\n        $(GOBUILD) -o $(BINARY_NAME) -v .\/...\n        .\/$(BINARY_NAME)\n<\/code><\/pre>\n\n<p>Naturally, the test command should be the part of the project makefile. I personally always choose the verbose mode to be able to debug and watch the test run better.<\/p>\n\n<pre><code>test:\n  $(GOTEST) -v .\/...\n<\/code><\/pre>\n\n<p>If the project uses CI\/CD or just for consistency, it is good to keep the list of dependencies used in packages. This is done by the \u201cdeps\u201d task, which should get all the necessary dependencies by \u201cgo get\u201d command.<\/p>\n\n<pre><code>deps:\n        $(GOGET) github.com\/markbates\/goth\n        $(GOGET) github.com\/markbates\/pop\n<\/code><\/pre>\n\n<p>To wrap up this section of useful commands, the clean command is accommodated into makefile. The \u201crm -f\u201d command is added to remove binary with the custom name in $(BINARY_XXX) variable. Typically another clean-up command could be part of this make section.<\/p>\n\n<pre><code>clean: \n        $(GOCLEAN)\n        rm -f $(BINARY_NAME)\n        rm -f $(BINARY_UNIX)\n<\/code><\/pre>\n\n<h2 id=\"crosscompilation-commands\">Crosscompilation commands<\/h2>\n\n<p>If the project is intended to run on another platform than the one where it is developed, it is useful to include cross compilation commands to make file. I usually run the binaries on\nLinux platform in the container, so the makefile contains the Linux build.<\/p>\n\n<pre><code>build-linux:\n        CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(BINARY_UNIX) -v\n<\/code><\/pre>\n\n<p>If your code use C binding you could get stuck a little bit. The issue with CGO is that you need a gcc compatible for given platform. So if the development is done on OSX\/Windows you need to build gcc to be able to compile for Linux. At least for me, the configuration of gcc to cross compile the C code is not so straightforward on OSX. If the CGO is needed, the docker image is the best way how to create Linux build. The only requirement: Docker has to be installed.<\/p>\n\n<pre><code>docker-build:\n        docker run --rm -it -v &quot;$(GOPATH)&quot;:\/go -w \/go\/src\/bitbucket.org\/rsohlich\/makepost golang:latest go build -o &quot;$(BINARY_UNIX)&quot; -v\n<\/code><\/pre>\n\n<h2 id=\"summary\">Summary<\/h2>\n\n<p>This way you can make your go development process more effective and fluent. The makefile used in this post is available <a href=\"https:\/\/gist.github.com\/sohlich\/8432e7c1bd56bc395b101d1ba444e982\">here<\/a>. Don\u2019t hesitate to comment or ask questions, I\u2019ll be happy to answer or talk about this. Enjoy!<\/p>\n"},{"title":"Deploy on Clever Cloud with Bitbucket Pipelines","link":"https:\/\/sohlich.github.io\/post\/clever_cloud_pipelines\/","pubDate":"Thu, 31 Aug 2017 05:08:10 +0200","guid":"https:\/\/sohlich.github.io\/post\/clever_cloud_pipelines\/","description":"\n\n<p>There are a lot of CI tools that are available on the market. These are usualy free for open-source project. Recently I\u2019ve come across the <a href=\"https:\/\/bitbucket.org\/product\/features\/pipelines\">Bitbucket Pipelines<\/a> feature that is free also for private ones, with limitation naturally. It is the CI\/CD tool bounded to Bitbucket repository, that is based on containers.\nIn this post, I\u2019d like to walk through the setup of Pipelines to deploy the build on <a href=\"https:\/\/www.clever-cloud.com\">Clever Cloud<\/a>. The Clever Cloud is PaaS provider, which I have been using for about 2 years. They come up with a lot of platforms, but the best one and my favorite is the Docker. With this one, it is possible to deploy any Docker image.\nFor this post, I\u2019ve chosen the Go application to be deployed on top of the Docker platform, but the same approach could be used with other languages.<\/p>\n\n<h2 id=\"repository-content\">Repository content<\/h2>\n\n<p>First, we need to add a Dockerfile to application folder (for the simplicity). The most simple Dockerfile could look like following one.<\/p>\n\n<p>${PROJECT_FOLDER}\/Dockerfile<\/p>\n\n<pre><code>    FROM golang:latest\n    #copy the binary of app\n    COPY linux_bin linux_bin\n    EXPOSE 8080\n    #execute the binary\n    ENTRYPOINT [&quot;.\/linux_bin&quot;]\n<\/code><\/pre>\n\n<p>The important step in Dockerfile is the exposing of port 8080. The Clever Cloud requires this port as a default HTTP port. If the application does not respond on this port, the monitor tool evaluates the application as non-working and the deployment fails.<\/p>\n\n<p>The binary itself will be built during the Pipelines run. We can test the Dockerfile by building the binary. As we are running the binary within the container, it must be compiled for Linux and amd64 architecture.<\/p>\n\n<pre><code>    &gt; GOOS=linux GOARCH=AMD64 go build -o linux_bin -v\n    &gt; docker build --rm -t clever_cloud_deploy .\n    Sending build context to Docker daemon  42.55MB\n    Step 1\/4 : FROM golang:alpine\n    Step 2\/4 : COPY linux_bin linux_bin\n    Step 3\/4 : EXPOSE 8080\n    Step 4\/4 : CMD .\/linux_bin\n    Successfully built 692db10e1840\n    Successfully tagged clever_cloud_deploy:latest\n    &gt; docker run --rm -it clever_cloud_deploy:latest\n<\/code><\/pre>\n\n<p>So the Dockerfile is OK. Now the Pipelines config file must be created. The easiest way how to do that is to copy the config from bitbucket docs and modify it to fit your needs. (<a href=\"https:\/\/confluence.atlassian.com\/bitbucket\/language-guides-856821477.html\">Bitbucket Docs<\/a>)<\/p>\n\n<p>${PROJECT_FOLDER}\/bitbucket-pipelines.yml<\/p>\n\n<pre><code>    image: golang:latest\n    pipelines:\n      default:\n        - step:\n            caches:\n              - gocache        # custom golang cache\n            script: # Modify the commands below to build your repository.\n              - PACKAGE_PATH=&quot;${GOPATH}\/src\/bitbucket.org\/${BITBUCKET_REPO_OWNER}\/${BITBUCKET_REPO_SLUG}&quot;\n              - mkdir -pv &quot;${PACKAGE_PATH}&quot;\n              - tar -cO --exclude-vcs --exclude=bitbucket-pipelines.yml . | tar -xv -C &quot;${PACKAGE_PATH}&quot;\n              - cd &quot;${PACKAGE_PATH}&quot;\n              - go get -v\n              - go build -o linux_bin -v\n              - go test -v\n\n<\/code><\/pre>\n\n<h2 id=\"deployment-to-clever-cloud\">Deployment to Clever Cloud<\/h2>\n\n<p>The deployment of an application to Clever Cloud is done via push to the git repository. The push to the master branch invokes the deployment on the provider side. The Docker platform was chosen so the Dockerfile must be the essential part of pushed changes.  Naturally, all the files used in Dockerfile are needed. The deployment on the provider side, in fact, consists of the Docker file build and start of the container based on the created docker image.<\/p>\n\n<h3 id=\"ssh-keys\">SSH Keys<\/h3>\n\n<p>To be able to push into the Clever Cloud repository, the SSH public key must be provided. The existing key could be added or you can generate a new one in Bitbucket repository (Settings \u2192 Pipelines \u2192 SSHKeys) and configure it to be allowed to use in Clever Cloud (see Clever Cloud settings).<\/p>\n\n<h3 id=\"clever-cloud-repository-and-config\">Clever Cloud repository and config<\/h3>\n\n<p>Each application in Clever Cloud has so called \u201cdeployment URL\u201d defined in information tab in the Clever Cloud console (administration page). The URL is similar to one below.<\/p>\n\n<pre><code>    git+ssh:\/\/git@push-par-clevercloud-customers.services.clever-cloud.com\/app_b5a2def7-ed24-4fde-bcf2-5d0525c2d00b.git\n<\/code><\/pre>\n\n<p>This URL would be used in Pipelines config file as a remote git repository to push the built files. The deploy than will consist of these steps:<\/p>\n\n<ul>\n<li>initialize Git repository<\/li>\n<li>commit all files needed for Dockerfile build<\/li>\n<li>push to remote master branch<\/li>\n<\/ul>\n\n<p>Before we do that we need to add the push-par-clevercloud-customers.services.clever-cloud.com host to \u201cknown hosts\u201d. This is done via Settings \u2192 SSH \u2192 Known Hosts section.\nAfter this is done the steps described above can be added to Pipelines config file.<\/p>\n\n<p>${PROJECT_FOLDER}\/bitbucket-pipelines.yml (partial)<\/p>\n\n<pre><code>              - git init\n              - git config user.name &quot;Pipeline&quot; &amp;&amp; git config user.email &quot;pipeline@example.org&quot;\n              # Use -f switch to override .gitignore file\n              - git add -f linux_bin \n              - git commit -m &quot;init&quot;\n<\/code><\/pre>\n\n<p>Initialisation of the repository, configuration of user and email is needed. Without this git refuses to work properly.<\/p>\n\n<p>Finally, push all the changes to Clever Cloud repo using the \u2014force switch.<\/p>\n\n<pre><code>    git push git+ssh:\/\/git@push-par-clevercloud-customers.services.clever-cloud.com\/app_b5a2def7-ed24-4fde-bcf2-5d0525c2d00b.git master --force\n<\/code><\/pre>\n\n<p>The complete Pipelines configuration file could look like this.<\/p>\n\n<p>${PROJECT_FOLDER}\/bitbucket-pipelines.yml<\/p>\n\n<pre><code>    image: golang:latest\n    pipelines:\n      default:\n        - step:\n            caches:\n              - gocache        # custom golang cache\n              - xchache        # custom golang cache\n              - pkgincache        # custom golang cache\n            script: # Modify the commands below to build your repository.\n              - PACKAGE_PATH=&quot;${GOPATH}\/src\/bitbucket.org\/${BITBUCKET_REPO_OWNER}\/${BITBUCKET_REPO_SLUG}&quot;\n              - mkdir -pv &quot;${PACKAGE_PATH}&quot;\n              - tar -cO --exclude-vcs --exclude=bitbucket-pipelines.yml . | tar -xv -C &quot;${PACKAGE_PATH}&quot;\n              - cd &quot;${PACKAGE_PATH}&quot;\n              - go get -v\n              - go build -o linux_bin -v\n              - go test -v\n              - git init\n              # Deployment to clever cloud\n              - git config user.name &quot;Pipeline&quot; &amp;&amp; git config user.email &quot;pipeline@example.org&quot;\n              - git add -f linux_bin\n              - git commit -m &quot;init&quot;\n              - git push git+ssh:\/\/git@push-par-clevercloud-customers.services.clever-cloud.com\/app_b5a2def7-ed24-4fde-bcf2-5d0525c2d00b.git master --force\n<\/code><\/pre>\n\n<p>That\u2019s it. After your commit arrive to Bitbucket repository the Pipelines run is started, subsequently the build deployed on Clever Cloud. Enjoy!<\/p>\n\n<p>Link to the sample repository:\n<a href=\"https:\/\/bitbucket.org\/rsohlich\/clever_cloud_deploy\">https:\/\/bitbucket.org\/rsohlich\/clever_cloud_deploy<\/a><\/p>\n"},{"title":"Angular on Electron, part 2","link":"https:\/\/sohlich.github.io\/post\/angular_electron_2\/","pubDate":"Sun, 20 Aug 2017 20:33:51 +0200","guid":"https:\/\/sohlich.github.io\/post\/angular_electron_2\/","description":"\n\n<p>In the previous post the bootstrap of Angular project on Electron platform was described. In this one, the process of application packaging will be presented.<\/p>\n\n<p>One of the benefits of Electron is that it runs on all major platforms. Each platform has naturally its needs regarding to creating the distribution package. Fortunately, the packaging and all that stuff do not need to be done manually. There are few tools which will help you. But first things first.<\/p>\n\n<h2 id=\"get-ready\">Get ready<\/h2>\n\n<p>Before we begin this tutorial there will be one small change to an existing project from part 1. Because the folder &ldquo;dist&rdquo; will be used for another purpose, the Angular default build folder will be changed to &ldquo;build&rdquo;. This is done by modification of &ldquo;angular-cli.json&rdquo; config file. The property &ldquo;outDir&rdquo; of &ldquo;apps&rdquo; section will change the default output directory.<\/p>\n\n<p>${PROJECT_FOLDER}\/angular-cli.json:<\/p>\n\n<pre><code>    &quot;apps&quot;: [\n        {\n          ...\n          &quot;root&quot;: &quot;src&quot;,\n          &quot;outDir&quot;: &quot;build&quot;\n          ...}\n          ],\n      ...\n<\/code><\/pre>\n\n<p>After this change, test the configuration by building the project. The folder &ldquo;build&rdquo; should be created with all the content. If everything is OK, we are good to go.<\/p>\n\n<pre><code>    &gt; ng build\n    &gt; tree build\/\n    build\/\n        \u251c\u2500\u2500 favicon.ico\n        \u251c\u2500\u2500 index.html\n        \u251c\u2500\u2500 inline.bundle.js\n        \u251c\u2500\u2500 inline.bundle.js.map\n        \u251c\u2500\u2500 main.bundle.js\n        \u251c\u2500\u2500 main.bundle.js.map\n        \u251c\u2500\u2500 polyfills.bundle.js\n        \u251c\u2500\u2500 polyfills.bundle.js.map\n        \u251c\u2500\u2500 styles.bundle.js\n        \u251c\u2500\u2500 styles.bundle.js.map\n        \u251c\u2500\u2500 vendor.bundle.js\n        \u2514\u2500\u2500 vendor.bundle.js.map\n<\/code><\/pre>\n\n<h2 id=\"assets-packaging\">Assets packaging<\/h2>\n\n<p>All the assets of application need to be bundled in the distribution somehow. Naturally there are several ways how to accomplish that. The first option is to bundle the files ( js, css bundles) as they are. Your install folder that will contain the build folder with all the files.  Sometimes it is better to hide the raw files from user. So the next option is to use archive. As this si preferred way, the asar archive were designed.<\/p>\n\n<p><em>Asar archive<\/em><\/p>\n\n<p>The asar archive (<a href=\"https:\/\/github.com\/electron\/asar\">https:\/\/github.com\/electron\/asar<\/a>) is tar-like format very easy to use. Following example demonstrates the basic usage.<\/p>\n\n<pre><code>    &gt; npm install -g asar\n    &gt; asar pack app app.asar\n<\/code><\/pre>\n\n<p>The benefit of asar archive is that it could be read as simple as a folder in the filesystem. One way how to achieve it is via Node API. (<a href=\"https:\/\/electron.atom.io\/docs\/tutorial\/application-packaging\/#using-asar-archives\">https:\/\/electron.atom.io\/docs\/tutorial\/application-packaging\/#using-asar-archives<\/a>)<\/p>\n\n<pre><code>    const fs = require('fs')\n    fs.readdirSync('\/path\/to\/example.asar')\n<\/code><\/pre>\n\n<p>There is more. The Electron BrowserWindow class provides the ability to access the archive too. So it can load the &ldquo;index.html&rdquo; file in the application the common way via the BrowserWindow#loadURL method. In this case, the &ldquo;__dirname&rdquo; would be the path to the .asar file.<\/p>\n\n<pre><code>        var path = require('path');\n        var url = require('url');\n        win = new BrowserWindow({ width: 1280, height: 960 });\n        \/\/ __dirname is a current working directory\n        win.loadURL(url.format({\n                pathname: path.join(__dirname, 'build', 'index.html'),\n                protocol: 'file:',\n                slashes: true\n        }));\n<\/code><\/pre>\n\n<p>Now after the packaging and the ways how to use the asar were described, let&rsquo;s move to an installer. Don&rsquo;t worry you would not need to create the archives and config files manually. The tools for this purpose are there for you.<\/p>\n\n<h2 id=\"electron-builder\">Electron builder<\/h2>\n\n<p>For this tutorial, the <a href=\"https:\/\/github.com\/electron-userland\/electron-builder\">electron-builder<\/a> tool will be used.  The utility simplifies the creation of distribution package for all major platforms, even the cross platform build is possible.<\/p>\n\n<pre><code>    npm install electron-builder --save-dev\n<\/code><\/pre>\n\n<p>The electron-builder tool needs a little bit of configuration, so the final changes in &ldquo;package.json&rdquo; file looks like this (This is a minimal configuration)\n${PROJECT_FOLDER}\/package.json<\/p>\n\n<pre><code>      &quot;author&quot;: {\n        &quot;name&quot;: &quot;Radomir Sohlich&quot;,\n        &quot;email&quot;: &quot;sohlich@example.com&quot;\n      },\n      &quot;description&quot;: &quot;Example application.&quot;,\n      &quot;devDependencies&quot;: {\n         &quot;electron-builder&quot;: &quot;^19.22.0&quot;,\n      },\n      &quot;build&quot;: {\n        &quot;appId&quot;: &quot;com.example.app&quot;,\n        &quot;files&quot;: [\n          &quot;main.js&quot;,\n          &quot;build&quot;\n        ],\n        &quot;mac&quot;: {\n          &quot;category&quot;: &quot;productivity&quot;\n        }\n      }\n<\/code><\/pre>\n\n<p>The build-&gt;files section defines which files\/folders will be included in asar archive. The archive works as the application folder. The electron executes the main.js directly from the archive. The build folder contains application build with index.html and bundles. The &ldquo;author&rdquo; and &ldquo;description&rdquo; properties are not mandatory, but it is always better to provide this info. (The electron-builder will produce less warning messages :) )<\/p>\n\n<p>The final step is to add a npm command to run the electron-builder build.<\/p>\n\n<p>${PROJECT_FOLDER}\/package.json<\/p>\n\n<pre><code>    &quot;scripts&quot;: {\n        &quot;dist&quot;: &quot;build --mac&quot;\n      },\n<\/code><\/pre>\n\n<p>The &ldquo;dist&rdquo; command will build the application and subsequently build a distribution package. In this case, the MacOS is configured. The platform is defined by the switch. The available values are in the following figure. (stolen from project documentation <a href=\"https:\/\/github.com\/electron-userland\/electron-builder#cli-usage\">https:\/\/github.com\/electron-userland\/electron-builder#cli-usage<\/a>)<\/p>\n\n<pre><code>      --mac, -m, -o, --macos   Build for macOS, accepts target list (see\n                               https:\/\/goo.gl\/HAnnq8).                       [array]\n      --linux, -l              Build for Linux, accepts target list (see\n                               https:\/\/goo.gl\/O80IL2)                        [array]\n      --win, -w, --windows     Build for Windows, accepts target list (see\n                               https:\/\/goo.gl\/dL4i8i)                        [array]\n<\/code><\/pre>\n\n<p>To execute the build, call the command in terminal and the output should look like this.<\/p>\n\n<pre><code>    &gt; npm run dist\n    &gt; electron_app@0.0.0 distmac \/Users\/radek\/Junk\/electron_app\n    &gt; ng build &amp;&amp; build --mac\n    \n    Hash: ee6c31ccdab8735b740c\n    Time: 10199ms\n    chunk    {0} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 177 kB {4} [initial] [rendered]\n    chunk    {1} main.bundle.js, main.bundle.js.map (main) 5.27 kB {3} [initial] [rendered]\n    chunk    {2} styles.bundle.js, styles.bundle.js.map (styles) 10.5 kB {4} [initial] [rendered]\n    chunk    {3} vendor.bundle.js, vendor.bundle.js.map (vendor) 1.89 MB [initial] [rendered]\n    chunk    {4} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry] [rendered]\n    electron-builder 19.22.1\n    No native production dependencies\n    Packaging for darwin x64 using electron 1.7.5 to dist\/mac\n    Building macOS zip\n    Building DMG\n    Application icon is not set, default Electron icon will be used\n<\/code><\/pre>\n\n<p>After the successful command run, the dist folder should be created in the working directory and the installer should be there.<\/p>\n\n<pre><code>    dist\/\n    --- electron_app-0.0.0-mac.zip\n    --- electron_app-0.0.0.dmg\n    --- mac\n        --- electron_app.app\n<\/code><\/pre>\n\n<p>The &ldquo;electron_app.app\/Resources&rdquo; folder contains the asar archive with &ldquo;app.asar&rdquo; file. That is our bundled application. If you need to debug, what is packed into &ldquo;app.asar&rdquo; file and what is included in the installer. The &ldquo;build &ndash;dir&rdquo; command could be used. It will create only the expanded distribution folder (same as dist\/mac).<\/p>\n\n<p>Note:\nIf you encounter the error by executing the &ldquo;build &ndash;dir&rdquo; command.<\/p>\n\n<pre><code>    Error: Cannot find electron dependency to get electron version\n<\/code><\/pre>\n\n<p>The electron dependency need to be add to project.<\/p>\n\n<pre><code>    npm install electron --save-dev\n<\/code><\/pre>\n\n<p>The repository with example project <a href=\"https:\/\/github.com\/sohlich\/angular_on_electron\">https:\/\/github.com\/sohlich\/angular_on_electron<\/a><\/p>\n\n<h3 id=\"series\">Series:<\/h3>\n\n<ul>\n<li><a href=\"https:\/\/sohlich.github.io\/post\/angular_electron\/\">Angular on Electron, part 1<\/a><\/li>\n<li><a href=\"https:\/\/sohlich.github.io\/post\/angular_electron_2\/\">Angular on Electron, part 2<\/a><\/li>\n<\/ul>\n"},{"title":"Angular on Electron, part 1","link":"https:\/\/sohlich.github.io\/post\/angular_electron\/","pubDate":"Sat, 29 Jul 2017 08:48:41 +0200","guid":"https:\/\/sohlich.github.io\/post\/angular_electron\/","description":"\n\n<p>Today it is possible to have almost all the applications as a service online. Literally you don&rsquo;t have to install any of it on you computer. Even if this is possible, but for me it is still more comfortable to have a dedicated desktop application. I believe I&rsquo;m not the only one. There are a lot of ways how to create a desktop application. Utilizing the native frameworks like Qt, WxWidgets is always an option. For Java people, there are two useful options: swing and java fx.\nBut for me as web developer, though java based, it means to learn a new library or whole framework, all its features and pitfalls&hellip; But what If anybody tells you that you can use your good &ldquo;old&rdquo; javascript and HTML? Me, I\u2019m totally IN.<\/p>\n\n<p>So here comes the Electron platform (<a href=\"https:\/\/electron.atom.io\/\">https:\/\/electron.atom.io\/<\/a>) based on Chromium browser. It provides presentation layer and runtime for your application.\nThe Electron accompanied by Angular framework is a very solid foundation for desktop application development in most of use cases. By the way lot of well known applications are based on electron: VS Code, Slack, WhatsApp&hellip;<\/p>\n\n<p>I&rsquo;ll try to show you how to start your own project, or &ldquo;Electronify&rdquo; the existing one.<\/p>\n\n<h1 id=\"bootstrap-your-project\">Bootstrap your project<\/h1>\n\n<p>Using an Angular CLI generate a new application and test the first run. After following command you should be able to see the result in the browser on URL <a href=\"http:\/\/localhost:4200\">http:\/\/localhost:4200<\/a>.<\/p>\n\n<pre><code>&gt; ng new electron_app\n&gt; ng serve\n<\/code><\/pre>\n\n<p>Add main file for the electron called main.js<\/p>\n\n<p>${PROJECT_FOLDER}\/main.js:<\/p>\n\n<pre><code>    const { app, BrowserWindow } = require('electron');\n    \n    \/\/ Executes when the application \n    \/\/ is initialized.\n    app.on('ready', function() {\n        console.log('Starting application!');\n        \/\/ Create browser window \n        \/\/ with given parameters\n        mainWindow = new BrowserWindow({ width: 1280, height: 960 });\n        mainWindow.loadURL(&quot;http:\/\/localhost:4200&quot;);\n    \n        \/\/ It is useful to open dev tools\n        \/\/ for debug.\n        mainWindow.webContents.openDevTools();\n        mainWindow.on('closed', function() {\n            mainWindow = null;\n        });\n    });\n    \n    \/\/ Defines the behavior on close.\n    app.on('window-all-closed', function() {\n        app.quit();\n    });\n<\/code><\/pre>\n\n<p>And update the package.json file by few additional properties:\n${PROJECT_FOLDER}\/package.json:<\/p>\n\n<pre><code>    {\n        &quot;name&quot;: &quot;electron_app&quot;,\n        &quot;version&quot;: &quot;0.0.0&quot;,\n        &quot;main&quot;: &quot;main.js&quot;,\n        &quot;license&quot;: &quot;MIT&quot;,\n        &quot;scripts&quot;: {\n            &quot;ng&quot;: &quot;ng&quot;,\n            &quot;start&quot;: &quot;ng serve&quot;,\n            &quot;build&quot;: &quot;ng build&quot;,\n            &quot;test&quot;: &quot;ng test&quot;,\n            &quot;lint&quot;: &quot;ng lint&quot;,\n            &quot;e2e&quot;: &quot;ng e2e&quot;\n        },\n        &quot;private&quot;: true,\n        &quot;dependencies&quot;: {\n            &quot;@angular\/animations&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/common&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/compiler&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/core&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/forms&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/http&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/platform-browser&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/platform-browser-dynamic&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/router&quot;: &quot;^4.0.0&quot;,\n            &quot;core-js&quot;: &quot;^2.4.1&quot;,\n            &quot;rxjs&quot;: &quot;^5.4.1&quot;,\n            &quot;zone.js&quot;: &quot;^0.8.14&quot;\n        },\n        &quot;devDependencies&quot;: {\n            &quot;@angular\/cli&quot;: &quot;1.2.4&quot;,\n            &quot;@angular\/compiler-cli&quot;: &quot;^4.0.0&quot;,\n            &quot;@angular\/language-service&quot;: &quot;^4.0.0&quot;,\n            &quot;@types\/jasmine&quot;: &quot;~2.5.53&quot;,\n            &quot;@types\/jasminewd2&quot;: &quot;~2.0.2&quot;,\n            &quot;@types\/node&quot;: &quot;~6.0.60&quot;,\n            &quot;codelyzer&quot;: &quot;~3.0.1&quot;,\n            &quot;jasmine-core&quot;: &quot;~2.6.2&quot;,\n            &quot;jasmine-spec-reporter&quot;: &quot;~4.1.0&quot;,\n            &quot;karma&quot;: &quot;~1.7.0&quot;,\n            &quot;karma-chrome-launcher&quot;: &quot;~2.1.1&quot;,\n            &quot;karma-cli&quot;: &quot;~1.0.1&quot;,\n            &quot;karma-coverage-istanbul-reporter&quot;: &quot;^1.2.1&quot;,\n            &quot;karma-jasmine&quot;: &quot;~1.1.0&quot;,\n            &quot;karma-jasmine-html-reporter&quot;: &quot;^0.2.2&quot;,\n            &quot;protractor&quot;: &quot;~5.1.2&quot;,\n            &quot;ts-node&quot;: &quot;~3.0.4&quot;,\n            &quot;tslint&quot;: &quot;~5.3.2&quot;,\n            &quot;typescript&quot;: &quot;~2.3.3&quot;\n        }\n    }\n<\/code><\/pre>\n\n<p>I recommend to install the electron platform globaly with command:<\/p>\n\n<pre><code>    &gt; npm install -g electron\n<\/code><\/pre>\n\n<p>The first simple manual run could be done by calling following commands (these must be run in separate terminal windows as the \u201cng serve\u201d is blocking)<\/p>\n\n<pre><code>    &gt; ng serve\n    &gt; electron .\n<\/code><\/pre>\n\n<p>Command \u201cng serve\u201d will start development server on <a href=\"http:\/\/localhost:4200\">http:\/\/localhost:4200<\/a>, you can notice the this url is used in main.js file. The &ldquo;electron .&rdquo; will start the electron app by executing the main.js file.<\/p>\n\n<p>You can use <a href=\"https:\/\/www.npmjs.com\/package\/concurrently\">concurrently<\/a> tool to run these two commands concurrently. Also it can be incorporated to package.json file as an npm script.<\/p>\n\n<pre><code>npm install -g concurrently\n<\/code><\/pre>\n\n<p>${PROJECT_FOLDER}\/package.json<\/p>\n\n<pre><code>&quot;scripts&quot;: {\n        ...\n        &quot;electrondev&quot;: &quot;concurrently -k \\&quot;ng serve\\&quot; \\&quot;electron .\\&quot;&quot;\n    },\n<\/code><\/pre>\n\n<h1 id=\"serving-static-files\">Serving static files<\/h1>\n\n<p>Serving angular application via development server is not very comfortable and permanent solution. Better approach is serving a static files from the build output folder (let&rsquo;s call it distribution folder). The main.js file need to be changed to open the index.html file located in distribution folder of your angular application.<\/p>\n\n<p>${PROJECT_FOLDER}\/main.js<\/p>\n\n<pre><code>    const { app, BrowserWindow } = require('electron');\n    path = require('path');\n    url = require('url');\n    app.on('ready', function() {\n        console.log('Starting application!');\n        mainWindow = new BrowserWindow({ width: 1280, height: 960 });\n        \n        \/\/ Change loadUrl to load index.html\n        \/\/ using url and path package \n        \/\/ to format the file url\n        mainWindow.loadURL(url.format({\n            \/\/__dirname is the current working dir\n            pathname: path.join(__dirname, 'dist', 'index.html'),\n            protocol: 'file:',\n            slashes: true\n        }));\n    \n        \/\/ Opens dev tools\n        mainWindow.webContents.openDevTools();\n        mainWindow.on('closed', function() {\n            mainWindow = null;\n        });\n    });\n    app.on('window-all-closed', function() {\n        app.quit();\n    });\n<\/code><\/pre>\n\n<p>After you open electron you will receive \u201cFailed to load resource\u201d error.\nThere is one step missing to get the change work.\n<img src =\"https:\/\/d2mxuefqeaa7sj.cloudfront.net\/s_F68920300BC018EB3E1E88614B689BAD376E939D730AA4BF30888F46A4DF2F8A_1501387336733_image.png\"\/><\/p>\n\n<p>The one small change that need to be done is in your index.html file. We need to define the base for the file as absolute but from the actual working directory like \u201c.\/\u201d. This is done in <base> element in head tag of index.html . After the modification you can try \u201celectron .\u201d in your ${PROJECT_FOLDER}<\/p>\n\n<p>${PROJECT_FOLDER}\/index.html :<\/p>\n\n<pre><code>    &lt;!doctype html&gt;\n    &lt;html lang=&quot;en&quot;&gt;\n    &lt;head&gt;\n        &lt;meta charset=&quot;utf-8&quot;&gt;\n        &lt;title&gt;Electron&lt;\/title&gt;\n        &lt;!-- Change the href attribute \n        to reference to cur. working dir --&gt;\n        &lt;base href=&quot;.\/&quot;&gt;\n        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n        &lt;link rel=&quot;icon&quot; type=&quot;image\/x-icon&quot; href=&quot;favicon.ico&quot;&gt;\n    &lt;\/head&gt;\n    &lt;body&gt;\n        &lt;app-root&gt;&lt;\/app-root&gt;\n    &lt;\/body&gt;\n    &lt;\/html&gt;\n<\/code><\/pre>\n\n<p>That&rsquo;s it. Desktop application with Angular. The same approach could be used with other JS frameworks or just pure static HTML. I was excited how easy it is.<\/p>\n\n<p>The repository with example project <a href=\"https:\/\/github.com\/sohlich\/angular_on_electron\">https:\/\/github.com\/sohlich\/angular_on_electron<\/a><\/p>\n\n<h3 id=\"series\">Series:<\/h3>\n\n<ul>\n<li><a href=\"https:\/\/sohlich.github.io\/post\/angular_electron\/\">Angular on Electron, part 1<\/a><\/li>\n<li><a href=\"https:\/\/sohlich.github.io\/post\/angular_electron_2\/\">Angular on Electron, part 2<\/a><\/li>\n<\/ul>\n"},{"title":"Streaming JSON with Jackson","link":"https:\/\/sohlich.github.io\/post\/jackson\/","pubDate":"Wed, 08 Feb 2017 20:27:44 +0100","guid":"https:\/\/sohlich.github.io\/post\/jackson\/","description":"<p>Sometimes there is a situation, when it is more\nefficient to parse the JSON in stream way.\nEspecially if you are dealing with huge input\nor slow connection. In that case the JSON need to be read\nas it comes from input part by part.\nThe side effect of such approach is that you are able to\nread corrupted JSON arrays in some kind of comfortable way.<\/p>\n\n<p>Well known Jackson library (<a href=\"https:\/\/github.com\/FasterXML\/jackson-core\">https:\/\/github.com\/FasterXML\/jackson-core<\/a>)\nprovides so called stream API to handle it.\nThe parsing of stream is possible via\nJsonParser object, which uses token approach.<\/p>\n\n<pre><code>InputStream is = new FileInputStream(&quot;data.json&quot;);\nJsonFactory factory = new JsonFactory();\nJsonParser parser = factory.createJsonParser(is);\n<\/code><\/pre>\n\n<p>To simplify the approach, the combination of ObjectMapper\nwith sequetial reading of JSON data could be used.The code of the\ncomplete solution could be like:<\/p>\n\n<pre><code>public void tryParse(InputStream is) throws IOException {\n\t\tJsonFactory factory = new JsonFactory();\n\t\tJsonParser parser = factory.createJsonParser(is);\n\t\tObjectMapper mapper = new ObjectMapper()\n\t\t\t\t.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,false);\n\n\t\tJsonToken token = parser.nextToken();\n\t\t\n        \t\/\/ Try find at least one object or array.\n\t\twhile (!JsonToken.START_ARRAY.equals(token) &amp;&amp; token != null &amp;&amp; !JsonToken.START_OBJECT.equals(token)) {\n\t\t\tparser.nextToken();\n\t\t}\n\n\t\t\/\/ No content found\n\t\tif (token == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tboolean scanMore = false;\n\n\t\twhile (true) {\n\t\t\t\/\/ If the first token is the start of obejct -&gt;\n\t\t\t\/\/ the response contains only one object (no array)\n\t\t\t\/\/ do not try to get the first object from array.\n\t\t\ttry {\n\t\t\t\tif (!JsonToken.START_OBJECT.equals(token) || scanMore) {\n\t\t\t\t\ttoken = parser.nextToken();\n\t\t\t\t}\n\t\t\t\tif (!JsonToken.START_OBJECT.equals(token)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (token == null) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tObject node = mapper.readValue(parser, mappedClass);\n\t\t\t\t\n\t\t\t\t\/\/YOUR CODE TO HANDLE OBJECT\n\t\t\t\t\/\/...\n\n\n\t\t\t\tscanMore = true;\n\t\t\t} catch (JsonParseException e) {\n\t\t\t\thandleParseException(e);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n<\/code><\/pre>\n"},{"title":"Nats Proxy Framework","link":"https:\/\/sohlich.github.io\/post\/natsproxy\/","pubDate":"Sun, 28 Aug 2016 08:48:41 +0200","guid":"https:\/\/sohlich.github.io\/post\/natsproxy\/","description":"\n\n<p>The REST to NATS proxy project <a href=\"http:\/\/gopkg.in\/sohlich\/nats-proxy.v1\">sohlich\/nats-proxy<\/a> is the micro framework that provides a bridge between HTTP and NATS. To introduce the problem, we first compare the HTTP and NATS communication models. The table below represents the matching of HTTP and NATS concepts and what do they provide.<\/p>\n\n<table>\n<thead>\n<tr>\n<th>HTTP<\/th>\n<th>NATS<\/th>\n<th><\/th>\n<\/tr>\n<\/thead>\n\n<tbody>\n<tr>\n<td>Request\/Response<\/td>\n<td>Request\/Reply<\/td>\n<td>synchronous communication<\/td>\n<\/tr>\n\n<tr>\n<td>Websocket<\/td>\n<td>Publish\/Subscribe<\/td>\n<td>real-time asynchronous communication<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n\n<p>As you can see, the NATS provides both synchronous and asynchronous communication between clients. The synchronous communication, represented by simple Request and Response of HTTP protocol, could be matched with the Request\/Reply communication model of NATS. As the documentation for <a href=\"http:\/\/nats.io\/documentation\/concepts\/nats-req-rep\/\">&ldquo;request reply&rdquo; <\/a> model describes: each request sent via NATS contains reply subject, to which the reply is sent. The asynchronous, let&rsquo;s say real-time communication, can be represented by Websockets on HTTP side.The truth is that it is not really related to HTTP, but if we simplify it, at least the handshake is based on HTTP. For this purpose, the Publish\/Subscribe model could be used.<\/p>\n\n<p>So the REST to NATS project uses this similarity between NATS and HTTP communication and tries to implement the bridge between HTTP(Websockets) and NATS in such way. The library was originally created for the purpose of migrating REST based architecture like this<\/p>\n\n<p><img class=\"img-responsive center-block\" src=\"https:\/\/sohlich.github.io\/img\/blog\/natsproxy\/natsproxy_rest.png\"><\/p>\n\n<p>into NATS messaging platform based one. But as it evolved, it started to grow into some kind of framework, that can be used for the creation of service API and seamless protocol bridging. So one of the many examples of how the system using a nats-proxy framework could look like is on the architecture below.<\/p>\n\n<p><img class=\"img-responsive center-block\" src=\"https:\/\/sohlich.github.io\/img\/blog\/natsproxy\/natsproxy_arch.png\"><\/p>\n\n<h2 id=\"proxy-basics\">Proxy basics<\/h2>\n\n<p>As the name of the project suggests the function of the library is very similar to basic HTTP proxy. The proxy receives the HTTP request and translates it into a struct, which contains all the information from original request (URL, header, body).<\/p>\n\n<pre><code class=\"language-go\">type Request struct {\n\tURL        string\n\tMethod     string\n\tHeader     http.Header\n\tForm       url.Values\n\tRemoteAddr string\n\tBody       []byte\n}\n<\/code><\/pre>\n\n<p>This struct is serialized and sent as a message through NATS via request (see <a href=\"http:\/\/nats.io\/documentation\/concepts\/nats-req-rep\/\">http:\/\/nats.io\/documentation\/concepts\/nats-req-rep\/<\/a>) to ensure synchronous processing.\nThe subject, to which the serialized struct is sent, is constructed from the HTTP request URL and METHOD by a very simple rule: slashes in the path are replaced by dots and the method is used as the prefix.<\/p>\n\n<p><img class=\"img-responsive center-block\" src=\"https:\/\/sohlich.github.io\/img\/blog\/natsproxy\/natsproxy_request.png\"><\/p>\n\n<blockquote>\n<p>Lets say we have GET request on URL <code>http:\/\/example.com\/user\/info<\/code> so the proxy will translate this URL to  subject <code>GET:user.info<\/code>.<\/p>\n<\/blockquote>\n\n<p>The client side is subscribed to the subject <code>GET:user.info<\/code>. Because of that, it receives the request and writes back the response to the reply subject. The response struct also contains the body, status and header.<\/p>\n\n<pre><code class=\"language-go\">type Response struct {\n\tHeader     http.Header\n\tStatusCode int\n\tBody       []byte\n}\n<\/code><\/pre>\n\n<p>For better picture of how it works in reality. There is a code of simple client and proxy.<\/p>\n\n<h2 id=\"proxy\">Proxy<\/h2>\n\n<p>The proxy side implements the <code>http.Handler<\/code> interface, so it can be used with built-in <code>http<\/code> package as you can see in the code below. The handler does nothing special. It parses the request and translates it to custom representation which is then serialized to JSON by built in <code>json<\/code> package encoder.<\/p>\n\n<pre><code class=\"language-go\">import(\n        &quot;gopkg.in\/sohlich\/nats-proxy.v1&quot;\n        &quot;net\/http&quot;\n        &quot;github.com\/nats-io\/nats&quot;\n    )\n\nfunc main() {\n\tproxyConn, _ := nats.Connect(nats.DefaultURL)\n\tproxy, _ := natsproxy.NewNatsProxy(proxyConn)\n\tdefer proxyConn.Close()\n\thttp.ListenAndServe(&quot;:8080&quot;, proxy)\n}\n<\/code><\/pre>\n\n<p>The proxy itself does not implement any mechanisms to apply filters before the request is passed to the proxy handler as this could be implemented by decorating the proxy handler or other similar techniques.\nBecause the implementation does not allow writing data to the <code>http.ResponseWriter<\/code> after the handler is applied, the proxy provides <code>natsproxy.Hook<\/code> interface. This hook is applied on the response before it is written to <code>http.ResponseWriter<\/code>. The example bellow shows the usage of hook to translate JWT token with all user info to meaningless reference token.<\/p>\n\n<pre><code class=\"language-go\">proxyHandler.AddHook(&quot;.*&quot;, func(r *Response) {\n        \/\/ Exchange the jwt token for\n        \/\/ reference token to hide user information\n        jwt := r.GetHeader().Get(&quot;X-Auth&quot;)\n        refToken := auth.GetTokenFor(jwt)\n\t\tr.GetHeader().Set(&quot;X-Auth&quot;, refToken)\n\t})\n<\/code><\/pre>\n\n<h2 id=\"client\">Client<\/h2>\n\n<p>The client code uses the nats connection as the constructor argument, so all available options for configuring the connection are accessible. The client itself uses the asynchronous subscription to handle incoming messages, so it&rsquo;s behavior similar to <code>http.HandlerFunc<\/code>. The client API and internals are heavily inspired by <a href=\"https:\/\/gin-gonic.github.io\/gin\/\">Gin Gonic<\/a> project. The sample code shows how to use the client API.<\/p>\n\n<pre><code class=\"language-go\">\nimport(\n    &quot;gopkg.in\/sohlich\/nats-proxy.v1&quot;\n    &quot;net\/http&quot;\n    &quot;github.com\/nats-io\/nats&quot;\n)\n\nfunc main(){\n\tclientConn, _ := nats.Connect(nats.DefaultURL)\n\tnatsClient, _ := natsproxy.NewNatsClient(clientConn)\n\t\/\/Subscribe to URL \/user\/info\n\tnatsClient.GET(&quot;\/user\/info&quot;, func(c *natsproxy.Context) {\n\t   user := struct {\n\t\t    Name string\n\t    }{\n\t\t    &quot;Alan&quot;,\n\t    }\n\t\tc.JSON(200, user)\n\t})\n\tdefer clientConn.Close()\n\n\t\/\/ Waiting for signal to close the client\n\tsig := make(chan os.Signal, 1)\n\tsignal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)\n\tfmt.Println(&quot;Press Ctrl+C for exit.&quot;)\n\t&lt;-sig\n}\n<\/code><\/pre>\n\n<p>The client API naturally provides the subscription for other HTTP methods and generic subscription method. The request handler which implements <code>natsproxy.NatsHandler<\/code> interface uses <code>natsproxy.Context<\/code> struct which encapsulates both Request and Response and provides some useful methods to access request data and to write a response.<\/p>\n\n<pre><code class=\"language-go\">\/\/GET\nnatsClient.GET(&quot;\/user\/info&quot;, func(c *natsproxy.Context) {\n\t\tc.JSON(200, &quot;Hello&quot;)\n\t})\n\n\/\/POST\nnatsClient.POST(&quot;\/user\/info&quot;, func(c *natsproxy.Context) {\n\t\tc.JSON(200, &quot;Hello&quot;)\n\t})\n\n\/\/PUT\nnatsClient.PUT(&quot;\/user\/info&quot;, func(c *natsproxy.Context) {\n\t\tc.JSON(200, &quot;Hello&quot;)\n\t})\n\n\/\/DELETE\nnatsClient.DELETE(&quot;\/user\/info&quot;, func(c *natsproxy.Context) {\n\t\tc.JSON(200, &quot;Hello&quot;)\n\t})\n\n\/\/General method\nnatsClient.Subscribe(&quot;HEAD&quot;,&quot;\/user\/info&quot;, func(c *natsproxy.Context) {\n\t\tc.JSON(200, &quot;Hello&quot;)\n\t})\n\n<\/code><\/pre>\n\n<p>The client also implements middleware function that provides the means of accessing the request before it is handled by the specific handler. The reason behind this feature is to provide options for security checks, logging, etc. The example shows the implementation of middleware, that logs all incoming requests.<\/p>\n\n<pre><code class=\"language-go\">natsClient.Use(func logger(c *natsproxy.Context) {\n    log.Infof(&quot;%s:%s from %s&quot;, c.Request.Method, c.Request.URL)\n})\n<\/code><\/pre>\n\n<h2 id=\"summary\">Summary<\/h2>\n\n<p>The first version (v1) of the nats-proxy framework implements only HTTP Request\/Response proxying.\nBecause it started as some kind of proof of concept, the solution is not really optimized, all the work is done on the proxy side.\nAlso, the serialization of structs is done by JSON encoder, which does not provide very fast serialization.\nHowever for the purpose of bridging REST(HTTP) requests to NATS messaging platform, it&rsquo;s enough to make it possible.<\/p>\n\n<p>Currently, the next version (v2) is under development.\nThe v2 should bring some performance improvements because the serialization is done via protocol buffers. Also, a lot of work originally done on the proxy side was moved to client(service) side.The next significant feature is the WebSocket support.<\/p>\n\n<p>If you are interested or have some ideas, see <a href=\"https:\/\/github.com\/sohlich\/nats-proxy\">REST to NATS proxy<\/a> project.<\/p>\n"}]}}