<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Red Rad</title>
    <description>The latest articles on DEV Community by Red Rad (@theredrad).</description>
    <link>https://dev.to/theredrad</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F719716%2Faee02cf4-920b-49be-ad1f-4fcd3ec84e34.jpeg</url>
      <title>DEV Community: Red Rad</title>
      <link>https://dev.to/theredrad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/theredrad"/>
    <language>en</language>
    <item>
      <title>Kubernetes scaler for dedicated stateful servers</title>
      <dc:creator>Red Rad</dc:creator>
      <pubDate>Tue, 25 Jan 2022 16:32:43 +0000</pubDate>
      <link>https://dev.to/theredrad/kubernetes-scaler-for-dedicated-stateful-servers-26cf</link>
      <guid>https://dev.to/theredrad/kubernetes-scaler-for-dedicated-stateful-servers-26cf</guid>
      <description>&lt;p&gt;The Kubernetes autoscaling tries to add more pods in horizontal scaling and more resources (like memory or CPU) are added to the pod in vertical scaling. but while you are deploying a bunch of dedicated memory stateful servers (like game servers) you need to scale the node sizes instead of adding more pod or increasing pod resources.&lt;/p&gt;

&lt;p&gt;I developed an open-source configurable k8s scaler server for the stateful dedicated servers inspired by Mark Mandel's (founder of &lt;a href="https://agones.dev/"&gt;Agones.dev&lt;/a&gt;) &lt;a href="https://www.compoundtheory.com/scaling-dedicated-game-servers-with-kubernetes-part-1-containerising-and-deploying/"&gt;blog post&lt;/a&gt;. He had an awesome &lt;a href="https://www.gdcvault.com/play/1024328/"&gt;presentation on GDC&lt;/a&gt; about developing, deploying, and scaling dedicated game servers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kubescaler
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/theredrad/kubescaler"&gt;Kubescaler&lt;/a&gt; is a simple Kubernetes node scaler for dedicated servers. It runs the scale function in a loop and checks all nodes’ resources to determine when to scale up and down.&lt;/p&gt;

&lt;h3&gt;
  
  
  Slot
&lt;/h3&gt;

&lt;p&gt;The slot is a pod that runs the game server and is limited to certain resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaler
&lt;/h3&gt;

&lt;p&gt;The scaler considers a buffer of slots that must be available for new pods, so at the start, it compares the available slots (that is equal to node resource capacity divided to slot’s needed resources), if the available slot is smaller than the buffer size, it tries to scale up the node pool size and in other condition, it scales down the node pool size.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RNFKdZ6x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxxsmd2gc201robgh7sa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RNFKdZ6x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxxsmd2gc201robgh7sa.jpg" alt="Here, the buffer size is 4 slots" width="541" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheduling nodes
&lt;/h3&gt;

&lt;p&gt;The Kubernetes allows marking a node as unschedulable. It shows that is the controller can schedule a pod on the node or not. The scaler uses this option to help the extra node get empty faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling up
&lt;/h3&gt;

&lt;p&gt;Before starting to resize the node pool size, the scaler checks unschedulable nodes and starts to mark them as schedulable until the needed resource be supplied. if no unschedulable nodes are found or the needed resource didn’t supply, it resizes the node pool size to the needed size.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling down
&lt;/h3&gt;

&lt;p&gt;If the available slot is greater than the buffer size, the scaler starts to mark extra nodes as unschedulable, this option prevents the controller to schedule a new pod on the extra node. at the end, it checks the unschedulable nodes (extra nodes) for running pods, if no dedicated server pod is running and the node empty time passed the expiration, it deletes the node from node pool. Note that adding a new node to the node pool takes time, so an expiration time is considered for the empty node before deleting them, maybe a little while later the needed resource increased.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5WTLUKML--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/343ozjrxzdh7hg49jd0l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5WTLUKML--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/343ozjrxzdh7hg49jd0l.png" alt="scale function UML" width="661" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Selectors
&lt;/h3&gt;

&lt;p&gt;The scaler lists the scalable nodes using node-selector option and uses the pod label selector to determine that is the node is empty of dedicated server pods or not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Podwatcher
&lt;/h3&gt;

