<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Mozes721</title>
        <link>https://paragraph.com/@mozes721</link>
        <description>I am a Full Stack developer.
Here are my relevant links into one: https://linktr.ee/richard_taujenis</description>
        <lastBuildDate>Wed, 15 Apr 2026 18:55:03 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Mozes721</title>
            <url>https://storage.googleapis.com/papyrus_images/6986ff21afbcb5fa6330358171cb59a7dedd8ca4d1b15415cab39f575896d16a.jpg</url>
            <link>https://paragraph.com/@mozes721</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Local Llama Setup: A Python Developer's Guide]]></title>
            <link>https://paragraph.com/@mozes721/local-llama-setup-a-python-developer-s-guide</link>
            <guid>ciVIv62TKyTnJtspeUQU</guid>
            <pubDate>Thu, 23 Jan 2025 00:53:21 GMT</pubDate>
            <description><![CDATA[As using chatGPTis API is becoming more and more expensive and number of tokens are limited there comes a point in your life that have to look for alternatives. Thats where Llama comes in!Alternatively you can use smaller models (3B parameters instead of 7B)Use bitsandbytes for 8-bit quantization, which reduces memory usage significantly.If you don’t have strong GPU can always outsource to cloud options that are out there like Google Colab, Hugging Face Inference API, RunPodAccessing Llama Mo...]]></description>
            <content:encoded><![CDATA[<p>As using chatGPTis API is becoming more and more expensive and number of tokens are limited there comes a point in your life that have to look for alternatives. Thats where Llama comes in!</p><blockquote><p>Alternatively you can use smaller models (3B parameters instead of 7B)</p></blockquote><blockquote><p>Use <strong>bitsandbytes</strong> for 8-bit quantization, which reduces memory usage significantly.</p></blockquote><blockquote><p>If you don’t have strong GPU can always outsource to cloud options that are out there like Google Colab, Hugging Face Inference API, RunPod</p></blockquote><h4 id="h-accessing-llama-models" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Accessing Llama Models</h4><p>To start off Hugging Face is the primary platform used for accessing Llama models(e.g., <code>meta-llama/Llama-2-7b-chat-hf</code>).</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://huggingface.co">https://huggingface.co</a></p><p>Create your account in <strong>Hugging Face</strong>👆 to start using LLM models provided by Llama.</p><p>If your ambitious can as well create own model if not there are a bunch of models to choose from. 🤖</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/131f6fbf2ae6863e72c61eb0ef98133a8ed3728d8ca0268a5dd9256033c4c5e7.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Most people including me just need text-to-text model so typical choose would be <em>meta-llama/Llama-2–7b-chat-hf.</em></p><p>Once the model has been selected be sure to request access to the model by adding credentials.</p><pre data-type="codeBlock" text="huggingface-cli login
"><code>huggingface<span class="hljs-operator">-</span>cli login
</code></pre><p>Then you will have to login in terminal to use the models. In your huggingface profile go to Settings &gt; Access Tokens, generate your access token that you will paste in.</p><h4 id="h-using-the-model" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Using the Model</h4><p>In your python app we should use <strong>conda</strong> instead of regular <strong>venv</strong> be sure to install it activating it is similar as venv.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.anaconda.com/working-with-conda/environments/">https://docs.anaconda.com/working-with-conda/environments/</a></p><pre data-type="codeBlock" text="//Required instalation for conda PyTorch
conda install pytorch torchvision torchaudio cpuonly -c pytorch
//Required python packages for huggingface etc
pip install transformers accelerate sentencepiece huggingface_hub
//To reduce memory usage you can as well install
pip install bitsandbytes
//Activate conda
conda activate myenv
"><code><span class="hljs-comment">//Required instalation for conda PyTorch</span>
conda install pytorch torchvision torchaudio cpuonly <span class="hljs-operator">-</span>c pytorch
<span class="hljs-comment">//Required python packages for huggingface etc</span>
pip install transformers accelerate sentencepiece huggingface_hub
<span class="hljs-comment">//To reduce memory usage you can as well install</span>
pip install bitsandbytes
<span class="hljs-comment">//Activate conda</span>
conda activate myenv
</code></pre><p>For this demonstration will just make it a simple as possible in main.py the power lies when implementing <strong>RAG</strong> (Retrieval-Augmented Generation)) or fine tuning the model.</p><pre data-type="codeBlock" text="import transformers
import torch

def main():
    # Load Llama model using transformers pipeline
    pipeline = transformers.pipeline(
        &quot;text-generation&quot;,
        model=&quot;meta-llama/Llama-2-7b-chat-hf&quot;,  # Replace with your model path if using a local model
        model_kwargs={&quot;torch_dtype&quot;: torch.bfloat16},
        device_map=&quot;auto&quot;
    )

    # Start the Llama pipeline
    while True:
        # Get user input
        query = input(&quot;\nYou: &quot;)
        
        # Exit condition
        if query.lower() in [&quot;exit&quot;, &quot;quit&quot;]:
            print(&quot;Goodbye!&quot;)
            break
        
        # Handle the query
        try:
            # Construct the prompt
            messages = [
                {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: query},
            ]
            
            # Generate a response using the Llama model
            outputs = pipeline(
                messages,
                max_new_tokens=256,  # Adjust as needed
            )
            
            # Extract and print the response
            response = outputs[0][&quot;generated_text&quot;][-1][&quot;content&quot;]
            print(f&quot;Bot: {response}&quot;)
        except Exception as e:
            print(f&quot;Error handling query: {e}&quot;)

if __name__ == &quot;__main__&quot;:
    main()
"><code>import transformers
import torch

def main():
    <span class="hljs-comment"># Load Llama model using transformers pipeline</span>
    <span class="hljs-attr">pipeline</span> = transformers.pipeline(
        "text-generation",
        <span class="hljs-attr">model</span>=<span class="hljs-string">"meta-llama/Llama-2-7b-chat-hf"</span>,  <span class="hljs-comment"># Replace with your model path if using a local model</span>
        <span class="hljs-attr">model_kwargs</span>={<span class="hljs-string">"torch_dtype"</span>: torch.bfloat16},
        <span class="hljs-attr">device_map</span>=<span class="hljs-string">"auto"</span>
    )

    <span class="hljs-comment"># Start the Llama pipeline</span>
    while True:
        <span class="hljs-comment"># Get user input</span>
        <span class="hljs-attr">query</span> = input(<span class="hljs-string">"\nYou: "</span>)
        
        <span class="hljs-comment"># Exit condition</span>
        if query.lower() in <span class="hljs-section">["exit", "quit"]</span>:
            print("Goodbye!")
            break
        
        <span class="hljs-comment"># Handle the query</span>
        try:
            <span class="hljs-comment"># Construct the prompt</span>
            <span class="hljs-attr">messages</span> = [
                {<span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>, <span class="hljs-string">"content"</span>: query},
            ]
            
            <span class="hljs-comment"># Generate a response using the Llama model</span>
            <span class="hljs-attr">outputs</span> = pipeline(
                messages,
                <span class="hljs-attr">max_new_tokens</span>=<span class="hljs-number">256</span>,  <span class="hljs-comment"># Adjust as needed</span>
            )
            
            <span class="hljs-comment"># Extract and print the response</span>
            <span class="hljs-attr">response</span> = outputs[<span class="hljs-number">0</span>][<span class="hljs-string">"generated_text"</span>][-<span class="hljs-number">1</span>][<span class="hljs-string">"content"</span>]
            print(f"Bot: {response}")
        except Exception as e:
            print(f"Error handling query: {e}")

if <span class="hljs-attr">__name__</span> == <span class="hljs-string">"__main__"</span>:
    main()
</code></pre><blockquote><p><em>Note: The model i used computation heavy(CPU, GPU) and due to enormous parameters this particular 7 Billion parameters so if it doesn&apos;t break and hangs it may be due to weak PC.</em></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/484f7697fea014a0547d507c8c9861e7fecd92ebea8576016f9e241dadcfbc0d.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-conclusion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Conclusion</h3><p>As AI doesn’t seem to fade and hype keeps on going good good to be more familiarized with it if not building own model might as well implement in own project with fine tuning or implementing it with RAG.</p><p>Of course IF your PC can handle it. 😉</p>]]></content:encoded>
            <author>mozes721@newsletter.paragraph.com (Mozes721)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/badbf630fb7e7ab2924cc3456583f362965dd3f1c918668ba301192e7dec65e3.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Can Pinterest Help Build Your Personal Brand?]]></title>
            <link>https://paragraph.com/@mozes721/can-pinterest-help-build-your-personal-brand</link>
            <guid>bwXx2lf0TxboRPzfy79B</guid>
            <pubDate>Tue, 10 Dec 2024 21:38:23 GMT</pubDate>
            <description><![CDATA[In todays age personal branding is more important then ever, while most of us focus on YouTube, blogging, personal website, GitHub(as a developer), Link bio(like linktree).Pinterest works similarly to affiliate links, directing users to external content where the shared content actually resides.While it’s true that Pinterest is better suited for creative, visually-driven fields like art, tattoos, and fashion, it can also be a valuable tool for IT professionals. Although results may not be ins...]]></description>
            <content:encoded><![CDATA[<figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/82906fff82b865e11e9ce72c4790d4f4cd576190af95b926832423c28bf01537.jpg" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><hr><p>In todays age personal branding is more important then ever, while most of us focus on YouTube, blogging, personal website, GitHub(as a developer), Link bio(like linktree).</p><blockquote><p>Pinterest works similarly to affiliate links, directing users to external content where the shared content actually resides.</p></blockquote><p>While it’s true that Pinterest is better suited for creative, visually-driven fields like art, tattoos, and fashion, it can also be a valuable tool for IT professionals. Although results may not be instantaneous, men and women alike can leverage Pinterest for personal branding.</p><h3 id="h-setting-up-pinterest" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Setting up Pinterest</h3><p>Ones you login with email, google or facebook you can start by creating different boards based on content that you want to share.</p><p>Above you can see my different boards i have created over time(the last one i have been invited to).</p><p>Some social platforms like <strong>YouTube</strong> will automatically suggest option to create a Pin on Pinterest. If not I suggest create manually through Canva by selecting Pinterest pin 👇<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.canva.com/">https://www.canva.com/</a></p><p>Pinterest offers SEO benefits that can drive traffic to your website or content. Additionally, there are paid options for promoting pins, but I use the free version.</p><h3 id="h-statistics" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Statistics</h3><p>Out of the many pins I’ve created, some have performed exceptionally well. For instance, my article ‘<strong>How to Stop Vaping for Good</strong>’ received 25 clicks, with 8 coming from Pinterest.</p><p>As you can see from above picture while most dont get any traction I made one article listed bellow.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://richard-taujenis.medium.com/how-to-stop-vaping-for-good-bb3e0563648e"><strong>How to Stop Vaping for Good</strong><em>Easy steps on how to stop your cravings on vaping</em>richard-taujenis.medium.com</a></p><p>So while it doesn&apos;t occur often it doesn&apos;t take as much time to create a Pin.</p><p>Bellow you can see how much pins i have created reality paints a different picture often in life compared to what we expect.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://pl.pinterest.com/richardtaujenis/">https://pl.pinterest.com/richardtaujenis/</a></p><hr><p>Branding yourself in a digital landscape has never been as competitive and saturated as it is now. While people say “you have to stand out from the rest” has never been more difficult, as when everyone is doing the same thing how to stand out?</p><p>While Pinterest may not always bring immediate results, its potential for long-term brand building is significant. Don’t overlook this powerful platform in your personal branding strategy.</p>]]></content:encoded>
            <author>mozes721@newsletter.paragraph.com (Mozes721)</author>
        </item>
        <item>
            <title><![CDATA[Effortlessly Deploy Your GCP Cloud Run App Using Terraform]]></title>
            <link>https://paragraph.com/@mozes721/effortlessly-deploy-your-gcp-cloud-run-app-using-terraform</link>
            <guid>08uRPeeEKFlUp6730xEX</guid>
            <pubDate>Fri, 01 Nov 2024 14:01:03 GMT</pubDate>
            <description><![CDATA[Terraform is gaining more popularity for a reason as it provides high level of control flexibility as IaC(Infrastructure as Code) Supports modules, keeps track of state of your infrastructure and is helpfull if your project is complex, multi-cloud or hybrid enviornments.PrerequisitesTo start off be sure to follow this guide for Terraform instalation if you haven’t done so and be sure to have GCP account already set up.You should have the app already prior deployed through other means like CLI...]]></description>
            <content:encoded><![CDATA[<p>Terraform is gaining more popularity for a reason as it provides high level of control flexibility as IaC(Infrastructure as Code)</p><p>Supports modules, keeps track of state of your infrastructure and is helpfull if your project is complex, multi-cloud or hybrid enviornments.</p><h3 id="h-prerequisites" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Prerequisites</h3><p>To start off be sure to follow <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://developer.hashicorp.com/terraform/install">this</a> guide for Terraform instalation if you haven’t done so and be sure to have <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://cloud.google.com/gcp?&amp;gad_source=1">GCP </a>account already set up.</p><blockquote><p>You should have the app already prior deployed through other means like CLI to understand the deployment process, baseline configuration, incremental transition etc.</p></blockquote><p>Related blog with manual deployment I added bellow 👇📖</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.stackademic.com/how-to-deploy-a-go-service-to-gcp-cloud-run-694d01cab5b5">https://blog.stackademic.com/how-to-deploy-a-go-service-to-gcp-cloud-run-694d01cab5b5</a></p><h3 id="h-project-structure" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Project Structure</h3><p>For my project structure I have these files and directory structure.</p><pre data-type="codeBlock" text="terraform/
  ├── modules/
  │   ├── docker/
  │   │   ├── docker-artifact.tf
  │   │   └── variables.tf
  │   ├── gcp/
  │   │   ├── cloud-run.tf
  │   │   └── variables.tf
  ├── main.tf
  ├── set-prod.env.sh
  ├── terraform.tfvars
  ├── variables.tf
  └── account_key.json
"><code>terraform<span class="hljs-operator">/</span>
  ├── modules<span class="hljs-operator">/</span>
  │   ├── docker<span class="hljs-operator">/</span>
  │   │   ├── docker<span class="hljs-operator">-</span>artifact.tf
  │   │   └── variables.tf
  │   ├── gcp<span class="hljs-operator">/</span>
  │   │   ├── cloud<span class="hljs-operator">-</span>run.tf
  │   │   └── variables.tf
  ├── main.tf
  ├── set<span class="hljs-operator">-</span>prod.env.sh
  ├── terraform.tfvars
  ├── variables.tf
  └── account_key.json
</code></pre><ul><li><p><code>main.tf</code>: Including the required providers and the Google provider configuration.</p></li><li><p><code>variables.tf</code>: Describe how to define variables for your project.</p></li><li><p><code>terraform.tfvars</code>: Explain how to set variable values specific to your environment.</p></li><li><p><code>set-prod.env.sh</code>: Sets the enviornment variables for terraform with <strong>TF_VAR</strong> prefix flag.</p></li><li><p><strong>Modules</strong>: Detail the <code>docker</code> and <code>cloud-run</code> modules, explaining their roles and how they interact.</p><h3 id="h-iac-scripts" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">IaC Scripts</h3><p>I will showcase from parent to child modules scripts for more of a higher order guide.</p><p>Most likely you will have env variables most convieneit way for me is to create shell script with the <code>TF_VAR_</code> prefix that Terraform will recoginze and use ones initialized(but for that later).</p><pre data-type="codeBlock" text="#!/bin/bash

#server 
export TF_VAR_redis_url=&quot;redis_url&quot;
export TF_VAR_firebase_account_key=&quot;your_account_key.json&quot;
export TF_VAR_client_url=&quot;client_url&quot;
export TF_VAR_gcp_account_key=&quot;client_url&quot;

echo &quot;Environment variables for Terraform GCP set.&quot;
"><code><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment">#server </span>
<span class="hljs-built_in">export</span> TF_VAR_redis_url=<span class="hljs-string">"redis_url"</span>
<span class="hljs-built_in">export</span> TF_VAR_firebase_account_key=<span class="hljs-string">"your_account_key.json"</span>
<span class="hljs-built_in">export</span> TF_VAR_client_url=<span class="hljs-string">"client_url"</span>
<span class="hljs-built_in">export</span> TF_VAR_gcp_account_key=<span class="hljs-string">"client_url"</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Environment variables for Terraform GCP set."</span>
</code></pre><p>Variables that i have as well set in module level but parent will usually contain all of them but in module level i just passed the right ones.</p><pre data-type="codeBlock" text="variable &quot;project_id&quot; {
  description = &quot;The ID of the Google Cloud project.&quot;
  type        = string
}

variable &quot;project_name&quot; {
  description = &quot;The project name of the Google Cloud Run project.&quot;
  type        = string
}


variable &quot;region&quot; {
  description = &quot;The Google Cloud region.&quot;
  type        = string
}


variable &quot;redis_url&quot; {
  description = &quot;The URL for the Redis instance.&quot;
  type        = string
}


variable &quot;client_url&quot; {
  description = &quot;The URL for the client application.&quot;
  type        = string
}

variable &quot;gcp_account_key&quot; {
  description = &quot;Path to the Google Cloud service account key file.&quot;
  type        = string
}

variable &quot;firebase_account_key_location&quot; {
  description = &quot;Firebase account key location in Docker container.&quot;
  type        = string
}
"><code>variable <span class="hljs-string">"project_id"</span> {
  description <span class="hljs-operator">=</span> <span class="hljs-string">"The ID of the Google Cloud project."</span>
  <span class="hljs-keyword">type</span>        <span class="hljs-operator">=</span> <span class="hljs-keyword">string</span>
}

variable <span class="hljs-string">"project_name"</span> {
  description <span class="hljs-operator">=</span> <span class="hljs-string">"The project name of the Google Cloud Run project."</span>
  <span class="hljs-keyword">type</span>        <span class="hljs-operator">=</span> <span class="hljs-keyword">string</span>
}


variable <span class="hljs-string">"region"</span> {
  description <span class="hljs-operator">=</span> <span class="hljs-string">"The Google Cloud region."</span>
  <span class="hljs-keyword">type</span>        <span class="hljs-operator">=</span> <span class="hljs-keyword">string</span>
}


variable <span class="hljs-string">"redis_url"</span> {
  description <span class="hljs-operator">=</span> <span class="hljs-string">"The URL for the Redis instance."</span>
  <span class="hljs-keyword">type</span>        <span class="hljs-operator">=</span> <span class="hljs-keyword">string</span>
}


variable <span class="hljs-string">"client_url"</span> {
  description <span class="hljs-operator">=</span> <span class="hljs-string">"The URL for the client application."</span>
  <span class="hljs-keyword">type</span>        <span class="hljs-operator">=</span> <span class="hljs-keyword">string</span>
}

variable <span class="hljs-string">"gcp_account_key"</span> {
  description <span class="hljs-operator">=</span> <span class="hljs-string">"Path to the Google Cloud service account key file."</span>
  <span class="hljs-keyword">type</span>        <span class="hljs-operator">=</span> <span class="hljs-keyword">string</span>
}

variable <span class="hljs-string">"firebase_account_key_location"</span> {
  description <span class="hljs-operator">=</span> <span class="hljs-string">"Firebase account key location in Docker container."</span>
  <span class="hljs-keyword">type</span>        <span class="hljs-operator">=</span> <span class="hljs-keyword">string</span>
}
</code></pre><p>There is as well other script file that I created that does <strong>NOT</strong> contain private or secret key values that can be easily modified and is handy for default values thats your <code>terraform.tfvars</code></p><pre data-type="codeBlock" text="project_id = &quot;recepies-6e7c0&quot;
project_name = &quot;recipe-service&quot;
region     = &quot;europe-north1&quot;
gcp_account_key = &quot;./account_key.json&quot;
firebase_account_key_location = &quot;/app/config/account_key.json&quot;
"><code><span class="hljs-attr">project_id</span> = <span class="hljs-string">"recepies-6e7c0"</span>
<span class="hljs-attr">project_name</span> = <span class="hljs-string">"recipe-service"</span>
<span class="hljs-attr">region</span>     = <span class="hljs-string">"europe-north1"</span>
<span class="hljs-attr">gcp_account_key</span> = <span class="hljs-string">"./account_key.json"</span>
<span class="hljs-attr">firebase_account_key_location</span> = <span class="hljs-string">"/app/config/account_key.json"</span>
</code></pre><p>Lets talk about 🐘 in the room our <code>main.tf</code> script.</p><pre data-type="codeBlock" text="terraform {
  required_providers {
    google = {
      source  = &quot;hashicorp/google&quot;
      version = &quot;&gt;= 4.0.0&quot;
    }
  }
  required_version = &quot;&gt;= 0.12&quot;
}

provider &quot;google&quot; {
  credentials = file(var.gcp_account_key)
  project     = var.project_id
  region      = var.region
}

# Get project information
data &quot;google_project&quot; &quot;project&quot; {
  project_id = var.project_id
}

module &quot;docker&quot; {
  source      = &quot;./modules/docker&quot;
  project_id  = var.project_id
}

module &quot;cloud_run&quot; {
  source      = &quot;./modules/gcp&quot;
  project_id  = var.project_id
  region      = var.region
  redis_url   = var.redis_url
  client_url  = var.client_url
  firebase_account_key_location = var.firebase_account_key_location
  cloudrun_image = &quot;gcr.io/${var.project_id}/recipe-server:latest&quot;

  depends_on = [
    module.docker
  ]
}
"><code>terraform {
  required_providers {
    google <span class="hljs-operator">=</span> {
      source  <span class="hljs-operator">=</span> <span class="hljs-string">"hashicorp/google"</span>
      version <span class="hljs-operator">=</span> <span class="hljs-string">">= 4.0.0"</span>
    }
  }
  required_version <span class="hljs-operator">=</span> <span class="hljs-string">">= 0.12"</span>
}

