avatarAnne Bonfert

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

5070

Abstract

do that:</p><div id="2e8b"><pre>eventHandler<span class="hljs-selector-class">.Handle</span>(event1, <span class="hljs-built_in">ExampleMiddlewareFoo</span>(<span class="hljs-built_in">ExampleMiddlewareBar</span>(handle)))</pre></div><h1 id="a8a5">Managing Events with Handlers and Middleware</h1><p id="f869">Most articles I read explain how to use this design pattern; this one deals with implementing the internal logic. So let's start coding.</p><p id="35c4">The full code for this article can be found <a href="https://github.com/xNok/slack-go-demo-socketmode/blob/main/examples/middleware/main.go">here</a> to help you follow along.</p><h2 id="0f88">Designing events</h2><p id="b622">First, we are going to enumerate the list of events that our system can handle. The way we create enumeration in Go is a bit different than in other programming languages. In Go, we are going to use a set of constants sharing the same <code>type</code>. Here I define a type <code>EventType</code>that represents a string with the event's name.</p><div id="b181"><pre>// <span class="hljs-keyword">type</span> <span class="hljs-type">used </span>to enumerate events <span class="hljs-keyword">type</span> <span class="hljs-type">EventType </span>string</pre></div><div id="4817"><pre>const ( event1 EventType <span class="hljs-operator">=</span> <span class="hljs-string">"event1"</span> event2 EventType <span class="hljs-operator">=</span> <span class="hljs-string">"event2"</span> )</pre></div><p id="e041">Next, we define the event itself. In our example, the<code>Event</code> as a type which can be selected among the list of <code>EventType</code> created above.</p><div id="2bc9"><pre><span class="hljs-keyword">type</span> <span class="hljs-type">Event</span> struct { <span class="hljs-type">Type</span> <span class="hljs-type">EventType</span> <span class="hljs-type">Data</span> interface{} }</pre></div><h2 id="df6c">Create an event sender (for test purpose)</h2><p id="60aa">To test our system, we will need to create a small function to send events every 2s. Each<code>Event</code> is transmitted via a <a href="https://tour.golang.org/concurrency/2">channel</a> and, the <code>eventSender</code> below sends a random <code>Event</code> of type <code>event1</code> or <code>event2</code> to a channel.</p><blockquote id="53f3"><p><i>Channels are a type which you can send and receive values, they are great for communication among goroutines. In other words, there are perfect for sending and receive event through your application.</i></p></blockquote><div id="ffd1"><pre><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">eventSender</span><span class="hljs-params">(c <span class="hljs-keyword">chan</span> EventType)</span></span> {</pre></div><div id="7f57"><pre> for { // Send <span class="hljs-selector-tag">a</span> random event <span class="hljs-selector-tag">to</span> the channel rand<span class="hljs-selector-class">.Seed</span>(<span class="hljs-selector-tag">time</span><span class="hljs-selector-class">.Now</span>()<span class="hljs-selector-class">.Unix</span>()) events := []EventType{ event1, event2, } n := rand.<span class="hljs-built_in">Int</span>() % <span class="hljs-built_in">len</span>(events)</pre></div><div id="6101"><pre> c <- events[n] <span class="hljs-comment">// send event to channel</span></pre></div><div id="5285"><pre> // <span class="hljs-keyword">wait</span> a <span class="hljs-built_in">bit</span> <span class="hljs-built_in">time</span>.Sleep(<span class="hljs-number">2</span> * <span class="hljs-built_in">time</span>.Second) } }</pre></div><h2 id="000c">Handler and dispatcher</h2><p id="e562">We first need a struct to hold the list of events we want to listen to and which function to call whenever that event is transmitted. This struct also contains the channel used for communicating events.</p><div id="280d"><pre><span class="hljs-comment">// Create a struct to hold config</span> <span class="hljs-comment">// And simplify dependency injections</span> <span class="hljs-keyword">type</span> EventHandler <span class="hljs-keyword">struct</span> { <span class="hljs-comment">// Event channel</span> Events <span class="hljs-keyword">chan</span> Event <span class="hljs-comment">// hold the registedred event functionss</span> EventMap <span class="hljs-keyword">map</span>[EventType][]<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(Event)</span></span> }</pre></div><p id="aa6c">Next, we need to provide an initializing constructor for our <code>EventHandler</code>.</p><div id="a4ed"><pre><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewEventHandler</span><span class="hljs-params">()</span></span> *EventHandler { eventMap := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[EventType][]<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(Event)</span></span>) event

Options

s := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> Event)</pre></div><div id="78bb"><pre> return <span class="hljs-variable">&</span>EventHandler<span class="hljs-punctuation">{</span> <span class="hljs-symbol"> Events:</span> events, <span class="hljs-symbol"> EventMap:</span> eventMap, <span class="hljs-punctuation">}</span> <span class="hljs-punctuation">}</span></pre></div><p id="98fe">Then, we can create our <code>Handle</code> function that associates the event with a callback function.</p><div id="308c"><pre><span class="hljs-comment">// register the handler function to handle an event type</span> func (h *EventHandler) <span class="hljs-built_in">Handle</span>(e EventType, f <span class="hljs-built_in">func</span>(Event)) { h<span class="hljs-selector-class">.EventMap</span><span class="hljs-selector-attr">[e]</span> = <span class="hljs-built_in">append</span>(h<span class="hljs-selector-class">.EventMap</span><span class="hljs-selector-attr">[e]</span>, f) }</pre></div><p id="e42a">Finally, we create the <code>EventDispatcher</code> function, the core of this mechanism. The <code>EventDispatcher</code>process any event sent to a channel, check its type, and if any function has been registering for that type, we call all registered functions.</p><div id="6597"><pre><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *EventHandler)</span></span> EventDispatcher() { <span class="hljs-keyword">for</span> evt := <span class="hljs-keyword">range</span> h.Events { log.Printf(<span class="hljs-string">"event recieved: %v"</span>, evt) <span class="hljs-keyword">if</span> handlers, ok := h.EventMap[evt.Type]; ok { <span class="hljs-comment">// If we registered an event</span> <span class="hljs-keyword">for</span> _, f := <span class="hljs-keyword">range</span> handlers { <span class="hljs-comment">// exacute function as goroutine</span> <span class="hljs-keyword">go</span> f(evt) } } } }</pre></div><h1 id="13e4">Using our system</h1><p id="4d4e">Everything is ready; we can start using our event handling system.</p><ol><li>Instantiate our event Handler</li><li>Register which event to listen to and what function to callback</li><li>Start the event sender</li><li>Start the event dispatcher</li></ol><div id="62ab"><pre><span class="hljs-keyword">func</span> <span class="hljs-title function_">main</span><span class="hljs-params">()</span> {</pre></div><div id="5b09"><pre> <span class="hljs-variable">eventHandler</span> := <span class="hljs-function"><span class="hljs-title">NewEventHandler</span>()</span></pre></div><div id="d244"><pre> eventHandler.Handle(event1, <span class="hljs-keyword">func</span><span class="hljs-params">()</span> { <span class="hljs-built_in">log</span>.Printf(<span class="hljs-string">"event Handled: %v"</span>, event1) })</pre></div><div id="5c56"><pre> <span class="hljs-variable">go</span> <span class="hljs-function"><span class="hljs-title">eventSender</span>(<span class="hljs-variable">eventHandler.Events</span>)</span></pre></div><div id="30f2"><pre> eventHandler<span class="hljs-selector-class">.EventDispatcher</span>()</pre></div><div id="9bf2"><pre>}</pre></div><p id="e590">The result should be along those lines:</p><figure id="5ee7"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*_D-GCRSu3K8CgTBXewJjJQ.gif"><figcaption></figcaption></figure><p id="19d6">Since we only handle an event of type <code>event1</code>, only <code>event1</code> shows as <code>Hansled</code>. All is good!</p><p id="d48a">The full code for this article can be found <a href="https://github.com/xNok/slack-go-demo-socketmode/blob/main/examples/middleware/main.go">here</a>.</p><h1 id="6f5e">Interesting Articles tackling the same topic</h1><ul><li><a href="https://drstearns.github.io/tutorials/gomiddleware/">Middleware Patterns in Go</a></li><li><a href="https://sathishvj.medium.com/web-handlers-and-middleware-in-golang-2706c2ecfb75">Web Handlers and Middleware in GoLang</a></li><li><a href="https://readmedium.com/lightweight-event-management-implemented-by-go-a654d59ac65">Lightweight event management implemented by Go</a></li><li><a href="https://readmedium.com/the-7-most-important-software-design-patterns-d60e546afb0e">The 7 Most Important Software Design Patterns</a></li></ul><p id="13e7"><i>Do you want <b>unlimited access</b> to all my content and many other writers’ content on Medium? Consider using my affiliate link to <a href="https://couedeloalexandre.medium.com/membership">become a Medium member today</a></i></p><h2 id="853a">Further reads</h2> <figure id="81d2"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://couedeloalexandre.medium.com/embed/list/3f9d03f2cb8f" allowfullscreen="" frameborder="0" height="184" width="undefined"> </div> </div> </figure></iframe></div></div></figure></article></body>

Hiking in the Snow

An adventure in the alps

Credit: Anne Bonfert

It was a lovely night in the mountains. Listening to the river flowing by our house I could fall asleep within seconds. But it was a cold night. Waking up the next morning with predictions of rain for the entire day we still head out.