&lt;p&gt;The scaler server watches the dedicated server pod creation or deletion events and triggers the scale function in addition to the time interval.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Provider
&lt;/h3&gt;

&lt;p&gt;To resize the node pool size or delete a node we need to use the cloud API. The Digitalocean cloud provider is implemented in the Kubescaler. feel free to contribute and implement any other cloud provider and send the PR.&lt;br&gt;
To use the Digitalocean API, you must set the cloud-provider-token and the cluster and node pool names.&lt;/p&gt;




&lt;p&gt;The docker image exists &lt;a href="https://github.com/theredrad/kubescaler/pkgs/container/kubescaler"&gt;here&lt;/a&gt;, also feel free to contribute to the repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/theredrad/kubescaler"&gt;https://github.com/theredrad/kubescaler&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>kubernetes</category>
      <category>scaling</category>
    </item>
    <item>
      <title>Pass secrets to Docker build to fetch private Github repositories</title>
      <dc:creator>Red Rad</dc:creator>
      <pubDate>Tue, 28 Dec 2021 18:20:17 +0000</pubDate>
      <link>https://dev.to/theredrad/pass-secrets-to-docker-build-to-fetch-private-github-repositories-291i</link>
      <guid>https://dev.to/theredrad/pass-secrets-to-docker-build-to-fetch-private-github-repositories-291i</guid>
      <description>&lt;p&gt;To fetch private repositories as dependencies in a Docker image build procedure, you must set the Github credentials.&lt;/p&gt;

&lt;p&gt;The popular errors while an invalid credential is set:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;fatal: could not read Username for ‘&lt;a href="https://github.com':"&gt;https://github.com':&lt;/a&gt; No such device or address&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Git URL config
&lt;/h2&gt;

&lt;p&gt;There are lots of posts on the internet to do this by setting your Github personal token in the git URL config, all of them are insecure because actually, they’re suggesting to pass your Github personal token to the Dockerfile as an argument and set it as the username of the Github repositories. remind that every command in Dockerfile, is printed on the build log and is accessible from the build history, so your private token is printed on the logs and ….&lt;/p&gt;

&lt;h2&gt;
  
  
  The SSH key method
&lt;/h2&gt;

&lt;p&gt;You can also use an SSH key to download private repositories in the Docker build procedure. for this you need to generate a new SSH key and assign it to your Github account, then store the private key into the repository secrets and write it into a file in the Github action job step, then copy the file from the context directory to the .ssh directory of build container. By using this method, you are not in control of the SSH key scopes, the SSH key is your identity and has access to your whole account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using .netrc file
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html"&gt;The .netrc file contains login and initialization information used by the auto-login process.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To use .netrc file, you must generate &lt;a href="https://github.com/settings/tokens/new"&gt;a new personal access token&lt;/a&gt; with private repositories related scopes, for example, if your private repositories exist under your account, therepo scope is enough, but if they exist under your organization or team account, theadmin:org scope is required.&lt;/p&gt;

&lt;p&gt;Then store the generated personal access token in the repository secrets. Here I saved it with &lt;code&gt;API_TOKEN_GITHUB&lt;/code&gt; name.&lt;/p&gt;

&lt;p&gt;Create a Github action file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Docker Image CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;master&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Store netrc file&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo 'machine github.com login ${{ secrets.API_TOKEN_GITHUB }} password x-oauth-basic' &amp;gt; .netrc&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build the Docker image&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DOCKER_BUILDKIT=1 docker build --file Dockerfile --tag test-image:$(date +%s) --secret id=github,src=.netrc .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this action, first, we store our secrets into the .netrc file, then pass the file as secret to the Docker build command.&lt;br&gt;
Github action job hides the secrets in the logs, so it’s safe to use secrets in the run command.&lt;br&gt;
After that, you must mount the secret file to root/.netrc in Dockerfile, (in this example we’re running Golang module download command after mounting the secret)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret,id&lt;span class="o"&gt;=&lt;/span&gt;github,dst&lt;span class="o"&gt;=&lt;/span&gt;/root/.netrc &lt;span class="se"&gt;\
&lt;/span&gt;    go &lt;span class="nb"&gt;env&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="nv"&gt;GOPRIVATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github.com/YOUR_USERNAME/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;env &lt;/span&gt;&lt;span class="nv"&gt;GIT_TERMINAL_PROMPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 go mod download
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Notice&lt;/strong&gt;: You must run the go mod download or npm install commands right after mounting the secret file, actually in the same Docker Run command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using docker/build-push-action@v2
&lt;/h2&gt;