provider <span class="hljs-string">"google"</span> {
  credentials <span class="hljs-operator">=</span> file(<span class="hljs-keyword">var</span>.gcp_account_key)
  project     <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.project_id
  region      <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.region
}

# Get project information
data <span class="hljs-string">"google_project"</span> <span class="hljs-string">"project"</span> {
  project_id <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.project_id
}

module <span class="hljs-string">"docker"</span> {
  source      <span class="hljs-operator">=</span> <span class="hljs-string">"./modules/docker"</span>
  project_id  <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.project_id
}

module <span class="hljs-string">"cloud_run"</span> {
  source      <span class="hljs-operator">=</span> <span class="hljs-string">"./modules/gcp"</span>
  project_id  <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.project_id
  region      <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.region
  redis_url   <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.redis_url
  client_url  <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.client_url
  firebase_account_key_location <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.firebase_account_key_location
  cloudrun_image <span class="hljs-operator">=</span> <span class="hljs-string">"gcr.io/${var.project_id}/recipe-server:latest"</span>

  depends_on <span class="hljs-operator">=</span> [
    module.docker
  ]
}
</code></pre><p>At the begining I define the <strong>PaaS</strong> provider as i use <strong>GCP</strong> google is added you can add <strong>AWS</strong>, <strong>Azure</strong> or other providers. Creditentials are essential to approve your request to any cloud provider the gcp_account_key you pass as a json file that i have in parent terraform directory.</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/40d8e395ef598c402592078ba99bfca56ad1aaa6d38ce10b8e11c983453d1484.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>At above screenshot you can see i have created a Service account key in GCP and passed the right IAM access rights.</p><blockquote><p>It crucial to assign the correct IAM (Identity and Access Management) access rights to the <code>account_key.json </code>as otherwise you will have different permission issues when trying to run Terraform. Roles viewer, editor, storage.admin, cloudrun.admin, Docker artifacts.</p></blockquote><p>There is an alternative as well to just assign roles and permission through IaC but for me it’s more an hastle at least until i get more familiar with it.</p><pre data-type="codeBlock" text="gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
  --member=&quot;serviceAccount:YOUR_SERVICE_ACCOUNT_EMAIL&quot; \
  --role=&quot;roles/editor&quot;
"><code>gcloud projects add<span class="hljs-operator">-</span>iam<span class="hljs-operator">-</span>policy<span class="hljs-operator">-</span>binding YOUR_PROJECT_ID \
  <span class="hljs-operator">-</span><span class="hljs-operator">-</span>member<span class="hljs-operator">=</span><span class="hljs-string">"serviceAccount:YOUR_SERVICE_ACCOUNT_EMAIL"</span> \
  <span class="hljs-operator">-</span><span class="hljs-operator">-</span>role<span class="hljs-operator">=</span><span class="hljs-string">"roles/editor"</span>
</code></pre><p>Above ilustrates how it could be done.</p><p>Then next steps are running your modules I start off with docker as need to create Docker Artifact in GCP and after that is completed I do the same with Cloud Run. Keep in mind I access the dir with <code>&quot;./modules/docker&quot; </code>and pass needed variables from parent to child <code>modules/docker/variables.tf</code> <em>.</em></p><pre data-type="codeBlock" text="resource &quot;google_project_service&quot; &quot;container_registry_api&quot; {
  project = var.project_id
  service = &quot;containerregistry.googleapis.com&quot;
  disable_on_destroy = false
}

resource &quot;null_resource&quot; &quot;docker_build_push&quot; {
  triggers = {
    always_run = timestamp()
  }

  provisioner &quot;local-exec&quot; {
    command = &lt;&lt;-EOT
      # Build the Docker image
      docker build -t gcr.io/${var.project_id}/recipe-server:latest .
      
      # Configure docker to authenticate with GCP
      gcloud auth configure-docker --quiet
      
      # Push the image
      docker push gcr.io/${var.project_id}/recipe-server:latest
    EOT
  }

  depends_on = [
    google_project_service.container_registry_api
  ]
}
"><code>resource <span class="hljs-string">"google_project_service"</span> <span class="hljs-string">"container_registry_api"</span> {
  project <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.project_id
  service <span class="hljs-operator">=</span> <span class="hljs-string">"containerregistry.googleapis.com"</span>
  disable_on_destroy <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>
}

resource <span class="hljs-string">"null_resource"</span> <span class="hljs-string">"docker_build_push"</span> {
  triggers <span class="hljs-operator">=</span> {
    always_run <span class="hljs-operator">=</span> timestamp()
  }

  provisioner <span class="hljs-string">"local-exec"</span> {
    command <span class="hljs-operator">=</span> <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">-</span>EOT
      # Build the Docker image
      docker build <span class="hljs-operator">-</span>t gcr.io/${<span class="hljs-keyword">var</span>.project_id}<span class="hljs-operator">/</span>recipe<span class="hljs-operator">-</span>server:latest .
      
      # Configure docker to authenticate with GCP
      gcloud auth configure<span class="hljs-operator">-</span>docker <span class="hljs-operator">-</span><span class="hljs-operator">-</span>quiet
      
      # Push the image
      docker push gcr.io/${<span class="hljs-keyword">var</span>.project_id}<span class="hljs-operator">/</span>recipe<span class="hljs-operator">-</span>server:latest
    EOT
  }

  depends_on <span class="hljs-operator">=</span> [
    google_project_service.container_registry_api
  ]
}
</code></pre><p>The <em>docker-artifact.tf</em> is quite short as only think we need is to define the resources used starting with <strong>container_registry_api</strong> and secondly <strong>docker_build_push</strong> add provisioning for local execution and end it with building and deploying the grc docker image with passed in <em>var.project_id +</em> add that it depends on container_registry_api as its required.</p><p>Lastly in our <strong>IaC</strong> we deploy it running our last module with <code>&quot;./modules/gcp&quot;</code></p><pre data-type="codeBlock" text="resource &quot;google_project_service&quot; &quot;required_apis&quot; {
  for_each = toset([
    &quot;run.googleapis.com&quot;,
    &quot;containerregistry.googleapis.com&quot;
  ])
  
  project = var.project_id
  service = each.key
  disable_on_destroy = false
}

resource &quot;google_cloud_run_service&quot; &quot;recipe_service&quot; {
  name     = var.project_name
  location = var.region
  project  = var.project_id

  template {
    spec {
      containers {
        image = var.cloudrun_image
        
        env {
          name  = &quot;REDIS_URL&quot;
          value = var.redis_url
        }
        env {
          name  = &quot;CLIENT_URL&quot;
          value = var.client_url
        }
        env {
          name  = &quot;FIREBASE_ACCOUNT_KEY&quot;
          value = var.firebase_account_key_location
        }
      }
    }
  }

  depends_on = [
    google_project_service.required_apis
  ]
}