The car stays behind. We walk to the bus station where a bus drives us to the village even higher up in the mountains. Then we switch the bus and drive the last half an hour on the tarred road up to the end of the valley. No other cars are allowed to drive here.

We’re the only ones on the bus. The driver isn’t very communicative. Yet he drops us off at the final destination with a recommendation where to go. We didn’t plan where to hike beforehand.

Credit: Anne Bonfert

Autumn meets winter

After yesterday’s snowfall, the valley is a white winter wonderland. Not entirely. In between the snow-covered trees, a few colorful areas are sticking out. Falls’ decoration.

Usually, the trees have lost all their leaves when the first snow arrives. But not this year. Most of the trees are still covered in yellow, brown, and orange shining leaves.

Since the temperatures are slowly rising the snow on the trees is melting. It sounds like it’s raining. Which is true. It is raining. But only from the treetops. It’s a mesmerizing sound. Drops of water falling onto a bed of colorful leaves on the forest floor.

Credit: Anne Bonfert

Morning mist

The fog is hanging low between the trees at the end of the valley. Slowly but surely we make our way through the forest. The trail is covered in snow and slippery.

Even though most of the peaks are still covered in clouds and morning mist the views we get are breathtaking. These snow-covered trees on rocky mountain slopes are unbelievable beautiful.

Slowly but surely the fog is lifting and offering us more and more breathtaking views. I switch between my GoPro and the DSLR camera to capture the most of it. But none of the pictures come close to it. Close to the real scenery.

Some things can’t be captured in a photograph. The smell. The sounds. And the feeling that goes through your body while embracing this magic moment.

Credit: Anne Bonfert

The views

We’re almost above the tree line and close to the mountain cabin. The clouds are disappearing showing some blue sky. Even the sun shines through to us. I can feel the sun rays and the reflection on the snow burning my face.

Behind every turn, I take a break. I take a break to embrace the moment. I want to inhale everything. The whole experience. Take a deep breath. Smile. And keep walking.

Credit: Anne Bonfert

Yellow leaves in the snow

An avenue of old maple trees stretches in front of us. Pieces of snow are dropping onto the trail. A bench covered in snow is decorated by a few leaves from the great maple tree.

It’s not a bench to take a rest on. It’s a bench to take a photograph from. Sometimes it’s not about taking a rest. It’s about seeing the places where you can slow down in life. And take that moment to see the beauty around you.

Like the shining yellow leaves lying in the snow. A rare moment. Yet a beautiful capture.

I walk bent over underneath the trees covering my camera from snow falling onto it. I decided against putting my camera back in the backpack. Too many views worth capturing. Too many objects worth turning into arts.

Credit: Anne Bonfert

The break

Just in front of the mountain cabin, a pony is digging in the snow looking for some eatable grass. It seems like this pony also got surprised by the change of weather. Or let’s say the change in his scenery.

We take off our backpacks and sit down for a moment. The terrace offers a great view. Lots of snow invites my mom to build a huge snowman which turns into an attraction as soon as other hikers reach the top.

We go inside for a good meal and some warmth. It is indeed very cold up here. And all the wetness surrounding us doesn’t help. Sitting opposite the fireplace we quickly warm up and choose a different route to go back down.

Credit: Anne Bonfert

Slushy mud

Hikers who came up this path called the “summer trail” did not recommend us taking it down. They said it is very muddy and slippery. Going up was alright but going down would be tricky.

We decide against their advice and start the hike through the slush. The parts where we walk in the forest the trail is soaked in water and covered in leaves. At some stretches, it felt like walking on a bed of leaves. Soft and relaxing.

The further down we get the muddier the trail becomes. Some trees fell over and we had to climb over or underneath them. The very last part of the trail goes down a field of grass. Or that is at least what I think it normally is. Right now it is just a beautiful mixture of snow and mud.

Water running down underneath the snow creating a soggy mud path. A slip-and-slide parkour begins. Luckily we all have our hiking sticks with us and get down without falling.

Credit: Anne Bonfert

Returning home

Eventually, we hit the tarred road again. Walking along the river in the valley we hike towards the mountain village. But before we get there the bus passes us which we force to slow down.

Instead of walking another hour on this boring road, we decide to catch a ride back. Our legs are burning, the shoes are brown and the body is tired. But it was a beautiful day.

Credit: Anne Bonfert

As we return to our holiday flat the sun is shining. Sitting on the terrace we let the day fade away. We catch the last sun rays and listen to the roaring sound of the mountain river.

“There is beauty to be found in the changing of the earth’s seasons, and in inner grace in honoring the cycles of life.” — Jack Kornfield

Nature
Travel
Outdoors
Travel Writing
Photography
Recommended from ReadMedium