&lt;p&gt;If you are using a Github action to build or push your image, you should pass the .netrc file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# bluh bluh bluh &lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Store netrc file&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo 'machine github.com login ${{ secrets.API_TOKEN_GITHUB }} password x-oauth-basic' &amp;gt; .netrc&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Push to GitHub Packages&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/build-push-action@v2&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;secret-files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;"github=./.netrc"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Don’t pass your secret to Docker build command as an argument, your secrets are printed in the build logs and history.&lt;/li&gt;
&lt;li&gt;Using SSH key limits your control of the scopes.&lt;/li&gt;
&lt;li&gt;You can store secrets in the .netrc file via the Github action and then pass it as a secret file to the Docker build command. (follow .netrc section)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>github</category>
    </item>
    <item>
      <title>How to use Lorem.space for generating random image placeholders with your local images</title>
      <dc:creator>Red Rad</dc:creator>
      <pubDate>Mon, 15 Nov 2021 18:02:39 +0000</pubDate>
      <link>https://dev.to/theredrad/how-to-use-loremspace-for-generating-random-image-placeholders-with-your-local-images-4cjl</link>
      <guid>https://dev.to/theredrad/how-to-use-loremspace-for-generating-random-image-placeholders-with-your-local-images-4cjl</guid>
      <description>&lt;p&gt;Lorem.space is an online API to generate categorized random image placeholders with custom sizes for your design layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the hell is that?
&lt;/h2&gt;