resource &quot;google_cloud_run_service_iam_member&quot; &quot;public_access&quot; {
  location = google_cloud_run_service.recipe_service.location
  project  = google_cloud_run_service.recipe_service.project
  service  = google_cloud_run_service.recipe_service.name
  role     = &quot;roles/run.invoker&quot;
  member   = &quot;allUsers&quot;
}
"><code>resource <span class="hljs-string">"google_project_service"</span> <span class="hljs-string">"required_apis"</span> {
  for_each <span class="hljs-operator">=</span> toset([
    <span class="hljs-string">"run.googleapis.com"</span>,
    <span class="hljs-string">"containerregistry.googleapis.com"</span>
  ])
  
  project <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.project_id
  service <span class="hljs-operator">=</span> each.key
  disable_on_destroy <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>
}

resource <span class="hljs-string">"google_cloud_run_service"</span> <span class="hljs-string">"recipe_service"</span> {
  name     <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.project_name
  location <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.region
  project  <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.project_id

  template {
    spec {
      containers {
        image <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.cloudrun_image
        
        env {
          name  <span class="hljs-operator">=</span> <span class="hljs-string">"REDIS_URL"</span>
          value <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.redis_url
        }
        env {
          name  <span class="hljs-operator">=</span> <span class="hljs-string">"CLIENT_URL"</span>
          value <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.client_url
        }
        env {
          name  <span class="hljs-operator">=</span> <span class="hljs-string">"FIREBASE_ACCOUNT_KEY"</span>
          value <span class="hljs-operator">=</span> <span class="hljs-keyword">var</span>.firebase_account_key_location
        }
      }
    }
  }

  depends_on <span class="hljs-operator">=</span> [
    google_project_service.required_apis
  ]
}

resource <span class="hljs-string">"google_cloud_run_service_iam_member"</span> <span class="hljs-string">"public_access"</span> {
  location <span class="hljs-operator">=</span> google_cloud_run_service.recipe_service.location
  project  <span class="hljs-operator">=</span> google_cloud_run_service.recipe_service.project
  service  <span class="hljs-operator">=</span> google_cloud_run_service.recipe_service.<span class="hljs-built_in">name</span>
  role     <span class="hljs-operator">=</span> <span class="hljs-string">"roles/run.invoker"</span>
  member   <span class="hljs-operator">=</span> <span class="hljs-string">"allUsers"</span>
}
</code></pre><p>Same as for docker module we define required resources for <code>&quot;google_cloud_run_service&quot;</code> we select the name, region, project_id then select the image thats been passed from main.</p><p>If you have required env variables pass them as well.</p><p>IAM member resource is added to give permission for deployment to Cloud Run.</p><h3 id="h-deploying-your-application" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Deploying Your Application</h3><p>Now when architecture is set and done we do the following steps.</p><p>1.Initialize Terraform</p><pre data-type="codeBlock" text="terraform init
"><code>terraform <span class="hljs-keyword">init</span>
</code></pre><p>2. Run the Shell Script or manually set your env variables</p><pre data-type="codeBlock" text="source set-prod.env.sh
"><code>source set<span class="hljs-operator">-</span>prod.env.sh
</code></pre><p>For terraform to access the .env variables.</p><p>3. Preview the changes in terraform or dirrectly deploy it.</p><pre data-type="codeBlock" text="terraform plan //Helps you preview the changes that Terraform will make to your infrastructure. 

terraform apply //Run the terraform script to deploy your app through IaC.
"><code>terraform plan <span class="hljs-comment">//Helps you preview the changes that Terraform will make to your infrastructure. </span>

terraform apply <span class="hljs-comment">//Run the terraform script to deploy your app through IaC.</span>
</code></pre><p>If all is good you will end up with something like this.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e81e78d2f8b18fa415da16c57ae13af68cc971fb6526b29a213e70534a7790e9.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>If commiting to GitHub be note worthy to add some files in <em>.gitignore</em> as terraform generates artifacts and backup etc.</p><pre data-type="codeBlock" text="terraform/set-prod-env.sh
terraform/account_key.json
terraform/.terraform
terraform/.terraform.lock.hcl
terraform/.terraform.tfstate.lock.info

# Ignore Terraform working directory
terraform/.terraform/

# Ignore tfstate files and backups
*.tfstate
*.tfstate.backup
"><code>terraform<span class="hljs-operator">/</span>set<span class="hljs-operator">-</span>prod<span class="hljs-operator">-</span>env.sh
terraform<span class="hljs-operator">/</span>account_key.json
terraform<span class="hljs-operator">/</span>.terraform
terraform<span class="hljs-operator">/</span>.terraform.lock.hcl
terraform<span class="hljs-operator">/</span>.terraform.tfstate.lock.info

# Ignore Terraform working directory
terraform<span class="hljs-operator">/</span>.terraform/

# Ignore tfstate files and backups
<span class="hljs-operator">*</span>.tfstate
<span class="hljs-operator">*</span>.tfstate.backup
</code></pre><h3 id="h-conclusion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Conclusion</h3><p>While IaC adds some complexity compared to manual setup it adds as well levarage as mentioned before of more maintainability and automation espectially of interact between multiple cloud providers etc. As well for me personally it gives more power to me as a developer!</p><p>Repo you can find <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Mozes721/RecipesApp">here</a>.</p>]]></content:encoded>
            <author>mozes721@newsletter.paragraph.com (Mozes721)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/a31b85890a18e336af7b80a6be5c9f56f8ab859a782838a3069106c4d6b0881a.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[How to Deploy a Go service to GCP Cloud Run]]></title>
            <link>https://paragraph.com/@mozes721/how-to-deploy-a-go-service-to-gcp-cloud-run</link>
            <guid>KTSHPaUeFLBe6y5WI4iO</guid>
            <pubDate>Wed, 02 Oct 2024 15:11:58 GMT</pubDate>
            <description><![CDATA[Deploying a Go service to GCP Cloud Run involves several steps, including setting up a Dockerfile and configuring environment variables. This guide will walk you through the process.Set up your GCP ProjectStart off by going to GCP create account if havent done so yet.Create a GCP Project.Go to the GCP console and create a new project.Note the project ID for deployment.The id you will use for deploying to particular projects2.Enable required APIs.Enable the Cloud Run API and Container Registry...]]></description>
            <content:encoded><![CDATA[<p>Deploying a Go service to GCP Cloud Run involves several steps, including setting up a Dockerfile and configuring environment variables.</p><p>This guide will walk you through the process.</p><h3 id="h-set-up-your-gcp-project" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Set up your GCP Project</h3><p>Start off by going to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://cloud.google.com/">GCP</a> create account if havent done so yet.</p><ol><li><p>Create a GCP Project.</p></li></ol><ul><li><p>Go to the GCP console and create a new project.</p></li><li><p>Note the project ID for deployment.</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/24f63c3d88ea8fe10339007207c948394be92636fd3486d805766d92afe40e91.png" alt="The id you will use for deploying to particular projects" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">The id you will use for deploying to particular projects</figcaption></figure><p>2.Enable required APIs.</p><ul><li><p>Enable the Cloud Run API and Container Registry API.</p></li></ul><p>3.Install Google Cloud SDK</p><ul><li><p>Initialize your repository with <code>gcloud init</code>.</p></li></ul><h3 id="h-create-your-go-service" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Create your Go Service</h3><p>Ensure your Go app can run locally and set up a Dockerfile.</p><p>cmd/main.go</p><pre data-type="codeBlock" text="// cmd/main.go
func main() {
 flag.Parse()

 a := app.Application{}

 if err := a.LoadConfigurations(); err != nil {
        log.Fatalf(&quot;Failed to load configurations: %v&quot;, err)
    }

    if err := runtime.Start(&amp;a); err != nil {
        log.Fatalf(&quot;Failed to start the application: %v&quot;, err)
    }

}
"><code><span class="hljs-comment">// cmd/main.go</span>
func main() {
 flag.Parse()

 a :<span class="hljs-operator">=</span> app.Application{}

 <span class="hljs-keyword">if</span> err :<span class="hljs-operator">=</span> a.LoadConfigurations(); err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
        log.Fatalf(<span class="hljs-string">"Failed to load configurations: %v"</span>, err)
    }

    <span class="hljs-keyword">if</span> err :<span class="hljs-operator">=</span> runtime.Start(<span class="hljs-operator">&#x26;</span>a); err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
        log.Fatalf(<span class="hljs-string">"Failed to start the application: %v"</span>, err)
    }

}
</code></pre><p>runtime/base.go</p><pre data-type="codeBlock" text="func Start(a *app.Application) error {
    router := gin.New()

    router.Use(cors.New(md.CORSMiddleware()))

    api.SetCache(router, a.RedisClient)
    api.SetRoutes(router, a.FireClient, a.FireAuth, a.RedisClient)

    err := router.Run(&quot;:&quot; + a.ListenPort)
    log.Printf(&quot;Starting server on port: %s&quot;, a.ListenPort)
    if err != nil {
        return err
    }

    return nil
}
"><code>func Start(a <span class="hljs-operator">*</span>app.Application) <span class="hljs-function"><span class="hljs-keyword">error</span> </span>{
    router :<span class="hljs-operator">=</span> gin.New()

    router.Use(cors.New(md.CORSMiddleware()))

    api.SetCache(router, a.RedisClient)
    api.SetRoutes(router, a.FireClient, a.FireAuth, a.RedisClient)

    err :<span class="hljs-operator">=</span> router.Run(<span class="hljs-string">":"</span> <span class="hljs-operator">+</span> a.ListenPort)
    log.Printf(<span class="hljs-string">"Starting server on port: %s"</span>, a.ListenPort)
    <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
        <span class="hljs-keyword">return</span> err
    }

    <span class="hljs-keyword">return</span> nil
}
</code></pre><p>Create Dockerfile</p><pre data-type="codeBlock" text="# Use the official Go image as the base image
FROM golang:1.18

WORKDIR /app

# Copy the Go module files
COPY go.mod go.sum ./

RUN go mod download

# Copy the rest of the application code
COPY . .

RUN go build -o main  ./cmd/main.go

CMD [&quot;./main&quot;]
"><code># Use the official Go image <span class="hljs-keyword">as</span> the base image
FROM golang:<span class="hljs-number">1.18</span>

WORKDIR <span class="hljs-operator">/</span>app

# Copy the Go module files
COPY go.mod go.sum ./

RUN go mod download

# Copy the rest of the application code
COPY . .

RUN go build <span class="hljs-operator">-</span>o main  ./cmd<span class="hljs-operator">/</span>main.go

CMD [<span class="hljs-string">"./main"</span>]
</code></pre><p>Set Up Env variables</p><p>Use shell script to automate setting env variables for GCP</p><p>as <strong>env-variables.sh.</strong></p><pre data-type="codeBlock" text="// env-variables.sh
#!/bin/bash

# Environment variables
export PROJECT_ID=recepies-6e7c0
export REGION=europe-west1

export REDIS_URL=&quot;rediss://default:AVrvA....-lemur-23279.u....:6379&quot;
export FIREBASE_ACCOUNT_KEY=&quot;/app/config/account_key.json&quot;
export CLIENT_URL=&quot;https://.....vercel.app/&quot;
"><code>// env-variables.sh
<span class="hljs-comment">#!/bin/bash</span>

<span class="hljs-comment"># Environment variables</span>
export <span class="hljs-attr">PROJECT_ID</span>=recepies-<span class="hljs-number">6</span>e7c0
export <span class="hljs-attr">REGION</span>=europe-west1

export <span class="hljs-attr">REDIS_URL</span>=<span class="hljs-string">"rediss://default:AVrvA....-lemur-23279.u....:6379"</span>
export <span class="hljs-attr">FIREBASE_ACCOUNT_KEY</span>=<span class="hljs-string">"/app/config/account_key.json"</span>
export <span class="hljs-attr">CLIENT_URL</span>=<span class="hljs-string">"https://.....vercel.app/"</span>
</code></pre><p>Deployment script as <strong>deploy-with-yaml.sh</strong>.</p><pre data-type="codeBlock" text="#!/bin/bash

source env-variables.sh

#Comment if correctly deployed
docker build -t gcr.io/$PROJECT_ID/recipe-server:latest .
docker push gcr.io/$PROJECT_ID/recipe-server:latest

#Uncomment if json needs to be added to GCP 
# gcloud secrets create firebase-account-key --data-file=/mnt/c/own_dev/RecipesApp/server/config/account_key.json --project=recepies-6e7c0

#Add permission IAM
gcloud projects add-iam-policy-binding recepies-6e7c0 \
    --member=&quot;serviceAccount:service-988443547488@serverless-robot-prod.iam.gserviceaccount.com&quot; \
    --role=&quot;roles/artifactregistry.reader&quot;

gcloud run deploy recipe-service \
  --image gcr.io/$PROJECT_ID/recipe-server:latest \
  --region $REGION \
  --platform managed \
  --set-env-vars REDIS_URL=$REDIS_URL,CLIENT_URL=$CLIENT_URL,FIREBASE_ACCOUNT_KEY=$FIREBASE_ACCOUNT_KEY
"><code>#<span class="hljs-operator">!</span><span class="hljs-operator">/</span>bin<span class="hljs-operator">/</span>bash

source env<span class="hljs-operator">-</span>variables.sh

#Comment <span class="hljs-keyword">if</span> correctly deployed
docker build <span class="hljs-operator">-</span>t gcr.io/$PROJECT_ID<span class="hljs-operator">/</span>recipe<span class="hljs-operator">-</span>server:latest .
docker push gcr.io/$PROJECT_ID<span class="hljs-operator">/</span>recipe<span class="hljs-operator">-</span>server:latest

#Uncomment <span class="hljs-keyword">if</span> json needs to be added to GCP 
# gcloud secrets create firebase<span class="hljs-operator">-</span>account<span class="hljs-operator">-</span>key <span class="hljs-operator">-</span><span class="hljs-operator">-</span>data<span class="hljs-operator">-</span>file<span class="hljs-operator">=</span><span class="hljs-operator">/</span>mnt<span class="hljs-operator">/</span>c<span class="hljs-operator">/</span>own_dev<span class="hljs-operator">/</span>RecipesApp<span class="hljs-operator">/</span>server<span class="hljs-operator">/</span>config<span class="hljs-operator">/</span>account_key.json <span class="hljs-operator">-</span><span class="hljs-operator">-</span>project<span class="hljs-operator">=</span>recepies<span class="hljs-operator">-</span>6e7c0

#Add permission IAM
gcloud projects add<span class="hljs-operator">-</span>iam<span class="hljs-operator">-</span>policy<span class="hljs-operator">-</span>binding recepies<span class="hljs-operator">-</span>6e7c0 \
    <span class="hljs-operator">-</span><span class="hljs-operator">-</span>member<span class="hljs-operator">=</span><span class="hljs-string">"serviceAccount:service-988443547488@serverless-robot-prod.iam.gserviceaccount.com"</span> \
    <span class="hljs-operator">-</span><span class="hljs-operator">-</span>role<span class="hljs-operator">=</span><span class="hljs-string">"roles/artifactregistry.reader"</span>

gcloud run deploy recipe<span class="hljs-operator">-</span>service \
  <span class="hljs-operator">-</span><span class="hljs-operator">-</span>image gcr.io/$PROJECT_ID<span class="hljs-operator">/</span>recipe<span class="hljs-operator">-</span>server:latest \
  <span class="hljs-operator">-</span><span class="hljs-operator">-</span>region $REGION \
  <span class="hljs-operator">-</span><span class="hljs-operator">-</span>platform managed \
  <span class="hljs-operator">-</span><span class="hljs-operator">-</span>set<span class="hljs-operator">-</span>env<span class="hljs-operator">-</span>vars REDIS_URL<span class="hljs-operator">=</span>$REDIS_URL,CLIENT_URL<span class="hljs-operator">=</span>$CLIENT_URL,FIREBASE_ACCOUNT_KEY<span class="hljs-operator">=</span>$FIREBASE_ACCOUNT_KEY
</code></pre><h4 id="h-deployment-to-your-gcp-cloud-run" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Deployment to your GCP Cloud Run</h4><p>Run the deployment script</p><pre data-type="codeBlock" text="env-variables.sh
"><code>env<span class="hljs-operator">-</span>variables.sh
</code></pre><h4 id="h-common-issues-and-troubleshooting" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Common Issues and Troubleshooting</h4><ul><li><p><strong>Permission Issues</strong>: Ensure the Cloud Run Service Agent has permission to read the image.</p></li><li><p><strong>Environment Variables</strong>: Verify that all required environment variables are set correctly.</p></li><li><p><strong>Port Configuration</strong>: Ensure the PORT environment variable is set correctly.</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/df65db776f7c8985ee30fdba055cd590faf6cac7ebd04016e8599ab87cf00a4d.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>When all set up as needed you will see Image being build and pushed to your GCP project Artifact Registry. In the end i got this.</p><blockquote><pre data-type="codeBlock" text="a9099c3159f5: Layer already exists
latest: digest: sha256:8c98063cd5b383df0b444c5747bb729ffd17014d42b049526b8760a4b09e5df1 size: 2846
Deploying container to Cloud Run service [recipe-service] in project [recepies-6e7c0] region [europe-west1]
✓ Deploying... Done.
  ✓ Creating Revision...
  ✓ Routing traffic...
Done.
Service [recipe-service] revision [recipe-service-00024-5mh] has been deployed and is serving 100 percent of traffic.
Service URL: https://recipe-service-819621241045.europe-west1.run.app
"><code>a9099c3159f5: Layer already exists
latest: digest: <span class="hljs-built_in">sha256</span>:8c98063cd5b383df0b444c5747bb729ffd17014d42b049526b8760a4b09e5df1 size: <span class="hljs-number">2846</span>
Deploying container to Cloud Run service [recipe<span class="hljs-operator">-</span>service] in project [recepies<span class="hljs-operator">-</span>6e7c0] region [europe<span class="hljs-operator">-</span>west1]
✓ Deploying... Done.
  ✓ Creating Revision...
  ✓ Routing traffic...
Done.
Service [recipe<span class="hljs-operator">-</span>service] revision [recipe<span class="hljs-operator">-</span>service<span class="hljs-operator">-</span>00024<span class="hljs-operator">-</span>5mh] has been deployed and <span class="hljs-keyword">is</span> serving <span class="hljs-number">100</span> percent of traffic.
Service URL: https:<span class="hljs-comment">//recipe-service-819621241045.europe-west1.run.app</span>
</code></pre><p>There is a standart error that I came across multiple times 👇</p><pre data-type="codeBlock" text="Deploying container to Cloud Run service [recipe-service] in project [recepies-6e7c0] region [europe-west1] X Deploying… - Creating Revision… . Routing traffic… Deployment failed ERROR: 
(gcloud.run.deploy) Revision &apos;recipe-service-00005-b6h&apos; 
is not ready and cannot serve traffic. Google Cloud Run Service Agent service-819621241045@serverless-robot-prod.iam.gserviceaccount.com must have permission to read the image, 
gcr.io/loyal-venture-436807-p7/recipe-server:latest. Ensure that the provided container image URL is correct and that the above account has permission to access the image. If you just enabled the Cloud Run API, the permissions might take a few minutes to propagate. Note that the image is from project [loyal-venture-436807-p7], which is not the same as this project [recepies-6e7c0]. Permission must be granted to the Google Cloud Run Service 
Agent service-819621241045@serverless-robot-prod.iam.gserviceaccount.com from this project. See https://cloud.google.com/run/docs/deploying#other-projects
"><code>Deploying container to Cloud Run service [recipe<span class="hljs-operator">-</span>service] in project [recepies<span class="hljs-operator">-</span>6e7c0] region [europe<span class="hljs-operator">-</span>west1] X Deploying… <span class="hljs-operator">-</span> Creating Revision… . Routing traffic… Deployment failed ERROR: 
(gcloud.run.deploy) Revision <span class="hljs-string">'recipe-service-00005-b6h'</span> 
<span class="hljs-keyword">is</span> not ready and cannot serve traffic. Google Cloud Run Service Agent service<span class="hljs-number">-819621241045</span>@serverless<span class="hljs-operator">-</span>robot<span class="hljs-operator">-</span>prod.iam.gserviceaccount.com must have permission to read the image, 
gcr.io/loyal<span class="hljs-operator">-</span>venture<span class="hljs-number">-436807</span><span class="hljs-operator">-</span>p7<span class="hljs-operator">/</span>recipe<span class="hljs-operator">-</span>server:latest. Ensure that the provided container image URL <span class="hljs-keyword">is</span> correct and that the above account has permission to access the image. If you just enabled the Cloud Run API, the permissions might take a few <span class="hljs-literal">minutes</span> to propagate. Note that the image <span class="hljs-keyword">is</span> <span class="hljs-keyword">from</span> project [loyal<span class="hljs-operator">-</span>venture<span class="hljs-number">-436807</span><span class="hljs-operator">-</span>p7], which <span class="hljs-keyword">is</span> not the same <span class="hljs-keyword">as</span> <span class="hljs-built_in">this</span> project [recepies<span class="hljs-operator">-</span>6e7c0]. Permission must be granted to the Google Cloud Run Service 
Agent service<span class="hljs-number">-819621241045</span>@serverless<span class="hljs-operator">-</span>robot<span class="hljs-operator">-</span>prod.iam.gserviceaccount.com <span class="hljs-keyword">from</span> <span class="hljs-built_in">this</span> project. See https:<span class="hljs-comment">//cloud.google.com/run/docs/deploying#other-projects</span>
</code></pre></blockquote><hr><p>Often it states that PORT=8080 could not be set but main issue is something else like env variable not set or in my case firebase account_key.json incorrectly set for deployment.</p><hr><p>When all is set you can test the connection and do requests.</p><p>I have my frontend deployed in Vercel and bellow you can see my Cloud Run Logs</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/416b5cfcd0ac18222385f9bfc8d737c816491bb664bbf6a9f82abd0e0dc2ca02.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure>]]></content:encoded>
            <author>mozes721@newsletter.paragraph.com (Mozes721)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/b22ab462e9e2a56a78f0be3790c125ba484d0959556843a86db5b995ab41e217.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[gRPC Communication Between Go and Python]]></title>
            <link>https://paragraph.com/@mozes721/grpc-communication-between-go-and-python</link>
            <guid>5HOhQLeAlmSeykRQf0to</guid>
            <pubDate>Thu, 22 Aug 2024 09:38:13 GMT</pubDate>
            <description><![CDATA[gRPC is a powerful, high-performance Remote Procedure Call (RPC) framework that, despite being less commonly used than REST, offers significant advantages in certain scenarios. In addition it’s language agnostic and can run in any environment, making it an ideal choice for server-to-server communication. I will not delve into in whole explenation of it but here is a general link of gRPC. I’ll provide a hands on turtorialGo gRPC clientLets image our Go is client but is a server asfor frontend ...]]></description>
            <content:encoded><![CDATA[<p>gRPC is a powerful, high-performance Remote Procedure Call (RPC) framework that, despite being less commonly used than REST, offers significant advantages in certain scenarios.</p><p>In addition it’s language agnostic and can run in any environment, making it an ideal choice for server-to-server communication.</p><p>I will not delve into in whole explenation of it but <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://grpc.io/">here </a>is a general link of gRPC. I’ll provide a hands on turtorial</p><h3 id="h-go-grpc-client" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Go gRPC client</h3><p>Lets image our Go is client but is a server asfor frontend app React, Svelte etc.</p><pre data-type="codeBlock" text="func getFirstArg() (string, error) {
    if len(os.Args) &lt; 2 {
        return &quot;&quot;, fmt.Errorf(&quot;expected 1 argument, but got none&quot;)
    }
    return os.Args[1], nil
}

func main() {
    filePath, err := getFirstArg()
    if err != nil {
        log.Fatalf(&quot;Failed to get file path from arguments: %v&quot;, err)
    }

    fileData, err := ioutil.ReadFile(filePath)
    if err != nil {
        log.Fatalf(&quot;Failed to read file: %v&quot;, err)
    }

 ...
}
"><code>func getFirstArg() (<span class="hljs-keyword">string</span>, <span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
    <span class="hljs-keyword">if</span> len(os.Args) <span class="hljs-operator">&#x3C;</span> <span class="hljs-number">2</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>, fmt.Errorf(<span class="hljs-string">"expected 1 argument, but got none"</span>)
    }
    <span class="hljs-keyword">return</span> os.Args[<span class="hljs-number">1</span>], nil
}

func main() {
    filePath, err :<span class="hljs-operator">=</span> getFirstArg()
    <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
        log.Fatalf(<span class="hljs-string">"Failed to get file path from arguments: %v"</span>, err)
    }

    fileData, err :<span class="hljs-operator">=</span> ioutil.ReadFile(filePath)
    <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
        log.Fatalf(<span class="hljs-string">"Failed to read file: %v"</span>, err)
    }

 ...
}
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/73f2ebc61735c2792aed479c636b272a16bc0020cad6bee0a6acf7ba364ac8c8.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>As an example React frontend uploads a file, Go process it but we need answers from excel we will use GPT API. While it can be done with Go, Python on the otherhand has more packages that can ease our lives like <em>langchan_openai</em>, <em>pandas</em> for excel and so forth.</p><hr><p>Lets start with instalation of gRPC preferably in your virtualenv <em>.venv</em></p><pre data-type="codeBlock" text="$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

$ export PATH=&quot;$PATH:$(go env GOPATH)/bin&quot;
"><code>$ go install google.golang.org/protobuf<span class="hljs-operator">/</span>cmd<span class="hljs-operator">/</span>protoc<span class="hljs-operator">-</span>gen<span class="hljs-operator">-</span>go@latest
$ go install google.golang.org/grpc<span class="hljs-operator">/</span>cmd<span class="hljs-operator">/</span>protoc<span class="hljs-operator">-</span>gen<span class="hljs-operator">-</span>go<span class="hljs-operator">-</span>grpc@latest

$ export PATH<span class="hljs-operator">=</span><span class="hljs-string">"$PATH:$(go env GOPATH)/bin"</span>
</code></pre><p>Next up you should install protocol buffer in your OS can follow it <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://grpc.io/docs/protoc-installation/">here</a>.</p><p>Let’s create a proto dir where you will store your protocol buffer file I will name it as <em>excel.proto</em> and paste this:</p><pre data-type="codeBlock" text="syntax = &quot;proto3&quot;;

option go_package = &quot;client-gRPC/proto&quot;;

service ExcelService {
    rpc UploadFile(FileRequest) returns (FileResponse);
}

message FileRequest {
    string file_name = 1;
    bytes file_content = 2;
}

message FileResponse {
    bytes file_content = 1;
}
"><code><span class="hljs-attr">syntax</span> = <span class="hljs-string">"proto3"</span><span class="hljs-comment">;</span>

option <span class="hljs-attr">go_package</span> = <span class="hljs-string">"client-gRPC/proto"</span><span class="hljs-comment">;</span>

service ExcelService {
    rpc UploadFile(FileRequest) returns (FileResponse)<span class="hljs-comment">;</span>
}

message FileRequest {
    string <span class="hljs-attr">file_name</span> = <span class="hljs-number">1</span><span class="hljs-comment">;</span>
    bytes <span class="hljs-attr">file_content</span> = <span class="hljs-number">2</span><span class="hljs-comment">;</span>
}

message FileResponse {
    bytes <span class="hljs-attr">file_content</span> = <span class="hljs-number">1</span><span class="hljs-comment">;</span>
}
</code></pre><p>This gRPC service, <code>ExcelService</code>, allows clients to upload a file by sending its name and content. The server responds with the same file content.</p><p>For Go its essential to pass in go_package in Python the line is not needed.</p><blockquote><p><strong>vscode-proto3</strong> is a good extension to download if you use VSCode.</p></blockquote><p>After all of this you can generate your proto files I preffer it in same level as prot dir, for that run this command:</p><pre data-type="codeBlock" text="protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative proto/excel.proto
"><code>protoc <span class="hljs-operator">-</span><span class="hljs-operator">-</span>go_out<span class="hljs-operator">=</span>. -<span class="hljs-operator">-</span>go_opt<span class="hljs-operator">=</span>paths<span class="hljs-operator">=</span>source_relative <span class="hljs-operator">-</span><span class="hljs-operator">-</span>go<span class="hljs-operator">-</span>grpc_out<span class="hljs-operator">=</span>. -<span class="hljs-operator">-</span>go<span class="hljs-operator">-</span>grpc_opt<span class="hljs-operator">=</span>paths<span class="hljs-operator">=</span>source_relative proto<span class="hljs-operator">/</span>excel.proto
</code></pre><p>If succesfull two files should be generated, optionally if there would be a lot of adjustments add a Makefile and define it as proto + upper command.</p><pre data-type="codeBlock" text="import (
    ....

    &quot;google.golang.org/grpc&quot;
    pb &quot;client-gRPC/proto&quot;
    &quot;github.com/xuri/excelize/v2&quot;
)