&lt;p&gt;Consider that you want to design a movie website or app, instead of downloading a bunch of movie covers, resizing them, and using them statically, you only set an URL (like &lt;a href="https://api.lorem.space/image/movie?w=150&amp;amp;h=220"&gt;https://api.lorem.space/image/movie?w=150&amp;amp;h=220&lt;/a&gt;) and each time a random movie cover will return.&lt;/p&gt;

&lt;p&gt;To use API you can simply send a request to &lt;code&gt;https://api.lorem.space/image/movie?w=150&amp;amp;h=220&lt;/code&gt;. This will return a random movie cover image in 150x220px dimensions. Some other categories like the game cover, music cover, store items, … are available and you can check &lt;a href="https://lorem.space"&gt;https://lorem.space&lt;/a&gt; for more information.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to run Lorem.space on your local machine
&lt;/h2&gt;

&lt;p&gt;Lorem.space is an open-sourced program, you can download and run both frontend and backend apps on your local machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the server from binaries
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Download the latest binary for your operating system: &lt;a href="https://github.com/manasky/lorem-server/releases"&gt;https://github.com/manasky/lorem-server/releases&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Extract the downloaded file&lt;/li&gt;
&lt;li&gt;Open Terminal (for macOS or Linux) and CMD (for windows) and navigate to the extracted folder.&lt;/li&gt;
&lt;li&gt;Make sure the file is executable (grant permissions if needed)&lt;/li&gt;
&lt;li&gt;Run the server with these commands:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# For macOS or Linux:
./lorem-server -host "127.0.0.1:8080" - dir "~/Pictures"
# This will run the server on port 8080 and serves images from ~/Pictures directory

# For Windows:
lorem-server.exe -host "127.0.0.1:8080" -dir "C:\Users\USER\Pictures"
# This will run the server on port 8080 and serves images from `C:\Users\USER\Pictures` directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run the server from source code
&lt;/h3&gt;

&lt;p&gt;Lorem.space server is written in Golang and you can access the source code from here: &lt;a href="https://github.com/manasky/lorem-server"&gt;https://github.com/manasky/lorem-server&lt;/a&gt;&lt;br&gt;
To run the server from codes, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Go: &lt;a href="https://golang.org/dl/"&gt;https://golang.org/dl/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Clone the repository: &lt;code&gt;git clone https://github.com/manasky/lorem-server.git&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go to the directory of source code, create a new directory named &lt;code&gt;images&lt;/code&gt; and put your images (.JPEG format) here. Each directory in &lt;code&gt;images&lt;/code&gt; is considered as a category. for example, you can create a directory named &lt;code&gt;car&lt;/code&gt; and put all cars’ images there.&lt;/li&gt;
&lt;li&gt;Open Terminal (for macOS and Linux) or CMD (for Windows), then &lt;code&gt;cd&lt;/code&gt; to the directory of source codes and run: &lt;code&gt;go run main.go&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Now the server is running on &lt;code&gt;127.0.0.1:8080&lt;/code&gt;. Open &lt;code&gt;http://127.0.0.1:8080/image&lt;/code&gt; in your browser and a random image from the &lt;code&gt;images&lt;/code&gt; directory is returned.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Options
&lt;/h3&gt;

&lt;p&gt;Some arguments are available to run the server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;host&lt;/code&gt;: The IP and port of the server host&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dir&lt;/code&gt;: The address of the images directory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cache&lt;/code&gt;: Enables file caching to prevent resizing the image in the same request&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cdn&lt;/code&gt;: CDN domain&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;min-width&lt;/code&gt;: minimum supported width size in px&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max-width&lt;/code&gt;: maximum supported width size in px&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;min-height&lt;/code&gt;: minimum supported height size in px&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max-height&lt;/code&gt;: maximum supported height size in px&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Run the server with Docker
&lt;/h3&gt;

&lt;p&gt;A built docker image of the Lorem server is available. You can pull the image by this command:&lt;br&gt;
&lt;code&gt;docker pull ghcr.io/manasky/lorem-server:latest&lt;/code&gt;&lt;br&gt;
To run the docker image, you need to create a &lt;code&gt;.env&lt;/code&gt; file containing the server configs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HOST=0.0.0.0:8080
DIR=/app/images
MIN_WIDTH=20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in the directory of &lt;code&gt;.env&lt;/code&gt; run this command in terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run - env-file=./.env -p 8080:8090 -v ~/Pictures:/app/images ghcr.io/manasky/lorem-server:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;— env-file&lt;/code&gt; sets the application environment variables path. Here &lt;code&gt;.env&lt;/code&gt; file exists in the current path.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p 8080:8080&lt;/code&gt; sets up a port forward. the application container will listen to the &lt;code&gt;8080&lt;/code&gt; port (set in the .env file as HOST). This flag maps the container’s port &lt;code&gt;8080&lt;/code&gt; to port &lt;code&gt;8080&lt;/code&gt; on the host (here, your localhost).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/Pictures:/app/images&lt;/code&gt; sets up a bind-mount volume that links the directory &lt;code&gt;/app/images&lt;/code&gt; from inside the app container to the directory &lt;code&gt;~/Pictures&lt;/code&gt; on the host machine (here, your system). The app image directory is set in the &lt;code&gt;.env&lt;/code&gt; file as &lt;code&gt;/app/images&lt;/code&gt;, so here the &lt;code&gt;~/Pictures&lt;/code&gt; is mounted to that.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After container running, the app will scan &lt;code&gt;/app/images&lt;/code&gt; which is mounted to the directory &lt;code&gt;~/Pictures&lt;/code&gt; of your system &amp;amp; serves the HTTP server on 127.0.0.1:8080. Visit &lt;code&gt;127.0.0.1:8080/image&lt;/code&gt; for start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contribute
&lt;/h2&gt;

&lt;p&gt;Feels free to contribute to the repository or file an issue for feedback or bug reporting in Github.&lt;/p&gt;

</description>
      <category>design</category>
      <category>webdev</category>
      <category>go</category>
    </item>
    <item>
      <title>UDP Socket manager for go server-side</title>
      <dc:creator>Red Rad</dc:creator>
      <pubDate>Tue, 05 Oct 2021 13:04:55 +0000</pubDate>
      <link>https://dev.to/theredrad/udp-socket-manager-for-go-server-side-3boj</link>
      <guid>https://dev.to/theredrad/udp-socket-manager-for-go-server-side-3boj</guid>
      <description>&lt;p&gt;I'm working on a prototype online multiplayer game. As you know an online multiplayer game has a server-side process that manages the game state &amp;amp; simulates the world based on the users' inputs.&lt;/p&gt;

&lt;p&gt;The game is fast-paced, so I used the UDP protocol to create a virtual channel between the client &amp;amp; the server. The UDP is a stateless protocol, which means that the server &amp;amp; client are not aware of a connection, they only exchange packets. Also, there is no guarantee that the packets are received in order or receive at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Security
&lt;/h2&gt;

&lt;p&gt;To manage the network connections there is a major challenge, security! this challenge has two sides, the first is related to user authentication &amp;amp; session management &amp;amp; the second is secure the content of the packets around the internet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Session management
&lt;/h3&gt;

&lt;p&gt;Each user input that is received in the server, must be authorized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Encryption
&lt;/h3&gt;

&lt;p&gt;To secure the content of packets around the internet we need to use encryption.&lt;/p&gt;

&lt;p&gt;So I decided to implement a simple general-purpose package for Golang to manage the incoming packets &amp;amp; provide security for the virtual connection between the server &amp;amp; the client.&lt;/p&gt;




&lt;h2&gt;
  
  
  The &lt;code&gt;udpsocket&lt;/code&gt; package
&lt;/h2&gt;

&lt;p&gt;I made this package to make a virtual stateful connection between the client &amp;amp; server using the UDP protocol for a Golang game server (as you know the UDP protocol is stateless, packets may not arrive in order &amp;amp; there is no ACK). check it out on &lt;a href="https://github.com/theredrad/udpsocket"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;udpsocket&lt;/code&gt; supports a mimic of DTLS handshake, cryptography, session management &amp;amp; authentication. It's responsible to make a secure channel between the client &amp;amp; server on UDP (handshake), authenticate &amp;amp; manage them, decrypt &amp;amp; encrypt the data &amp;amp; provide an API to send or broadcast data to the clients &amp;amp; listen to them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Implementations
&lt;/h3&gt;

&lt;p&gt;Feels free to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;implement your auth client to authorize the users' tokens&lt;/li&gt;
&lt;li&gt;implement your preferred symmetric &amp;amp; asymmetric encryption algorithms (the RSA &amp;amp; AES encryption are supported as default)&lt;/li&gt;
&lt;li&gt;implement your preferred encoding package. (the protobuf is supported as default)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Basic Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"crypto/rsa"&lt;/span&gt;

    &lt;span class="s"&gt;"demo/auth"&lt;/span&gt;
    &lt;span class="s"&gt;"demo/encoding"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/theredrad/udpsocket"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/theredrad/udpsocket/crypto"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;pk&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rsa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PrivateKey&lt;/span&gt;

    &lt;span class="n"&gt;udpServerIP&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"127.0.0.1"&lt;/span&gt;
    &lt;span class="n"&gt;udpServerPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"7009"&lt;/span&gt;

    &lt;span class="n"&gt;defaultRSAPrivateKeySize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2048&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewFirebaseClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"firebase-config.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// firebase implementation of auth client to validate firebase-issued tokens&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;udpAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResolveUDPAddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"udp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s:%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;udpServerIP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;udpServerPort&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;udpConn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenUDP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"udp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;udpAddr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;udpConn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


    &lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GenerateRSAKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;defaultRSAPrivateKeySize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRSAFromPK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// creating a new instance of the RSA implementation&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewAES&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AES_CBC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// creating a new instance of the AES implementation&lt;/span&gt;

    &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessagePack&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c"&gt;// an implementation of msgpack for the Transcoder&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;udpsocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;udpConn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;udpsocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;AuthClient&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Transcoder&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SymmCrypto&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;AsymmCrypto&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ReadBufferSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;MinimumPayloadSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ProtocolVersionMajor&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ProtocolVersionMinor&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;incomingHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// handling the server errors&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;uerr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;uerr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"errors on udp server: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uerr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// start to run the server, listen to incoming records&lt;/span&gt;

  &lt;span class="c"&gt;// TODO: need to serve the public key on HTTPS (TLS) to secure the download for the client&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;incomingHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// handle the incoming&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dig deeper, How it works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Record
&lt;/h3&gt;

&lt;p&gt;Each message from the client is a Record. The record has a format to parse &amp;amp; decryption.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; 1   0   1   1 0 2 52 91 253 115 22 78 39 28 5 192 47 211...
|-| |-| |-|  |------------------------------------------|
 a   b   c                        d

a: record type
b: record protocol major version
c: record protocol minor version
d: record body
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Record Types
&lt;/h3&gt;

&lt;p&gt;The first byte of record is the type &amp;amp; indicates how to parse the record. supported reserved types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ClientHello : &lt;code&gt;1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;HelloVerify: &lt;code&gt;2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ServerHello: &lt;code&gt;3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ping: &lt;code&gt;4&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Pong: &lt;code&gt;5&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Handshake
&lt;/h3&gt;

&lt;p&gt;The handshake process is made base on a mimic of DTLS protocol, the client sends &lt;code&gt;ClientHello&lt;/code&gt; record, this record contains a random bytes &amp;amp; AES key &amp;amp; encrypted by the server public key, which is needed to download on TLS, then the server generates a random cookie based on the client parameters, encrypts it with the client AES key (which is received by &lt;code&gt;ClientHello&lt;/code&gt; &amp;amp; sends it as the &lt;code&gt;HelloVerify&lt;/code&gt; record. The client decrypts the record &amp;amp; repeats the &lt;code&gt;ClientHello&lt;/code&gt; message with the cookie, the record is needed to be encrypted with the server public key, then append the encrypted user token (with AES) to the record body. the server will registers the client after cookie verification &amp;amp; authenticates the user token &amp;amp; then returns a &lt;code&gt;ServerHello&lt;/code&gt; record contains a random secret session ID. The handshake process is done here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      Client                                   Server
      ------                                   ------
      ClientHello           ------&amp;gt;

                            &amp;lt;-----         HelloVerifyRequest
                                           (contains cookie)

      ClientHello           ------&amp;gt;
 (with cookie &amp;amp; token)

                            &amp;lt;-----           ServerHello
                                         (contains session ID)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Encryption
&lt;/h3&gt;

&lt;p&gt;The Server uses both symmetric &amp;amp; asymmetric encryptions to communicate with the client.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ClientHello&lt;/code&gt; record (for the server) contains a secure 256 bit AES key &amp;amp; encrypted by the server public key, so the server could decrypt it with the private key.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;HelloVerify&lt;/code&gt; record (for the client) encrypts with the client &lt;code&gt;AES&lt;/code&gt; key (which was decrypted before).&lt;br&gt;
If user authentication is required, the client must send the user token with the &lt;code&gt;ClientHello&lt;/code&gt; (a record which contains cookie too), but the asymmetric encryption has a limitation on size. for example, the &lt;code&gt;RSA&lt;/code&gt; only is able to encrypt data to a maximum amount equal to the key size (e.g. 2048 bits = 256 bytes) &amp;amp; the user token size could be more, so the user token must be encrypted by the client &lt;code&gt;AES&lt;/code&gt;, then the server could decrypt it after validation of &lt;code&gt;ClientHello&lt;/code&gt; record.&lt;br&gt;
The handshake record structure is a little different because of using hybrid encryption. the two bytes after the protocol version bytes indicates the size of the handshake body which is encrypted by the server public key. the handshake body size is passing because of the key size, the encrypted body size depends on the &lt;code&gt;RSA&lt;/code&gt; key size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; 1   0   1   1   0   2 52 91 253 115 22 78 ... 4 22 64 91 195 37 225
|-| |-| |-| |-| |-| |---------------------|   |--------------------|
 a   b   c   d   e            f                         g

a: record type (1 =&amp;gt; handshake)
b: record protocol major version (0 =&amp;gt; 0.1v)
c: record protocol minor version (1 =&amp;gt; 0.1v)
d: handshake body size ([1] 0 =&amp;gt; 256 bytes, key size: 2048 bits) (first digit number in base of 256)
e: handshake body size (1 [0] =&amp;gt; 256 bytes, key size: 2048 bits) (second digit number in base of 256)
f: handshake body which is encrypted by the server public key &amp;amp; contains the client AES key
g: user token which is encrypted by the client AES key size
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Possible issues
&lt;/h2&gt;

&lt;p&gt;If there were any possible issues or needs, please put comments or collaborate to make it better. &lt;a href="https://github.com/theredrad/udpsocket"&gt;Repository on the Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>gamedev</category>
      <category>encryption</category>
      <category>udp</category>
    </item>
  </channel>
</rss>