func main() {
    ....

    conn, err := grpc.Dial(&quot;localhost:50051&quot;, grpc.WithInsecure())
    if err != nil {
        log.Fatalf(&quot;Failed to connect to gRPC server: %v&quot;, err)
    }
    defer conn.Close()

    client := pb.NewExcelServiceClient(conn)

    req := &amp;pb.FileRequest{
        FileName:    filePath,
        FileContent: fileData,
    }

    res, err := client.UploadFile(context.Background(), req)
    if err != nil {
        log.Fatalf(&quot;Failed to upload file: %v&quot;, err)
    }

    outputFile := &quot;output.xlsx&quot;
    err = saveBytesAsExcel(outputFile, res.FileContent)
    if err != nil {
        log.Fatalf(&quot;Failed to save bytes as Excel file: %v&quot;, err)
    }

    fmt.Printf(&quot;Excel file saved as: %s\n&quot;, outputFile)
}

func saveBytesAsExcel(filePath string, fileContent []byte) error {
    f, err := excelize.OpenReader(bytes.NewReader(fileContent))
    if err != nil {
        return fmt.Errorf(&quot;failed to open Excel file: %v&quot;, err)
    }

    if err := f.SaveAs(filePath); err != nil {
        return fmt.Errorf(&quot;failed to save Excel file: %v&quot;, err)
    }
    return nil
}
"><code><span class="hljs-keyword">import</span> (
    ....

    <span class="hljs-string">"google.golang.org/grpc"</span>
    <span class="hljs-title">pb</span> <span class="hljs-string">"client-gRPC/proto"</span>
    <span class="hljs-string">"github.com/xuri/excelize/v2"</span>
)

<span class="hljs-title">func</span> <span class="hljs-title">main</span>() {
    ....

    <span class="hljs-title">conn</span>, <span class="hljs-title">err</span> :<span class="hljs-operator">=</span> <span class="hljs-title">grpc</span>.<span class="hljs-title">Dial</span>(<span class="hljs-string">"localhost:50051"</span>, <span class="hljs-title">grpc</span>.<span class="hljs-title">WithInsecure</span>())
    <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">err</span> <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-title">nil</span> {
        <span class="hljs-title">log</span>.<span class="hljs-title">Fatalf</span>(<span class="hljs-string">"Failed to connect to gRPC server: %v"</span>, <span class="hljs-title">err</span>)
    }
    <span class="hljs-title">defer</span> <span class="hljs-title">conn</span>.<span class="hljs-title">Close</span>()

    <span class="hljs-title">client</span> :<span class="hljs-operator">=</span> <span class="hljs-title">pb</span>.<span class="hljs-title">NewExcelServiceClient</span>(<span class="hljs-title">conn</span>)

    <span class="hljs-title">req</span> :<span class="hljs-operator">=</span> <span class="hljs-operator">&#x26;</span><span class="hljs-title">pb</span>.<span class="hljs-title">FileRequest</span>{
        <span class="hljs-title">FileName</span>:    <span class="hljs-title">filePath</span>,
        <span class="hljs-title">FileContent</span>: <span class="hljs-title">fileData</span>,
    }

    <span class="hljs-title">res</span>, <span class="hljs-title">err</span> :<span class="hljs-operator">=</span> <span class="hljs-title">client</span>.<span class="hljs-title">UploadFile</span>(<span class="hljs-title">context</span>.<span class="hljs-title">Background</span>(), <span class="hljs-title">req</span>)
    <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">err</span> <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-title">nil</span> {
        <span class="hljs-title">log</span>.<span class="hljs-title">Fatalf</span>(<span class="hljs-string">"Failed to upload file: %v"</span>, <span class="hljs-title">err</span>)
    }

    <span class="hljs-title">outputFile</span> :<span class="hljs-operator">=</span> <span class="hljs-string">"output.xlsx"</span>
    <span class="hljs-title">err</span> <span class="hljs-operator">=</span> <span class="hljs-title">saveBytesAsExcel</span>(<span class="hljs-title">outputFile</span>, <span class="hljs-title">res</span>.<span class="hljs-title">FileContent</span>)
    <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">err</span> <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-title">nil</span> {
        <span class="hljs-title">log</span>.<span class="hljs-title">Fatalf</span>(<span class="hljs-string">"Failed to save bytes as Excel file: %v"</span>, <span class="hljs-title">err</span>)
    }

    <span class="hljs-title">fmt</span>.<span class="hljs-title">Printf</span>(<span class="hljs-string">"Excel file saved as: %s\n"</span>, <span class="hljs-title">outputFile</span>)
}

<span class="hljs-title">func</span> <span class="hljs-title">saveBytesAsExcel</span>(<span class="hljs-title">filePath</span> <span class="hljs-title"><span class="hljs-keyword">string</span></span>, <span class="hljs-title">fileContent</span> []<span class="hljs-title"><span class="hljs-keyword">byte</span></span>) <span class="hljs-title"><span class="hljs-keyword">error</span></span> {
    <span class="hljs-title">f</span>, <span class="hljs-title">err</span> :<span class="hljs-operator">=</span> <span class="hljs-title">excelize</span>.<span class="hljs-title">OpenReader</span>(<span class="hljs-title"><span class="hljs-keyword">bytes</span></span>.<span class="hljs-title">NewReader</span>(<span class="hljs-title">fileContent</span>))
    <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">err</span> <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-title">nil</span> {
        <span class="hljs-title"><span class="hljs-keyword">return</span></span> <span class="hljs-title">fmt</span>.<span class="hljs-title">Errorf</span>(<span class="hljs-string">"failed to open Excel file: %v"</span>, <span class="hljs-title">err</span>)
    }

    <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">err</span> :<span class="hljs-operator">=</span> <span class="hljs-title">f</span>.<span class="hljs-title">SaveAs</span>(<span class="hljs-title">filePath</span>); err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
        <span class="hljs-keyword">return</span> fmt.Errorf(<span class="hljs-string">"failed to save Excel file: %v"</span>, err)
    }
    <span class="hljs-keyword">return</span> nil
}
</code></pre><p>We make a connection to listen to 50051 that will be our Python server, &amp;pb.FileRequest was generated prior by using proto command and now we are importing the methods. If you run you will recive 👇 due to Python server not established yet.</p><pre data-type="codeBlock" text="Failed to upload file: rpc error: code = Unavailable desc = connection error: desc = &quot;transport: Error while dialing: dial tcp 127.0.0.1:50051: connect: connection refused&quot;
"><code>Failed <span class="hljs-keyword">to</span> upload file: rpc <span class="hljs-keyword">error</span>: code = Unavailable desc = connection <span class="hljs-keyword">error</span>: desc = <span class="hljs-string">"transport: Error while dialing: dial tcp 127.0.0.1:50051: connect: connection refused"</span>
</code></pre><h3 id="h-python-grpc-server" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Python gRPC server</h3><p>As python will act as a server the approach will be slightly different but in essense same proto file appart from package field is not reqired. Lets start by creating a base <em>main.py</em> without the gRPC just to give a glance of how GPT will populate the questions in excel.</p><pre data-type="codeBlock" text="import os
import openai
import pandas as pd
from dotenv import load_dotenv

def get_answer_from_gpt(apikey: str, question: str):
    openai.api_key = apikey
    response = openai.ChatCompletion.create(
        model=&quot;gpt-4&quot;,
        messages=[
            {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: &quot;You are a helpful assistant.&quot;},
            {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: question}
        ]
    )
    return response[&apos;choices&apos;][0][&apos;message&apos;][&apos;content&apos;].strip()

def answer_questions_df(df: pd.DataFrame, apikey: str):
    answers = []

    for question in df.iloc[:, 0]: 
        answer = get_answer_from_gpt(apikey, question)
        answers.append(answer)
    return answers

if __name__ == &quot;__main__&quot;:
    load_dotenv()

    openai_api_key = os.getenv(&quot;OPENAI_API_KEY&quot;, &quot;OpenAI API key hasn&apos;t been set.&quot;)


    df = pd.read_excel(&apos;Book1.xlsx&apos;)
    
    df[&apos;Answer&apos;] = answer_questions_df(df, openai_api_key) 
"><code>import os
import openai
import pandas as pd
from dotenv import load_dotenv

def get_answer_from_gpt(apikey: str, question: str):
    <span class="hljs-attr">openai.api_key</span> = apikey
    <span class="hljs-attr">response</span> = openai.ChatCompletion.create(
        <span class="hljs-attr">model</span>=<span class="hljs-string">"gpt-4"</span>,
        <span class="hljs-attr">messages</span>=[
            {<span class="hljs-string">"role"</span>: <span class="hljs-string">"system"</span>, <span class="hljs-string">"content"</span>: <span class="hljs-string">"You are a helpful assistant."</span>},
            {<span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>, <span class="hljs-string">"content"</span>: question}
        ]
    )
    return response<span class="hljs-section">['choices']</span><span class="hljs-section">[0]</span><span class="hljs-section">['message']</span><span class="hljs-section">['content']</span>.strip()

def answer_questions_df(df: pd.DataFrame, apikey: str):
    <span class="hljs-attr">answers</span> = []

    for question in df.iloc<span class="hljs-section">[:, 0]</span>: 
        <span class="hljs-attr">answer</span> = get_answer_from_gpt(apikey, question)
        answers.append(answer)
    return answers

if <span class="hljs-attr">__name__</span> == <span class="hljs-string">"__main__"</span>:
    load_dotenv()

    <span class="hljs-attr">openai_api_key</span> = os.getenv(<span class="hljs-string">"OPENAI_API_KEY"</span>, <span class="hljs-string">"OpenAI API key hasn't been set."</span>)


    <span class="hljs-attr">df</span> = pd.read_excel(<span class="hljs-string">'Book1.xlsx'</span>)
    
    df<span class="hljs-section">['Answer']</span> = answer_questions_df(df, openai_api_key) 
</code></pre><p>Its a simple script that will answer questions that Go will send us but the LOC is less due to dedicated <em>openai</em> library that makes it easier.</p><hr><p>We start by as well adding proto dir with same file as above the option section can be removed as disccused. Install gRPC in your virtualenv preferably and follow <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://grpc.io/docs/languages/python/quickstart/">here </a>the instalation for proto generation I ran:</p><pre data-type="codeBlock" text="python3 -m grpc_tools.protoc --proto_path=proto --python_out=proto --grpc_python_out=proto proto/excel.proto
"><code>python3 <span class="hljs-operator">-</span>m grpc_tools.protoc <span class="hljs-operator">-</span><span class="hljs-operator">-</span>proto_path<span class="hljs-operator">=</span>proto <span class="hljs-operator">-</span><span class="hljs-operator">-</span>python_out<span class="hljs-operator">=</span>proto <span class="hljs-operator">-</span><span class="hljs-operator">-</span>grpc_python_out<span class="hljs-operator">=</span>proto proto<span class="hljs-operator">/</span>excel.proto
</code></pre><p>To be in same lvl as my proto directory <em>remember to add _init</em>_.py!</p><p>Ones the files have been generated lets continue on.</p><pre data-type="codeBlock" text="import io
import grpc
from proto import excel_pb2_grpc as excel_grpc
from proto import excel_pb2



class ExcelService(excel_grpc.ExcelServiceServicer):
    def UploadFile(self, request, context):
        try:
            # Convert bytes to a file-like object
            file_like_object = io.BytesIO(request.file_content)

            # Load the workbook from the file-like object
            workbook = openpyxl.load_workbook(file_like_object)

            # Access the first sheet (or use appropriate logic to get the sheet you need)
            sheet = workbook.active

            # Convert the sheet to a DataFrame
            data = sheet.values
            columns = next(data)  # Get the header row
            df = pd.DataFrame(data, columns=columns)

            print(&quot;Loaded DataFrame:&quot;)
            print(df.head())

            # Ensure that the DataFrame is not empty and has questions
            if df.empty or df.shape[1] &lt; 1:
                print(&quot;DataFrame is empty or does not have the expected columns.&quot;)
                return excel_pb2.FileResponse(file_content=b&apos;&apos;)

            # Get answers and add them to the DataFrame
            answers = answer_questions_df(df, openai_api_key)
            df[&apos;Answer&apos;] = answers

            # Write the updated DataFrame back to a BytesIO object
            output = io.BytesIO()
            with pd.ExcelWriter(output, engine=&apos;openpyxl&apos;) as writer:
                df.to_excel(writer, index=False, sheet_name=&apos;Sheet1&apos;)

            # Reset the buffer&apos;s position to the beginning
            output.seek(0)

            # Return the modified file content
            response = excel_pb2.FileResponse(file_content=output.read())
            return response
        except Exception as e:
            print(f&quot;Error processing file: {e}&quot;)
            return excel_pb2.FileResponse(file_content=b&apos;&apos;)
    
def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    excel_grpc.add_ExcelServiceServicer_to_server(ExcelService(), server)
    server.add_insecure_port(&apos;[::]:50051&apos;)
    server.start()
    print(&quot;Server running on port 50051.&quot;)
    server.wait_for_termination()


if __name__ == &quot;__main__&quot;:
    load_dotenv()

    openai_api_key = os.getenv(&quot;OPENAI_API_KEY&quot;, &quot;OpenAI API key hasn&apos;t been set.&quot;)

    serve()
"><code>import io
import grpc
from proto import excel_pb2_grpc as excel_grpc
from proto import excel_pb2



class ExcelService(excel_grpc.ExcelServiceServicer):
    def UploadFile(self, request, context):
        try:
            <span class="hljs-comment"># Convert bytes to a file-like object</span>
            <span class="hljs-attr">file_like_object</span> = io.BytesIO(request.file_content)

            <span class="hljs-comment"># Load the workbook from the file-like object</span>
            <span class="hljs-attr">workbook</span> = openpyxl.load_workbook(file_like_object)

            <span class="hljs-comment"># Access the first sheet (or use appropriate logic to get the sheet you need)</span>
            <span class="hljs-attr">sheet</span> = workbook.active

            <span class="hljs-comment"># Convert the sheet to a DataFrame</span>
            <span class="hljs-attr">data</span> = sheet.values
            <span class="hljs-attr">columns</span> = next(data)  <span class="hljs-comment"># Get the header row</span>
            <span class="hljs-attr">df</span> = pd.DataFrame(data, columns=columns)

            print("Loaded DataFrame:")
            print(df.head())

            <span class="hljs-comment"># Ensure that the DataFrame is not empty and has questions</span>
            if df.empty or df.shape<span class="hljs-section">[1]</span> &#x3C; 1:
                print("DataFrame is empty or does not have the expected columns.")
                return excel_pb2.FileResponse(<span class="hljs-attr">file_content</span>=b<span class="hljs-string">''</span>)

            <span class="hljs-comment"># Get answers and add them to the DataFrame</span>
            <span class="hljs-attr">answers</span> = answer_questions_df(df, openai_api_key)
            df<span class="hljs-section">['Answer']</span> = answers

            <span class="hljs-comment"># Write the updated DataFrame back to a BytesIO object</span>
            <span class="hljs-attr">output</span> = io.BytesIO()
            with pd.ExcelWriter(output, <span class="hljs-attr">engine</span>=<span class="hljs-string">'openpyxl'</span>) as writer:
                df.to_excel(writer, <span class="hljs-attr">index</span>=<span class="hljs-literal">False</span>, sheet_name=<span class="hljs-string">'Sheet1'</span>)

            <span class="hljs-comment"># Reset the buffer's position to the beginning</span>
            output.seek(0)

            <span class="hljs-comment"># Return the modified file content</span>
            <span class="hljs-attr">response</span> = excel_pb2.FileResponse(file_content=output.read())
            return response
        except Exception as e:
            print(f"Error processing file: {e}")
            return excel_pb2.FileResponse(<span class="hljs-attr">file_content</span>=b<span class="hljs-string">''</span>)
    
def serve():
    <span class="hljs-attr">server</span> = grpc.server(futures.ThreadPoolExecutor(max_workers=<span class="hljs-number">10</span>))
    excel_grpc.add_ExcelServiceServicer_to_server(ExcelService(), server)
    server.add_insecure_port('<span class="hljs-section">[::]</span>:50051')
    server.start()
    print("Server running on port 50051.")
    server.wait_for_termination()


if <span class="hljs-attr">__name__</span> == <span class="hljs-string">"__main__"</span>:
    load_dotenv()

    <span class="hljs-attr">openai_api_key</span> = os.getenv(<span class="hljs-string">"OPENAI_API_KEY"</span>, <span class="hljs-string">"OpenAI API key hasn't been set."</span>)

    serve()
</code></pre><p>We define server and add ExcelService class what containes the methods generated by proto file. Because we recive file by bytes have to use io byte reader and commence further processing of the file and population the second column.</p><pre data-type="codeBlock" text="response = excel_pb2.FileResponse(file_content=output.read())
"><code>response <span class="hljs-operator">=</span> excel_pb2.FileResponse(file_content<span class="hljs-operator">=</span>output.read())
</code></pre><p>At the end we are returning ☝️ for our Go client to recive.</p><blockquote><p>To be able to find proto files in python however you should define an export path<strong><em>export PYTHONPATH=$PYTHONPATH:mnt/c/own_dev/gRPC/server/proto</em></strong></p></blockquote><h4 id="h-running-client-and-server" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Running Client and Server</h4><p>If all is good you can run</p><pre data-type="codeBlock" text="#First comes server

python3 -m main

#Then client

go run client.go Book1.xlsx
"><code>#First comes server

python3 <span class="hljs-operator">-</span>m main

#Then client

go run client.go Book1.xlsx
</code></pre><p>And you should get the updated .xlsx file in Go client side.</p><h4 id="h-conclusion" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Conclusion</h4><p>In this article we explored the fundamentals of setting up gRPC communication between Python server and Go client. By leveraging gRPC, we established a seamless way to send an Excel file from a Go application to a Python server, process the file using OpenAI’s GPT API, and return the modified file back to the Go client.</p>]]></content:encoded>
            <author>mozes721@newsletter.paragraph.com (Mozes721)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/6bcdc64e576b1a48ef36e63f875225d9b32c192c51327b71f419ab10afacf1e6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Transform Your Raspberry Pi into a Network-wide Ad Blocker]]></title>
            <link>https://paragraph.com/@mozes721/transform-your-raspberry-pi-into-a-network-wide-ad-blocker</link>
            <guid>DnZSAeC3a0Ntya6uZObK</guid>
            <pubDate>Sat, 03 Aug 2024 09:07:15 GMT</pubDate>
            <description><![CDATA[Advertisments are everywhere in todays digital landscape, from websites, apps, and even streaming services. Taking matters in own hands by blocking ads and tracking scripts, setting up your own ad blocker with a Raspberry Pi is a great way to start. Appart from the project that will help you manage ads, but it also offers a hands on way to learn about Internet of Things (IoT).How does it work?We will use Pi-hole it’s a popular tool that acts as a network-wide ad blocke by functioning as a DNS...]]></description>
            <content:encoded><![CDATA[<figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e0f171a3dadb61a111fa749cac197f26acb599ad510e2d5b7ea4f6e93f94e0f2.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Advertisments are everywhere in todays digital landscape, from websites, apps, and even streaming services. Taking matters in own hands by blocking ads and tracking scripts, setting up your own ad blocker with a Raspberry Pi is a great way to start. Appart from the project that will help you manage ads, but it also offers a hands on way to learn about Internet of Things (IoT).</p><h4 id="h-how-does-it-work" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">How does it work?</h4><p>We will use <em>Pi-hole</em> it’s a popular tool that acts as a network-wide ad blocke by functioning as a DNS sinkhole. In a nutshell <em>Pi-hole</em> interecentps <em>DNS</em> requests and blocks these that match known ad and tracking domains.</p><p><strong>DNS (Domain Name System)</strong>: <strong>DNS</strong> is like the phonebook of the internet. Basically it translates names like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.google.com">www.google.com</a> into IP address</p><ul><li><p><strong>Primary DNS (IPv4):</strong> <code>8.8.8.8</code></p></li><li><p><strong>Secondary DNS (IPv4):</strong> <code>8.8.4.4</code></p></li></ul><p>**<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.theknowledgeacademy.com/blog/dns-and-dhcp/">DHCP (Dynamic Host Configuration Protocol)</a>: DHCP **is a network management protocol to automatically asign IP addresses and other network configurations.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2046da9dd827064c8ab51c9b4523c87d12d744dbd2ab73d36e82f4535742a241.png" alt="In pi-hole you can manage DHCP as well!" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">In pi-hole you can manage DHCP as well!</figcaption></figure><p>The diagram bellow hope is clarrifing enough how it will work.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/62ee5d5e70749f6d563ee132d7d23f8f920548a05d6eb1a19ce4c2b44808684b.jpg" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-setting-up-your-raspberry-pi" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Setting Up Your Raspberry Pi</h3><p>For the setup, it’s advisable to use <em>Raspberry Pi OS Lite,</em> which is a minimal version of the Raspberry Pi operating system.</p><ol><li><p><strong>Install Raspberry Pi OS Lite</strong> and connect your Raspberry Pi to your router.</p></li></ol><p><strong>2 .Set a Static IP Address</strong>:</p><ul><li><p>SSH into your Raspberry Pi using the command: <code>ssh pi@&lt;your_pi_ip_address&gt;</code>.</p></li><li><p>Edit the DHCP configuration by running <code>sudo nano /etc/dhcpcd.conf</code>.</p></li><li><p>Set your desired static IP address, ensuring it’s within the range provided by your router’s DHCP settings.</p></li><li><p>Save the changes and reboot the Raspberry Pi using <code>sudo reboot</code>.</p></li></ul><p>When connecting on ethernet you wont know your IP address unless search it in router admin LAN devices. 👇</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3ba71d7bf2cc654c1f88ab4521194911f5a3afaa087d0d5d08bb557e4c82b1d5.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>The DHCP configurations better to enable just one as wlan0 is not needed in my case to not cause conflicts.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/47e2fd4152e694d90e90cef0d6dcff423aa35802679c69dba0de53be497f67a1.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-installing-pi-hole" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Installing Pi-Hole</h3><p>Installing Pi-Hole is straightforward. Simply run the following command in your terminal:</p><pre data-type="codeBlock" text="curl -sSL https://install.pi-hole.net | bash
"><code>curl <span class="hljs-operator">-</span>sSL https:<span class="hljs-comment">//install.pi-hole.net | bash</span>
</code></pre><p>The listed command will start the Pi-hole installatio script. Just follow screen prompts to complete the setup process. For a detailed walkthrough pick up the video listed <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=roYduABVjo8">here </a>at the 4:08 mark.</p><h4 id="h-important-note-on-dns-configuration" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Important Note on DNS Configuration</h4><p>After installing Pi-Hole, you may notice that your devices are not immediately routing traffic through it. This is because, by default, devices on your network continue to use the DNS server provided by your router, which is often your ISP’s DNS or a service like Google DNS.</p><p>Few things to consider:</p><ul><li><p><strong>Delayed Configuration</strong>: If your router’s DHCP is set to manual mode (meaning it’s not automatically updating DNS settings), your devices may take some time to start using Pi-Hole as their DNS server. This can be due to DHCP leases needing to expire and refresh with the new DNS settings.</p></li><li><p><strong>Manual DNS Setting</strong>: If you don’t want to wait, you can manually configure your devices to use the Pi-Hole as their DNS server. On Windows, for example, you can do this by going to your network settings and entering the IP address of your Raspberry Pi as the DNS server.</p></li></ul><p>Manual setup you can see being done bellow on Windows device same can be done on OS if patience is not your strong suite.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/97e5c267f18f11bb6c6f8ae2d3d977e8bb59ebdd3f5f547d005e493e69ef31ec.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h4 id="h-accessing-the-pi-hole-dashboard" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Accessing the Pi-Hole Dashboard</h4><p>Once everything is set up, you can access the Pi-Hole web interface to manage your network settings and view blocked requests.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://192.168.1.74/admin/">http://192.168.1.74/admin/</a></p><p>Raspberry PI while being small can be a powwerfull tool ranging from setting up <strong>NAS</strong> (Network-Attached Storage) , <strong>VPN</strong> or even delve into basic electronics projects. These are just a few of many ways to expand your knowledge of IoT (Internet of Things) with this versatile device.</p><p>With Pi-Hole running, you should see a significant reduction in ads across your network, and you’ll have greater control over your DNS settings — no need to rely on Google’s or Microsoft’s default configurations.</p>]]></content:encoded>
            <author>mozes721@newsletter.paragraph.com (Mozes721)</author>
        </item>
        <item>
            <title><![CDATA[Implementing JWT Authentication with Redis and Go]]></title>
            <link>https://paragraph.com/@mozes721/implementing-jwt-authentication-with-redis-and-go</link>
            <guid>3pnw3loWKAOxotaonR2x</guid>
            <pubDate>Fri, 05 Jul 2024 12:34:07 GMT</pubDate>
            <description><![CDATA[Redis is an in memory data structure store often used as a cache and message broker but can as well be used as a primary database. Redis is well suited for JWT authentication tokens due to Speed, Scalability, TTL(Time To Live), Session Storage. I will use own repository to showcase how have I used it and if you want to follow video format you can check out bellow YouTube videos. IntroductionIn JWT authentication like mine it makes sense if you have a primary database like PostgreSQL, Mongo or...]]></description>
            <content:encoded><![CDATA[<figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a1379615daf2c257877bb5bf54b22424a5377d9314d843dd6dd94d5539f1b8f0.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Redis is an in memory data structure store often used as a cache and message broker but can as well be used as a primary database.</p><p>Redis is well suited for JWT authentication tokens due to Speed, Scalability, TTL(Time To Live), Session Storage.</p><p>I will use own repository to showcase how have I used it and if you want to follow video format you can check out bellow <strong>YouTube</strong> videos.</p><div data-type="youtube" videoId="SQrsDZU_D5k">
      <div class="youtube-player" data-id="SQrsDZU_D5k" style="background-image: url('https://i.ytimg.com/vi/SQrsDZU_D5k/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=SQrsDZU_D5k">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><div data-type="youtube" videoId="NissLXyZ2Zw">
      <div class="youtube-player" data-id="NissLXyZ2Zw" style="background-image: url('https://i.ytimg.com/vi/NissLXyZ2Zw/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=NissLXyZ2Zw">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><h3 id="h-introduction" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Introduction</h3><p>In JWT authentication like mine it makes sense if you have a primary database like PostgreSQL, Mongo or Firebase(like in my example).</p><p>Be sure to run command</p><pre data-type="codeBlock" text="go get github.com/redis/go-redis/v9
"><code>go get github.com/redis<span class="hljs-operator">/</span>go<span class="hljs-operator">-</span>redis<span class="hljs-operator">/</span>v9
</code></pre><p>Ones installed figure out if you want to run Redis in a Docker Image or PaaS provider like Upstash👇</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://console.upstash.com/login">https://console.upstash.com/login</a></p><p>You can use Docker to run Redis.</p><blockquote><p>docker run — name recepie -p 6379:6379 -d redis:latest</p></blockquote><p>In a nutshell my frontend is with React but backend is Go with Gin Web Framework main database Firebase and Redis will save userID with AuthToken ones logged in from frontend.</p><h3 id="h-architecture-and-code" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Architecture &amp; Code</h3><p>Architecures change based on implementation This is how I have approached it to make it organized.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0cd43079a732738f7191515b5e2a67153540a6305d6733e5ada5976d326545c8.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><hr><h4 id="h-application-configuration" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Application Configuration</h4><p><strong>LoadConfigurations</strong>: Set up initial configurations, including connecting to Firebase and Redis.</p><pre data-type="codeBlock" text="func (a *Application) LoadConfigurations() error {
 ctx := context.Background()

 fireClient, err := GetFirestoreClient(ctx)
 if err != nil {
  return err
 }
 a.FireClient = fireClient

 fireAuth, err := GetAuthClient(ctx)
 if err != nil {
  return err
 }
 a.FireAuth = fireAuth

 // Redis env variable depending if PaaS server provided if not 6379 port used. 
 // So basically Docker image.
 a.RedisPort = envy.Get(&quot;REDIS_SERVER&quot;, &quot;localhost:6379&quot;)

 redisClient, err := RedisConnect(a.RedisPort)
 if err != nil {
  return err
 }

 a.RedisClient = redisClient

 a.ListenPort = envy.Get(&quot;PORT&quot;, &quot;8080&quot;)

 return nil
}
"><code>func (a <span class="hljs-operator">*</span>Application) LoadConfigurations() <span class="hljs-function"><span class="hljs-keyword">error</span> </span>{
 ctx :<span class="hljs-operator">=</span> context.Background()

 fireClient, err :<span class="hljs-operator">=</span> GetFirestoreClient(ctx)
 <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
  <span class="hljs-keyword">return</span> err
 }
 a.FireClient <span class="hljs-operator">=</span> fireClient

 fireAuth, err :<span class="hljs-operator">=</span> GetAuthClient(ctx)
 <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
  <span class="hljs-keyword">return</span> err
 }
 a.FireAuth <span class="hljs-operator">=</span> fireAuth

 <span class="hljs-comment">// Redis env variable depending if PaaS server provided if not 6379 port used. </span>
 <span class="hljs-comment">// So basically Docker image.</span>
 a.RedisPort <span class="hljs-operator">=</span> envy.Get(<span class="hljs-string">"REDIS_SERVER"</span>, <span class="hljs-string">"localhost:6379"</span>)

 redisClient, err :<span class="hljs-operator">=</span> RedisConnect(a.RedisPort)
 <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
  <span class="hljs-keyword">return</span> err
 }

 a.RedisClient <span class="hljs-operator">=</span> redisClient

 a.ListenPort <span class="hljs-operator">=</span> envy.Get(<span class="hljs-string">"PORT"</span>, <span class="hljs-string">"8080"</span>)

 <span class="hljs-keyword">return</span> nil
}
</code></pre><p><strong>RedisConnect Function</strong>: Connect to Redis, handling both Docker and PaaS setups</p><pre data-type="codeBlock" text="func redisClientPort(port string, envExists bool) (*redis.Client, error) {
    if envExists {
       opt, err := redis.ParseURL(port)
       if err != nil {
          return nil, fmt.Errorf(&quot;failed to parse Redis URL: %w&quot;, err)
       }
       return redis.NewClient(opt), nil
    }

    return redis.NewClient(&amp;redis.Options{
       Addr:     port,
       Password: &quot;&quot;,
       DB:       0,
    }), nil
}

func RedisConnect(port string) (*redis.Client, error) {
    _, ok := os.LookupEnv(port)
    client, err := redisClientPort(port, ok)
    if err != nil {
       return nil, fmt.Errorf(&quot;failed to ping Redis server: %w&quot;, err)
    }

    ping, err := client.Ping(context.Background()).Result()
    if err != nil {
       return nil, fmt.Errorf(&quot;failed to ping Redis server: %w&quot;, err)
    }

    fmt.Println(&quot;Ping response from Redis:&quot;, ping)
    return client, nil
}
"><code>func redisClientPort(port <span class="hljs-keyword">string</span>, envExists <span class="hljs-keyword">bool</span>) (<span class="hljs-operator">*</span>redis.Client, <span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
    <span class="hljs-keyword">if</span> envExists {
       opt, err :<span class="hljs-operator">=</span> redis.ParseURL(port)
       <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
          <span class="hljs-keyword">return</span> nil, fmt.Errorf(<span class="hljs-string">"failed to parse Redis URL: %w"</span>, err)
       }
       <span class="hljs-keyword">return</span> redis.NewClient(opt), nil
    }

    <span class="hljs-keyword">return</span> redis.NewClient(<span class="hljs-operator">&#x26;</span>redis.Options{
       Addr:     port,
       Password: <span class="hljs-string">""</span>,
       DB:       <span class="hljs-number">0</span>,
    }), nil
}

func RedisConnect(port <span class="hljs-keyword">string</span>) (<span class="hljs-operator">*</span>redis.Client, <span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
    <span class="hljs-keyword">_</span>, ok :<span class="hljs-operator">=</span> os.LookupEnv(port)
    client, err :<span class="hljs-operator">=</span> redisClientPort(port, ok)
    <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
       <span class="hljs-keyword">return</span> nil, fmt.Errorf(<span class="hljs-string">"failed to ping Redis server: %w"</span>, err)
    }

    ping, err :<span class="hljs-operator">=</span> client.Ping(context.Background()).Result()
    <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
       <span class="hljs-keyword">return</span> nil, fmt.Errorf(<span class="hljs-string">"failed to ping Redis server: %w"</span>, err)
    }

    fmt.Println(<span class="hljs-string">"Ping response from Redis:"</span>, ping)
    <span class="hljs-keyword">return</span> client, nil
}
</code></pre><p><strong>Start Function</strong>: Initialize the Gin router and set up routes and middleware.</p><pre data-type="codeBlock" text="func Start(a *app.Application) error {
    router := gin.New()

    router.Use(cors.New(md.CORSMiddleware()))

    api.SetCache(router, a.RedisClient)

    api.SetRoutes(router, a.FireClient, a.FireAuth, a.RedisClient)

    err := router.Run(&quot;:&quot; + a.ListenPort)
    if err != nil {
       return err
    }

    return nil
}
"><code>func Start(a <span class="hljs-operator">*</span>app.Application) <span class="hljs-function"><span class="hljs-keyword">error</span> </span>{
    router :<span class="hljs-operator">=</span> gin.New()

    router.Use(cors.New(md.CORSMiddleware()))

    api.SetCache(router, a.RedisClient)

    api.SetRoutes(router, a.FireClient, a.FireAuth, a.RedisClient)

    err :<span class="hljs-operator">=</span> router.Run(<span class="hljs-string">":"</span> <span class="hljs-operator">+</span> a.ListenPort)
    <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
       <span class="hljs-keyword">return</span> err
    }

    <span class="hljs-keyword">return</span> nil
}
</code></pre><p><strong>SetCache Function</strong>: Define endpoints for setting cache and other requests handled by <strong>Firebase</strong>.</p><pre data-type="codeBlock" text="// api/controller.go
func SetCache(router *gin.Engine, client *redis.Client) {
    router.POST(&quot;/set-cache&quot;, func(c *gin.Context) {
       setUserCache(c, client)
    })

    router.GET(&quot;/check-expiration&quot;, func(c *gin.Context) {
       checkTokenExpiration(c, client)
    })

}

func SetRoutes(router *gin.Engine, client *firestore.Client, auth *auth.Client, redisClient *redis.Client) {
    router.OPTIONS(&quot;/*any&quot;, func(c *gin.Context) {
       c.Status(http.StatusOK)
    })
    
    // In Gin Use means that it&apos;s required
    router.Use(func(c *gin.Context) {
       authToken := getUserCache(c, redisClient)
       md.AuthJWT(auth, authToken)(c)
    })

    router.GET(&quot;/&quot;, func(c *gin.Context) {
       showRecepies(c, client)
    })

    router.POST(&quot;/&quot;, func(c *gin.Context) {
       addRecepie(c, client)
    })
"><code><span class="hljs-comment">// api/controller.go</span>
func SetCache(router <span class="hljs-operator">*</span>gin.Engine, client <span class="hljs-operator">*</span>redis.Client) {
    router.POST(<span class="hljs-string">"/set-cache"</span>, func(c <span class="hljs-operator">*</span>gin.Context) {
       setUserCache(c, client)
    })

    router.GET(<span class="hljs-string">"/check-expiration"</span>, func(c <span class="hljs-operator">*</span>gin.Context) {
       checkTokenExpiration(c, client)
    })

}

func SetRoutes(router <span class="hljs-operator">*</span>gin.Engine, client <span class="hljs-operator">*</span>firestore.Client, auth <span class="hljs-operator">*</span>auth.Client, redisClient <span class="hljs-operator">*</span>redis.Client) {
    router.OPTIONS(<span class="hljs-string">"/*any"</span>, func(c <span class="hljs-operator">*</span>gin.Context) {
       c.Status(http.StatusOK)
    })
    
    <span class="hljs-comment">// In Gin Use means that it's required</span>
    router.Use(func(c <span class="hljs-operator">*</span>gin.Context) {
       authToken :<span class="hljs-operator">=</span> getUserCache(c, redisClient)
       md.AuthJWT(auth, authToken)(c)
    })

    router.GET(<span class="hljs-string">"/"</span>, func(c <span class="hljs-operator">*</span>gin.Context) {
       showRecepies(c, client)
    })

    router.POST(<span class="hljs-string">"/"</span>, func(c <span class="hljs-operator">*</span>gin.Context) {
       addRecepie(c, client)
    })
</code></pre><p>In SetRouters we do main requests to alter db data. <strong>AuthJWT</strong> is set by client side on <strong>Firebase</strong> to authenticate any request made to database.</p><p>AuthToken is what we will be talking about and it is passed in to AuthJWT to authenticate or deny user of any interaction.</p><hr><p>Next up is to set up main GET, SET actions including TTL for session management.</p><pre data-type="codeBlock" text="// models/cache.go
type UserCache struct {
    UserID    string `redis:&quot;UserID&quot;`
    AuthToken string `redis:&quot;AuthToken&quot;`
}
"><code><span class="hljs-comment">// models/cache.go</span>
<span class="hljs-keyword">type</span> UserCache <span class="hljs-keyword">struct</span> {
    UserID    <span class="hljs-type">string</span> <span class="hljs-string">`redis:"UserID"`</span>
    AuthToken <span class="hljs-type">string</span> <span class="hljs-string">`redis:"AuthToken"`</span>
}
</code></pre><p>The above struct is the only important one to parse incoming data from React. ☝️</p><h4 id="h-handling-cache-operations" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Handling Cache Operations</h4><p><strong>Get User Cache</strong>: Retrieve user cache from Redis.</p><pre data-type="codeBlock" text="// api/cache.go
func getUserCache(ctx *gin.Context, client *redis.Client) string {
    userID := ctx.Query(&quot;userID&quot;)
    authToken, err := models.GetUserCacheToken(ctx, client, userID)
    if err != nil {
       log.Printf(&quot;Issues retriving  Cached Token %v&quot;, err)
       return &quot;&quot;
    }

    return authToken
}

// models/cache.go
func GetUserCacheToken(ctx *gin.Context, client *redis.Client, userID string) (string, error) {
 key := fmt.Sprintf(&quot;user:%s&quot;, userID)
 cache, err := client.HGetAll(ctx, key).Result()
 if err != nil {
  return &quot;&quot;, fmt.Errorf(&quot;failed to get cache: %v&quot;, err)
 }

 authToken, ok := cache[&quot;AuthToken&quot;]
 if !ok {
  return &quot;&quot;, fmt.Errorf(&quot;AuthToken not found in cache&quot;)
 }

 return authToken, nil
}
"><code><span class="hljs-comment">// api/cache.go</span>
func getUserCache(ctx <span class="hljs-operator">*</span>gin.Context, client <span class="hljs-operator">*</span>redis.Client) <span class="hljs-keyword">string</span> {
    userID :<span class="hljs-operator">=</span> ctx.Query(<span class="hljs-string">"userID"</span>)
    authToken, err :<span class="hljs-operator">=</span> models.GetUserCacheToken(ctx, client, userID)
    <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
       log.Printf(<span class="hljs-string">"Issues retriving  Cached Token %v"</span>, err)
       <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>
    }

    <span class="hljs-keyword">return</span> authToken
}

<span class="hljs-comment">// models/cache.go</span>
func GetUserCacheToken(ctx <span class="hljs-operator">*</span>gin.Context, client <span class="hljs-operator">*</span>redis.Client, userID <span class="hljs-keyword">string</span>) (<span class="hljs-keyword">string</span>, <span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
 key :<span class="hljs-operator">=</span> fmt.Sprintf(<span class="hljs-string">"user:%s"</span>, userID)
 cache, err :<span class="hljs-operator">=</span> client.HGetAll(ctx, key).Result()
 <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
  <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>, fmt.Errorf(<span class="hljs-string">"failed to get cache: %v"</span>, err)
 }

 authToken, ok :<span class="hljs-operator">=</span> cache[<span class="hljs-string">"AuthToken"</span>]
 <span class="hljs-keyword">if</span> <span class="hljs-operator">!</span>ok {
  <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>, fmt.Errorf(<span class="hljs-string">"AuthToken not found in cache"</span>)
 }

 <span class="hljs-keyword">return</span> authToken, nil
}
</code></pre><p><strong>Set User Cache</strong>: Set user cache in Redis with TTL.</p><pre data-type="codeBlock" text="// api/cache.go
func setUserCache(ctx *gin.Context, client *redis.Client) {
    var userCache models.UserCache

    err := models.UnmarshallRequestBodyToAPIData(ctx.Request.Body, &amp;userCache)
    if err != nil {
       ctx.JSON(http.StatusBadRequest, gin.H{
          &quot;error&quot;: &quot;Unable to parse data&quot;,
       })
       return
    }

    key := fmt.Sprintf(&quot;user:%s&quot;, userCache.UserID)
    _, notExists := client.HGetAll(ctx, key).Result()

    if notExists == nil {
       userCache.SetCachedToken(ctx, client, key)
       return
    }

}

// models/cache.go

func (c *UserCache) SetCachedToken(ctx *gin.Context, client *redis.Client, key string) {
 fields := map[string]interface{}{
  &quot;UserID&quot;:    c.UserID,
  &quot;AuthToken&quot;: c.AuthToken,
 }
 err := client.HSet(ctx, key, fields).Err()
 if err != nil {
  log.Printf(&quot;Issues setting Cached Token %v&quot;, err)
 }

 client.Expire(ctx, key, 7*24*time.Hour)

}
"><code><span class="hljs-comment">// api/cache.go</span>
func setUserCache(ctx <span class="hljs-operator">*</span>gin.Context, client <span class="hljs-operator">*</span>redis.Client) {
    <span class="hljs-keyword">var</span> userCache models.UserCache

    err :<span class="hljs-operator">=</span> models.UnmarshallRequestBodyToAPIData(ctx.Request.Body, <span class="hljs-operator">&#x26;</span>userCache)
    <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
       ctx.JSON(http.StatusBadRequest, gin.H{
          <span class="hljs-string">"error"</span>: <span class="hljs-string">"Unable to parse data"</span>,
       })
       <span class="hljs-keyword">return</span>
    }

    key :<span class="hljs-operator">=</span> fmt.Sprintf(<span class="hljs-string">"user:%s"</span>, userCache.UserID)
    <span class="hljs-keyword">_</span>, notExists :<span class="hljs-operator">=</span> client.HGetAll(ctx, key).Result()

    <span class="hljs-keyword">if</span> notExists <span class="hljs-operator">=</span><span class="hljs-operator">=</span> nil {
       userCache.SetCachedToken(ctx, client, key)
       <span class="hljs-keyword">return</span>
    }

}

<span class="hljs-comment">// models/cache.go</span>

func (c <span class="hljs-operator">*</span>UserCache) SetCachedToken(ctx <span class="hljs-operator">*</span>gin.Context, client <span class="hljs-operator">*</span>redis.Client, key <span class="hljs-keyword">string</span>) {
 fields :<span class="hljs-operator">=</span> map[<span class="hljs-keyword">string</span>]<span class="hljs-class"><span class="hljs-keyword">interface</span></span>{}{
  <span class="hljs-string">"UserID"</span>:    c.UserID,
  <span class="hljs-string">"AuthToken"</span>: c.AuthToken,
 }
 err :<span class="hljs-operator">=</span> client.HSet(ctx, key, fields).Err()
 <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
  log.Printf(<span class="hljs-string">"Issues setting Cached Token %v"</span>, err)
 }

 client.Expire(ctx, key, <span class="hljs-number">7</span><span class="hljs-operator">*</span><span class="hljs-number">24</span><span class="hljs-operator">*</span>time.Hour)

}
</code></pre><blockquote><p>If you are interested in React section let me know otherwise Github repo will be listed bellow.</p></blockquote><blockquote><p>As on React login through Firebase it creates a user with authToken and passes to Go backend if exists ignore otherwise create.</p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a1e9cd5ed1874354bb942db528d2adcd6bfcf99aee63b05b8aa44877078afef8.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h4 id="h-check-token-expiration" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Check Token Expiration</h4><p><strong>Check Token Expiration</strong>: Check if the token has expired.</p><pre data-type="codeBlock" text="
// api/cache.go
func checkTokenExpiration(ctx *gin.Context, client *redis.Client) {
    userID := ctx.Query(&quot;userID&quot;)
    key := fmt.Sprintf(&quot;user:%s&quot;, userID)

    ttl, err := client.TTL(ctx, key).Result()
    if err != nil {
       ctx.JSON(http.StatusInternalServerError, gin.H{
          &quot;error&quot;: &quot;Failed to get TTL&quot;,
       })
       return
    }

    expired := ttl &lt;= 0

    ctx.JSON(http.StatusOK, expired)
}
"><code>
<span class="hljs-comment">// api/cache.go</span>
func checkTokenExpiration(ctx <span class="hljs-operator">*</span>gin.Context, client <span class="hljs-operator">*</span>redis.Client) {
    userID :<span class="hljs-operator">=</span> ctx.Query(<span class="hljs-string">"userID"</span>)
    key :<span class="hljs-operator">=</span> fmt.Sprintf(<span class="hljs-string">"user:%s"</span>, userID)

    ttl, err :<span class="hljs-operator">=</span> client.TTL(ctx, key).Result()
    <span class="hljs-keyword">if</span> err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
       ctx.JSON(http.StatusInternalServerError, gin.H{
          <span class="hljs-string">"error"</span>: <span class="hljs-string">"Failed to get TTL"</span>,
       })
       <span class="hljs-keyword">return</span>
    }

    expired :<span class="hljs-operator">=</span> ttl <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>

    ctx.JSON(http.StatusOK, expired)
}
</code></pre><h4 id="h-conclusion" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Conclusion</h4><p>This setup provides a robust structure for managing JWT authentication with Redis in a Go application, ensuring efficient session management and token validation. If there are any questions feel free to ask(or ask GPT) my repo you can find bellow.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Mozes721/RecipesApp">https://github.com/Mozes721/RecipesApp</a></p>]]></content:encoded>
            <author>mozes721@newsletter.paragraph.com (Mozes721)</author>
        </item>
        <item>
            <title><![CDATA[Meditation: A Modern Necessity]]></title>
            <link>https://paragraph.com/@mozes721/meditation-a-modern-necessity</link>
            <guid>73Nk6kPPCCb2L8WAM2ZV</guid>
            <pubDate>Sat, 22 Jun 2024 12:27:27 GMT</pubDate>
            <description><![CDATA[The thumbnail perfectly describes reason why meditation is crucial in our day in age. With the rapid advancements in AI and technology, thinking for ourselves can feel impossible as we are constantly bombarded with information and distractions. This is where meditation becomes crucial.I found myself in need of a mental reset.The Importance of Meditation TodayAs a developer and someone who works behind the screen more then 8h a day(95% of people here do I pressume) Meditation offered a quick, ...]]></description>
            <content:encoded><![CDATA[<figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/52f00b2e04fd6797a0aa40d1c8a758a5849748ec824245bb580543cb7e9f2408.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>The thumbnail perfectly describes reason why meditation is crucial in our day in age. With the rapid advancements in AI and technology, thinking for ourselves can feel impossible as we are constantly bombarded with information and distractions. This is where meditation becomes crucial.I found myself in need of a mental reset.</p><h2 id="h-the-importance-of-meditation-today" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The Importance of Meditation Today</h2><p>As a developer and someone who works behind the screen more then 8h a day(95% of people here do I pressume) Meditation offered a quick, effecive reset and clarity(even euphoria if done consistently).</p><p><strong>Stress reduction</strong>: In an 8-week study, a meditation style called &quot;mindfulness meditation&quot; reduced the inflammation response caused by stress</p><p><strong>Controls anxiety</strong>: Meditation can reduce stress levels, which translates to less anxiety as well help control job-releated anxiety(something needed in our day and age). FYI almost everyone now suffers from ADHD and it&apos;s not out of nowhere.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8cc7fbd9f3f563f16a439e2aea692230b3db5303b3ec608714d2afee9fb59dc0.jpg" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p><strong>Enhances self-awareness</strong>: Can help you develop a stronger understanding of yourself with how it is currently heading it is mitigated strongly.</p><p><strong>Lengthens attention span</strong>: Focused-attention meditation is like weight lifting for your attention span. It helps increase the strength and endurance of your attention.</p><p>Many more advantages but I will not get further into it for but more of can find here.</p><blockquote><p>To put it shortly connecting with yourself and not being influenced by external factors has been harder then ever and may link to depresion and anxiety. With regular meditation may it be 10 min can give a high level of euphoria and mindfullness.</p></blockquote><h2 id="h-how-to-meditate" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">How to Meditate</h2><p>It&apos;s not an overall cure but it can provide the mental space needed to listen to your inner self and resist external pressures. It&apos;s easy getting &quot;roped in&quot; by external factors(like raise your exepctations to unresonable amounts based on Instagram stories or YouTube or some course that sells you high success rate of completion).</p><hr><p>Taking time off for yourself will lead to greater productivity. Same as going to gym for physical health that will increase your mood and make you tackle professional chalanges at work etc so will having mental clarity and being mindfull. Appart from the obvious of getting into it 🧘‍♂️👇</p><ul><li><p><strong>Take a Seat</strong>: Find a comfortable place to sit.</p></li><li><p><strong>Set a Time Limit</strong>: Start with just 10 minutes.</p></li><li><p><strong>Notice Your Body</strong>: Make sure you&apos;re comfortable and stable.</p></li><li><p><strong>Feel Your Breath</strong>: Focus on your breathing.</p></li><li><p><strong>Notice When Your Mind Wanders</strong>: It&apos;s natural for your mind to wander. Simply bring it back to your breath.</p></li><li><p><strong>Be Kind to Your Wandering Mind</strong>: Don&apos;t judge yourself for getting distracted.</p></li><li><p><strong>Close with Kindness</strong>: End your session with a moment of gratitude or kindness.</p></li></ul><p>As a begginer guided meditation is what I would strongly recomend on <strong>YouTube</strong> bellow I added my favorite guide.</p><div data-type="youtube" videoId="GQ2blO8yATY">
      <div class="youtube-player" data-id="GQ2blO8yATY" style="background-image: url('https://i.ytimg.com/vi/GQ2blO8yATY/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=GQ2blO8yATY">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><p>Consistency is key so no reason to be hard on yourself if it wont go smoothly initially or you wonder off.</p><p>In the fast-paced world of IT, it&apos;s easy to feel overwhelmed and suffer from issues like ADHD and impatience.</p><p>Without clarity and self control it&apos;s difficult to continuously make good decisions without emotions taking over AI worsens it even if technology is superb.</p><p>Taking time for yourself through meditation can lead to greater productivity and a more balanced life. Give it a try and see the difference it can make.</p>]]></content:encoded>
            <author>mozes721@newsletter.paragraph.com (Mozes721)</author>
        </item>
        <item>
            <title><![CDATA[How to use Nodies for your Dapp]]></title>
            <link>https://paragraph.com/@mozes721/how-to-use-nodies-for-your-dapp</link>
            <guid>yVWU61l40cIb3wRHY1VL</guid>
            <pubDate>Mon, 03 Jun 2024 13:45:30 GMT</pubDate>
            <description><![CDATA[As Web3 becomes more streamlined and decentralized app development increases, the need for lightning-fast gateway providers to decentralized blockchain data also grows. Nodies addresses this need by offering efficient and reliable access to blockchain data.How does Nodies archive it?In a nutshell Nodies is part of an ongoing partnership with the Pocket Network Foundation more you can find here. It has implemented public RPC endpoints utilizing the Pocket Network&apos;s decentralized infrastru...]]></description>
            <content:encoded><![CDATA[<figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/13b7ea3a06c06354b00d69170b29f4919ccff2f21a31dfa6a1f2fb712ea64799.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>As Web3 becomes more streamlined and decentralized app development increases, the need for lightning-fast gateway providers to decentralized blockchain data also grows. Nodies addresses this need by offering efficient and reliable access to blockchain data.</p><h2 id="h-how-does-nodies-archive-it" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">How does Nodies archive it?</h2><p>In a nutshell Nodies is part of an ongoing partnership with the Pocket Network Foundation more you can find here. It has implemented public RPC endpoints utilizing the Pocket Network&apos;s decentralized infrastructure for relaying RPC requests.</p><blockquote><p>Remote Procedure Call (RPC): A protocol that enables one program to execute a procedure or service in another program on a different machine within a network. In Blockchain it facilitates communication and data exchange between nodes, clients, and servers in the blockchain network.</p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b311c1347b628b3b5c694de8591f93365e9b71a268b30a8165a79a781314ed26.avif" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-integrate-nodies-to-your-nextjs-dapp" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Integrate Nodies to your NextJS dapp</h2><p>As a quick setup will create a barebone wallet connect using &apos;wagmi&apos; package including RPC URL provided by Nodies.</p><p>Lets start creating bare 🦴 NextJs app with</p><p><code>npx create-next-app@latest</code></p><p>Then just follow the guide from Family ConnectKit docs here.</p><pre data-type="codeBlock" text="const config = createConfig(
  getDefaultConfig({
    chains: [mainnet, polygon, avalanche],
    transports: {
      [mainnet.id]: http(
        `https://lb.nodies.app/v1/5e9daed367d1454fab7c75f0ec8aceff`, //Add here!
      ),
    },

    walletConnectProjectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID as string,

    appName: &quot;Get started with Nodie powered by POKT&quot;,
    appDescription: &quot;Walllet Connect with Nodie&quot;,
    appUrl: &quot;https://family.co&quot;,
    appIcon: &quot;https://family.co/logo.png&quot;,
  }),
);
"><code><span class="hljs-selector-tag">const</span> <span class="hljs-selector-tag">config</span> = <span class="hljs-selector-tag">createConfig</span>(
  <span class="hljs-built_in">getDefaultConfig</span>({
    <span class="hljs-attribute">chains</span>: [mainnet, polygon, avalanche],
    <span class="hljs-attribute">transports</span>: {
      [mainnet.id]: <span class="hljs-built_in">http</span>(
        <span class="hljs-built_in">`https://lb.nodies.app/v1/5e9daed367d1454fab7c75f0ec8aceff`</span>, <span class="hljs-comment">//Add here!</span>
      ),
    },

    <span class="hljs-attribute">walletConnectProjectId</span>: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID as string,

    <span class="hljs-attribute">appName</span>: <span class="hljs-string">"Get started with Nodie powered by POKT"</span>,
    <span class="hljs-attribute">appDescription</span>: <span class="hljs-string">"Walllet Connect with Nodie"</span>,
    <span class="hljs-attribute">appUrl</span>: <span class="hljs-string">"https://family.co"</span>,
    <span class="hljs-attribute">appIcon</span>: <span class="hljs-string">"https://family.co/logo.png"</span>,
  }),
);
</code></pre><p>From <em>Web3Provider.tsx</em> example add your preffered networks like polygon, avalance etc and inside transport config pass in nodies HTTP link.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e8d6a4ed6e1c68fb2448cd781a4de5c984b2e596e4bb6102ecef8d8eec92df01.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>The site you can reach <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.nodies.app/">here</a> on the left side you just copy endpoint link and paste it. The right side is when you log in with Github can have added features like logs, statisitcs add API keys and even <em>Websockets</em> comming soon! 😉</p><blockquote><p>Note: Be sure to add your .env file and WalletConnect Project ID follow <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://cloud.walletconnect.com/sign-in">this </a>link to create an account and to generate projectId key.</p></blockquote><p>When all set and done with the short guide referenced above you should see something like this when connected.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9679ee532f41e1a2f8596bce4fd6da4e6702c948110970a67701c0dc9f8ec549.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>If you encountered issues with NextJS(I sure had) bellow I have attached dead simple repo including everything above(excluding .env duhhh)</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Mozes721/WalletConnect">https://github.com/Mozes721/WalletConnect</a></p><h3 id="h-honorable-mentions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Honorable Mentions</h3><p>If you want something even more flexible and additional features like utilizing your backend to your Dapp you can go up a notch using</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.grove.city/guides/getting-started/welcome-to-grove">https://docs.grove.city/guides/getting-started/welcome-to-grove</a></p><p>As a Go, Rust enthusiast it’s tough to ignore the added features at Groove as well powered by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://pokt.network">POKT</a> but have utilize added features when needed.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6ea60b4b0ad4e631f889267dd11f3ef8912c6db162bd48fec77d16ae64d52a4f.jpg" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>There are several free RPC endpoints available, which vary in accessibility, user experience (UX), and performance.</p><p>The setup was quite simple and intuitive, making it relatively easy to build on top of them. This is beneficial for web3, DePIN infrastructure, or any projects that involve working with blockchain data and creating API endpoints.</p><p>If you encounter issues or have any questions feel free to contact me dirrectly or ask in discord group <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.com/invite/pokt">here</a>.</p><p>For more on <strong>POKT Network</strong> you can check out bellow link. 👇</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://pokt.network/blog">https://pokt.network/blog</a></p>]]></content:encoded>
            <author>mozes721@newsletter.paragraph.com (Mozes721)</author>
        </item>
    </channel>
</rss>