buzzer game

This commit is contained in:
andrzej 2024-11-24 16:54:20 +01:00
parent eac5573121
commit 7fab5277e6
32 changed files with 1128 additions and 109 deletions

View File

@ -0,0 +1,140 @@
+++
date = '2024-11-24T15:23:50+01:00'
draft = true
title = 'Classroom Buzzer App'
tags = ["education","golang","websockets","concurrency"]
+++
## I started working on a new project today.
The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:
- provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds
- allow a teacher to assign groups and pairs in
- allow the teacher to dynamically reassign groups without repeating combinations
- implement a simple score-keeping functionality
- be able to run a 'buzzer' game
- have a clean, appealing, and user-friendly UI
A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student 'buzzes', state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.
Now I'm relatively new to both of these topics, but my project [GoPaper](https://projects.ajstepien.xyz/andrzej/gopaper) made use of concurrent goroutines to implement a wallpaper daemon, so I'll be building off that knowledge and developing the server side of this project in Go.
## WebSockets in Go
It is possible to build a websocket framework entirely from scratch in Go, but seeing as I don't hate myself *quite that much*, I'll be using the framework [Gorilla](https://github.com/gorilla/websocket).
## Getting started: running concurrent websocket connections
```go
package main
import (
"log"
"net/http"
"sync"
"github.com/gorilla/websocket"
)
type webSocketHandler struct {
upgrader websocket.Upgrader
}
// GLOBALS
var connections int = 0
var wg sync.WaitGroup
func (wsh webSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
//upgrade http connection to websocket
connection, err := wsh.upgrader.Upgrade(w, r, nil)
if err != nil {
log.Printf("Error while upgrading connection to websocket: %s", err)
return
}
connections++
log.Printf("New websocket connection. There are now %v\n", connections)
wg.Add(1)
go func() {
for {
//actually handle the websocket connection here
}
}()
}
func main() {
webSocketHandler := webSocketHandler{
upgrader: websocket.Upgrader{},
}
var port string = "8080"
http.Handle("/", webSocketHandler)
wg.Add(1)
log.Printf("listening on port %s...\n", port)
log.Fatal(http.ListenAndServe("localhost:8080", nil))
wg.Wait()
}
```
In this quick-and-dirty bit of code, we create a websocket handler that upgrades an http connection to a websocket connection, and then launches a goroutine. The goroutine doesn't do anything yet, but running ´websocat´ from multiple terminals shows us that we are now capable of handling multiple concurrent websocket connections 👍.
```bash
websocat ws://localhost:8080/
```
```
New websocket connection. There are now 1.
```
```
New websocket connection. There are now 2.
```
```
New websocket connection. There are now 3.
```
We know the connections have been made as either websocat or our Go app would error out otherwise. We should certainly do something to handle closed connections, as this code is a memory leak waiting to happen as things stand, but as a proof of concept, it works.
Now, time to actually do something with these connections! Let's add some logic to that goroutine.
```go
func (wsh webSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
//upgrade http connection to websocket
connection, err := wsh.upgrader.Upgrade(w, r, nil)
if err != nil {
log.Printf("Error while upgrading connection to websocket: %s", err)
return
}
connections++
log.Printf("New websocket connection. There are now %v\n", connections)
wg.Add(1)
go func() {
defer connection.Close()
for {
msgType, message, err := connection.ReadMessage()
if err != nil {
log.Printf("Error trying to read message from client: %s", err)
return
}
if msgType == websocket.BinaryMessage {
err = connection.WriteMessage(websocket.TextMessage, []byte("this server does not support binary messages"))
if err != nil {
log.Printf("Error trying to send message to client: %s", err)
}
return
}
log.Printf("received message from client: %s", message)
err = connection.WriteMessage(websocket.TextMessage, []byte("Message received!"))
}
}()
}
```
### Here's what we just added:
- The `defer` keyword closes the connection if/when the goroutine returns. In its current state, that would only happen in the case of an error.
- `connection.ReadMessage()` blocks until a message is received from the client
- If the client tries to send binary data, we bounce an error message back to the client, log an error on the server and return from the goroutine.
- If the message is text, we log it on the server and send a thank-you message back to the client. Testing this again with multiple instances of `websocat` shows that everything is working as it should. We have established two-way channels of communication between a server and multiple clients! 🥳
In my next post, I'll begin implementing the business logic.

View File

@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-us" dir="ltr"> <html lang="en-us" dir="ltr">
<head> <head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title> <title>
Categories | Coding with Andrzej Categories | Coding with Andrzej
</title> </title>
<link rel="alternate" type="application/rss+xml" href="http://devlog.ajstepien.xyz//index.xml" title="Coding with Andrzej"> <link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
@ -24,13 +24,13 @@
<script src="/js/main.23cd0c7d837263b9eaeb96ee2d9ccfa2969daa3fa00fa1c1fe8701a9b87251a1.js" integrity="sha256-I80MfYNyY7nq65buLZzPopadqj&#43;gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script> <script src="/js/main.js"></script>
</head> </head>
<body> <body>
<header> <header>
<a href=http://devlog.ajstepien.xyz/><h1>Coding with Andrzej</h1></a> <a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav> <nav>
<ul> <ul>

View File

@ -2,10 +2,10 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel> <channel>
<title>Categories on Coding with Andrzej</title> <title>Categories on Coding with Andrzej</title>
<link>http://devlog.ajstepien.xyz/categories/</link> <link>http://localhost:1313/categories/</link>
<description>Recent content in Categories on Coding with Andrzej</description> <description>Recent content in Categories on Coding with Andrzej</description>
<generator>Hugo</generator> <generator>Hugo</generator>
<language>en-us</language> <language>en-us</language>
<atom:link href="http://devlog.ajstepien.xyz/categories/index.xml" rel="self" type="application/rss+xml" /> <atom:link href="http://localhost:1313/categories/index.xml" rel="self" type="application/rss+xml" />
</channel> </channel>
</rss> </rss>

View File

@ -186,6 +186,10 @@ nav>ul {
gap: 2rem; gap: 2rem;
} }
nav>ul>li {
list-style-type: none;
}
nav>ul>li>a { nav>ul>li>a {
color: pink; color: pink;
font-size: 2rem; font-size: 2rem;
@ -199,7 +203,7 @@ nav>ul>li>a {
border-radius: 1rem; border-radius: 1rem;
margin-bottom: 1rem; margin-bottom: 1rem;
min-width: 24em; min-width: 24em;
; list-style-type: none;
} }
@ -208,6 +212,15 @@ nav>ul>li>a {
margin: auto; margin: auto;
} }
li {
list-style-type: '>';
padding: 0.6em;
}
li::marker {
color: var(--rp-pine);
}
/* TAGS */ /* TAGS */
.post-tags { .post-tags {
display: flex; display: flex;
@ -215,8 +228,6 @@ nav>ul>li>a {
} }
.post-tags>li { .post-tags>li {
@media screen and (min-width:600px) { @media screen and (min-width:600px) {
font-size: 3rem; font-size: 3rem;
} }
@ -224,4 +235,5 @@ nav>ul>li>a {
background-image: linear-gradient(to bottom, var(--rp-overlay) 80%, var(--rp-base)); background-image: linear-gradient(to bottom, var(--rp-overlay) 80%, var(--rp-base));
padding: 0.4em; padding: 0.4em;
border-radius: 0.6em 0.6em 0 0; border-radius: 0.6em 0.6em 0 0;
list-style-type: none;
} }

View File

@ -1,13 +1,13 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-us" dir="ltr"> <html lang="en-us" dir="ltr">
<head> <head>
<meta name="generator" content="Hugo 0.138.0"> <meta name="generator" content="Hugo 0.138.0"><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title> <title>
Coding with Andrzej Coding with Andrzej
</title> </title>
<link rel="alternate" type="application/rss+xml" href="http://devlog.ajstepien.xyz//index.xml" title="Coding with Andrzej"> <link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
@ -25,13 +25,13 @@
<script src="/js/main.23cd0c7d837263b9eaeb96ee2d9ccfa2969daa3fa00fa1c1fe8701a9b87251a1.js" integrity="sha256-I80MfYNyY7nq65buLZzPopadqj&#43;gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script> <script src="/js/main.js"></script>
</head> </head>
<body> <body>
<header> <header>
<a href=http://devlog.ajstepien.xyz/><h1>Coding with Andrzej</h1></a> <a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav> <nav>
<ul> <ul>
@ -55,10 +55,19 @@
<h1>Latest...</h1> <h1>Latest...</h1>
<h2><a href="/posts/cache-busting-2/">More cache-busting</a></h2> <h2><a href="/posts/buzzer-game/">Classroom Buzzer App</a></h2>
<p><strong>Well, that was easy.</strong></p> <h2 id="i-started-working-on-a-new-project-today">I started working on a new project today.</h2>
<p>At the end of <a href="cache-busting">my last post</a>, I had successfully written a script to stop stale CSS from getting stuck in the browser cache. It was a rough-and-ready solution &mdash; mine usually are &mdash; but it did the job. The one optimization I wanted to make was to ensure that the cache gets busted <em>only</em> when there is fresh CSS, as opposed to on every build. I had expected to get a nice long blog post out of this, but it turns out to be a very easy job.</p> <p>The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:</p>
<a href="/posts/cache-busting-2/">Read more...</a> <ul>
<li>provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds</li>
<li>allow a teacher to assign groups and pairs in</li>
<li>allow the teacher to dynamically reassign groups without repeating combinations</li>
<li>implement a simple score-keeping functionality</li>
<li>be able to run a &lsquo;buzzer&rsquo; game</li>
<li>have a clean, appealing, and user-friendly UI</li>
</ul>
<p>A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &lsquo;buzzes&rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.</p>
<a href="/posts/buzzer-game/">Read more...</a>
</main> </main>

View File

@ -2,31 +2,38 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel> <channel>
<title>Home on Coding with Andrzej</title> <title>Home on Coding with Andrzej</title>
<link>http://devlog.ajstepien.xyz/</link> <link>http://localhost:1313/</link>
<description>Recent content in Home on Coding with Andrzej</description> <description>Recent content in Home on Coding with Andrzej</description>
<generator>Hugo</generator> <generator>Hugo</generator>
<language>en-us</language> <language>en-us</language>
<lastBuildDate>Fri, 15 Nov 2024 22:33:10 +0100</lastBuildDate> <lastBuildDate>Sun, 24 Nov 2024 15:23:50 +0100</lastBuildDate>
<atom:link href="http://devlog.ajstepien.xyz/index.xml" rel="self" type="application/rss+xml" /> <atom:link href="http://localhost:1313/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Classroom Buzzer App</title>
<link>http://localhost:1313/posts/buzzer-game/</link>
<pubDate>Sun, 24 Nov 2024 15:23:50 +0100</pubDate>
<guid>http://localhost:1313/posts/buzzer-game/</guid>
<description>&lt;h2 id=&#34;i-started-working-on-a-new-project-today&#34;&gt;I started working on a new project today.&lt;/h2&gt;&#xA;&lt;p&gt;The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds&lt;/li&gt;&#xA;&lt;li&gt;allow a teacher to assign groups and pairs in&lt;/li&gt;&#xA;&lt;li&gt;allow the teacher to dynamically reassign groups without repeating combinations&lt;/li&gt;&#xA;&lt;li&gt;implement a simple score-keeping functionality&lt;/li&gt;&#xA;&lt;li&gt;be able to run a &amp;lsquo;buzzer&amp;rsquo; game&lt;/li&gt;&#xA;&lt;li&gt;have a clean, appealing, and user-friendly UI&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &amp;lsquo;buzzes&amp;rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.&lt;/p&gt;</description>
</item>
<item> <item>
<title>More cache-busting</title> <title>More cache-busting</title>
<link>http://devlog.ajstepien.xyz/posts/cache-busting-2/</link> <link>http://localhost:1313/posts/cache-busting-2/</link>
<pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate> <pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/cache-busting-2/</guid> <guid>http://localhost:1313/posts/cache-busting-2/</guid>
<description>&lt;p&gt;&lt;strong&gt;Well, that was easy.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;At the end of &lt;a href=&#34;cache-busting&#34;&gt;my last post&lt;/a&gt;, I had successfully written a script to stop stale CSS from getting stuck in the browser cache. It was a rough-and-ready solution &amp;mdash; mine usually are &amp;mdash; but it did the job. The one optimization I wanted to make was to ensure that the cache gets busted &lt;em&gt;only&lt;/em&gt; when there is fresh CSS, as opposed to on every build. I had expected to get a nice long blog post out of this, but it turns out to be a very easy job.&lt;/p&gt;</description> <description>&lt;p&gt;&lt;strong&gt;Well, that was easy.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;At the end of &lt;a href=&#34;cache-busting&#34;&gt;my last post&lt;/a&gt;, I had successfully written a script to stop stale CSS from getting stuck in the browser cache. It was a rough-and-ready solution &amp;mdash; mine usually are &amp;mdash; but it did the job. The one optimization I wanted to make was to ensure that the cache gets busted &lt;em&gt;only&lt;/em&gt; when there is fresh CSS, as opposed to on every build. I had expected to get a nice long blog post out of this, but it turns out to be a very easy job.&lt;/p&gt;</description>
</item> </item>
<item> <item>
<title>Invalidating the browser cache</title> <title>Invalidating the browser cache</title>
<link>http://devlog.ajstepien.xyz/posts/cache-busting/</link> <link>http://localhost:1313/posts/cache-busting/</link>
<pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate> <pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/cache-busting/</guid> <guid>http://localhost:1313/posts/cache-busting/</guid>
<description>&lt;p&gt;&lt;strong&gt;I had a bit of an issue with my &lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;website&lt;/a&gt; recently.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;I pushed some changes incorporating images for the first time (I know &amp;ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&amp;hellip; the images were not styled. Stranger still, they &lt;em&gt;were&lt;/em&gt; styled when I loaded the same page in Chrome.&lt;/p&gt;&#xA;&lt;p&gt;The experienced computer touchers amongst you will be saying &amp;ldquo;this is obviously a cache problem&amp;rdquo;, and you&amp;rsquo;re right, it is obviously a cache problem. Pressing &lt;code&gt;CTR + SHIFT + R&lt;/code&gt; (which forces Firefox to clear the cache and do a full reload) proved this thesis, and solved the immediate problem for me, on my machine. But what about other people&amp;rsquo;s machines? &lt;strong&gt;I needed to cache-bust.&lt;/strong&gt;&lt;/p&gt;</description> <description>&lt;p&gt;&lt;strong&gt;I had a bit of an issue with my &lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;website&lt;/a&gt; recently.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;I pushed some changes incorporating images for the first time (I know &amp;ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&amp;hellip; the images were not styled. Stranger still, they &lt;em&gt;were&lt;/em&gt; styled when I loaded the same page in Chrome.&lt;/p&gt;&#xA;&lt;p&gt;The experienced computer touchers amongst you will be saying &amp;ldquo;this is obviously a cache problem&amp;rdquo;, and you&amp;rsquo;re right, it is obviously a cache problem. Pressing &lt;code&gt;CTR + SHIFT + R&lt;/code&gt; (which forces Firefox to clear the cache and do a full reload) proved this thesis, and solved the immediate problem for me, on my machine. But what about other people&amp;rsquo;s machines? &lt;strong&gt;I needed to cache-bust.&lt;/strong&gt;&lt;/p&gt;</description>
</item> </item>
<item> <item>
<title>Permissions strike again</title> <title>Permissions strike again</title>
<link>http://devlog.ajstepien.xyz/posts/permissions-strike-again/</link> <link>http://localhost:1313/posts/permissions-strike-again/</link>
<pubDate>Wed, 13 Nov 2024 11:53:13 +0100</pubDate> <pubDate>Wed, 13 Nov 2024 11:53:13 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/permissions-strike-again/</guid> <guid>http://localhost:1313/posts/permissions-strike-again/</guid>
<description>&lt;p&gt;Configuring Apache really isn&amp;rsquo;t rocket science. There are a wealth of great tutorials online, the documentation is very well documented, and the defaults work more or less out of the box. But it&amp;rsquo;s one of those jobs that I do just infrequently enough that I always forget things in the interim, and end up making the same old mistakes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;strong&gt;And it almost always has to do with permissions.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;So, I&amp;rsquo;m writing this post both as a means of christening this devlog (&lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;Hi! I&amp;rsquo;m Andrzej! Hire me!&lt;/a&gt;) and also as a reminder to myself that &lt;em&gt;the home folder is not executable by default.&lt;/em&gt;&lt;/p&gt;</description> <description>&lt;p&gt;Configuring Apache really isn&amp;rsquo;t rocket science. There are a wealth of great tutorials online, the documentation is very well documented, and the defaults work more or less out of the box. But it&amp;rsquo;s one of those jobs that I do just infrequently enough that I always forget things in the interim, and end up making the same old mistakes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;strong&gt;And it almost always has to do with permissions.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;So, I&amp;rsquo;m writing this post both as a means of christening this devlog (&lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;Hi! I&amp;rsquo;m Andrzej! Hire me!&lt;/a&gt;) and also as a reminder to myself that &lt;em&gt;the home folder is not executable by default.&lt;/em&gt;&lt;/p&gt;</description>
</item> </item>
</channel> </channel>

View File

@ -0,0 +1,181 @@
<!DOCTYPE html>
<html lang="en-us" dir="ltr">
<head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>
Classroom Buzzer App | Coding with Andrzej
</title>
<link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
<link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/syntax.css" />
<link rel="stylesheet" href="/css/defaults.css" />
<script src="/js/main.js"></script>
</head>
<body>
<header>
<a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a aria-current="true" class="ancestor" href="/posts/">Posts</a>
</li>
<li>
<a href="/tags/">Tags</a>
</li>
</ul>
</nav>
</header>
<main>
<h1>Classroom Buzzer App</h1>
<time datetime="2024-11-24T15:23:50&#43;01:00">November 24, 2024</time>
<h2 id="i-started-working-on-a-new-project-today">I started working on a new project today.</h2>
<p>The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:</p>
<ul>
<li>provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds</li>
<li>allow a teacher to assign groups and pairs in</li>
<li>allow the teacher to dynamically reassign groups without repeating combinations</li>
<li>implement a simple score-keeping functionality</li>
<li>be able to run a &lsquo;buzzer&rsquo; game</li>
<li>have a clean, appealing, and user-friendly UI</li>
</ul>
<p>A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &lsquo;buzzes&rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.</p>
<p>Now I&rsquo;m relatively new to both of these topics, but my project <a href="https://projects.ajstepien.xyz/andrzej/gopaper">GoPaper</a> made use of concurrent goroutines to implement a wallpaper daemon, so I&rsquo;ll be building off that knowledge and developing the server side of this project in Go.</p>
<h2 id="websockets-in-go">WebSockets in Go</h2>
<p>It is possible to build a websocket framework entirely from scratch in Go, but seeing as I don&rsquo;t hate myself <em>quite that much</em>, I&rsquo;ll be using the framework <a href="https://github.com/gorilla/websocket">Gorilla</a>.</p>
<h2 id="getting-started-running-concurrent-websocket-connections">Getting started: running concurrent websocket connections</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">&#34;log&#34;</span>
</span></span><span class="line"><span class="cl"> <span class="s">&#34;net/http&#34;</span>
</span></span><span class="line"><span class="cl"> <span class="s">&#34;sync&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">&#34;github.com/gorilla/websocket&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">webSocketHandler</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">upgrader</span> <span class="nx">websocket</span><span class="p">.</span><span class="nx">Upgrader</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// GLOBALS
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">connections</span> <span class="kt">int</span> <span class="p">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">wg</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">wsh</span> <span class="nx">webSocketHandler</span><span class="p">)</span> <span class="nf">ServeHTTP</span><span class="p">(</span><span class="nx">w</span> <span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="nx">r</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">//upgrade http connection to websocket
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">connection</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">wsh</span><span class="p">.</span><span class="nx">upgrader</span><span class="p">.</span><span class="nf">Upgrade</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span> <span class="nx">r</span><span class="p">,</span> <span class="kc">nil</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;Error while upgrading connection to websocket: %s&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">connections</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;New websocket connection. There are now %v\n&#34;</span><span class="p">,</span> <span class="nx">connections</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">//actually handle the websocket connection here
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">webSocketHandler</span> <span class="o">:=</span> <span class="nx">webSocketHandler</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">upgrader</span><span class="p">:</span> <span class="nx">websocket</span><span class="p">.</span><span class="nx">Upgrader</span><span class="p">{},</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">port</span> <span class="kt">string</span> <span class="p">=</span> <span class="s">&#34;8080&#34;</span>
</span></span><span class="line"><span class="cl"> <span class="nx">http</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="s">&#34;/&#34;</span><span class="p">,</span> <span class="nx">webSocketHandler</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;listening on port %s...\n&#34;</span><span class="p">,</span> <span class="nx">port</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nf">ListenAndServe</span><span class="p">(</span><span class="s">&#34;localhost:8080&#34;</span><span class="p">,</span> <span class="kc">nil</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Wait</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>In this quick-and-dirty bit of code, we create a websocket handler that upgrades an http connection to a websocket connection, and then launches a goroutine. The goroutine doesn&rsquo;t do anything yet, but running ´websocat´ from multiple terminals shows us that we are now capable of handling multiple concurrent websocket connections 👍.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">websocat ws://localhost:8080/
</span></span></code></pre></div><pre tabindex="0"><code>New websocket connection. There are now 1.
</code></pre><pre tabindex="0"><code>New websocket connection. There are now 2.
</code></pre><pre tabindex="0"><code>New websocket connection. There are now 3.
</code></pre><p>We know the connections have been made as either websocat or our Go app would error out otherwise. We should certainly do something to handle closed connections, as this code is a memory leak waiting to happen as things stand, but as a proof of concept, it works.</p>
<p>Now, time to actually do something with these connections! Let&rsquo;s add some logic to that goroutine.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">wsh</span> <span class="nx">webSocketHandler</span><span class="p">)</span> <span class="nf">ServeHTTP</span><span class="p">(</span><span class="nx">w</span> <span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="nx">r</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">//upgrade http connection to websocket
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">connection</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">wsh</span><span class="p">.</span><span class="nx">upgrader</span><span class="p">.</span><span class="nf">Upgrade</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span> <span class="nx">r</span><span class="p">,</span> <span class="kc">nil</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;Error while upgrading connection to websocket: %s&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">connections</span><span class="o">++</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;New websocket connection. There are now %v\n&#34;</span><span class="p">,</span> <span class="nx">connections</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="nx">connection</span><span class="p">.</span><span class="nf">Close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">msgType</span><span class="p">,</span> <span class="nx">message</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">connection</span><span class="p">.</span><span class="nf">ReadMessage</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;Error trying to read message from client: %s&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">msgType</span> <span class="o">==</span> <span class="nx">websocket</span><span class="p">.</span><span class="nx">BinaryMessage</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="p">=</span> <span class="nx">connection</span><span class="p">.</span><span class="nf">WriteMessage</span><span class="p">(</span><span class="nx">websocket</span><span class="p">.</span><span class="nx">TextMessage</span><span class="p">,</span> <span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&#34;this server does not support binary messages&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;Error trying to send message to client: %s&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;received message from client: %s&#34;</span><span class="p">,</span> <span class="nx">message</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="p">=</span> <span class="nx">connection</span><span class="p">.</span><span class="nf">WriteMessage</span><span class="p">(</span><span class="nx">websocket</span><span class="p">.</span><span class="nx">TextMessage</span><span class="p">,</span> <span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&#34;Message received!&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="heres-what-we-just-added">Here&rsquo;s what we just added:</h3>
<ul>
<li>The <code>defer</code> keyword closes the connection if/when the goroutine returns. In its current state, that would only happen in the case of an error.</li>
<li><code>connection.ReadMessage()</code> blocks until a message is received from the client</li>
<li>If the client tries to send binary data, we bounce an error message back to the client, log an error on the server and return from the goroutine.</li>
<li>If the message is text, we log it on the server and send a thank-you message back to the client. Testing this again with multiple instances of <code>websocat</code> shows that everything is working as it should. We have established two-way channels of communication between a server and multiple clients! 🥳</li>
</ul>
<p>In my next post, I&rsquo;ll begin implementing the business logic.</p>
<div>
<div>Tags:</div>
<ul class="post-tags">
<li><a href="/tags/education/">Education</a></li>
<li><a href="/tags/golang/">Golang</a></li>
<li><a href="/tags/websockets/">Websockets</a></li>
<li><a href="/tags/concurrency/">Concurrency</a></li>
</ul>
</div>
</main>
<footer>
<p>Copyright 2024. All rights reserved.</p>
</footer>
</body>
</html>

View File

@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-us" dir="ltr"> <html lang="en-us" dir="ltr">
<head> <head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title> <title>
More cache-busting | Coding with Andrzej More cache-busting | Coding with Andrzej
</title> </title>
<link rel="alternate" type="application/rss+xml" href="http://devlog.ajstepien.xyz//index.xml" title="Coding with Andrzej"> <link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
@ -24,13 +24,13 @@
<script src="/js/main.23cd0c7d837263b9eaeb96ee2d9ccfa2969daa3fa00fa1c1fe8701a9b87251a1.js" integrity="sha256-I80MfYNyY7nq65buLZzPopadqj&#43;gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script> <script src="/js/main.js"></script>
</head> </head>
<body> <body>
<header> <header>
<a href=http://devlog.ajstepien.xyz/><h1>Coding with Andrzej</h1></a> <a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav> <nav>
<ul> <ul>

View File

@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-us" dir="ltr"> <html lang="en-us" dir="ltr">
<head> <head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title> <title>
Invalidating the browser cache | Coding with Andrzej Invalidating the browser cache | Coding with Andrzej
</title> </title>
<link rel="alternate" type="application/rss+xml" href="http://devlog.ajstepien.xyz//index.xml" title="Coding with Andrzej"> <link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
@ -24,13 +24,13 @@
<script src="/js/main.23cd0c7d837263b9eaeb96ee2d9ccfa2969daa3fa00fa1c1fe8701a9b87251a1.js" integrity="sha256-I80MfYNyY7nq65buLZzPopadqj&#43;gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script> <script src="/js/main.js"></script>
</head> </head>
<body> <body>
<header> <header>
<a href=http://devlog.ajstepien.xyz/><h1>Coding with Andrzej</h1></a> <a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav> <nav>
<ul> <ul>

View File

@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-us" dir="ltr"> <html lang="en-us" dir="ltr">
<head> <head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title> <title>
Posts | Coding with Andrzej Posts | Coding with Andrzej
</title> </title>
<link rel="alternate" type="application/rss+xml" href="http://devlog.ajstepien.xyz//index.xml" title="Coding with Andrzej"> <link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
@ -24,13 +24,13 @@
<script src="/js/main.23cd0c7d837263b9eaeb96ee2d9ccfa2969daa3fa00fa1c1fe8701a9b87251a1.js" integrity="sha256-I80MfYNyY7nq65buLZzPopadqj&#43;gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script> <script src="/js/main.js"></script>
</head> </head>
<body> <body>
<header> <header>
<a href=http://devlog.ajstepien.xyz/><h1>Coding with Andrzej</h1></a> <a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav> <nav>
<ul> <ul>
@ -58,6 +58,28 @@
<ul class="page-list"> <ul class="page-list">
<li>
<h2 class="center"><a href="/posts/buzzer-game/">Classroom Buzzer App</a></h2>
<time datetime="2024-11-24T15:23:50&#43;01:00">November 24, 2024</time>
<h2 id="i-started-working-on-a-new-project-today">I started working on a new project today.</h2>
<p>The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:</p>
<ul>
<li>provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds</li>
<li>allow a teacher to assign groups and pairs in</li>
<li>allow the teacher to dynamically reassign groups without repeating combinations</li>
<li>implement a simple score-keeping functionality</li>
<li>be able to run a &lsquo;buzzer&rsquo; game</li>
<li>have a clean, appealing, and user-friendly UI</li>
</ul>
<p>A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &lsquo;buzzes&rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.</p>
<a href="/posts/buzzer-game/">Read more...</a>
</li>
<li> <li>
<h2 class="center"><a href="/posts/cache-busting-2/">More cache-busting</a></h2> <h2 class="center"><a href="/posts/cache-busting-2/">More cache-busting</a></h2>

View File

@ -2,31 +2,38 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel> <channel>
<title>Posts on Coding with Andrzej</title> <title>Posts on Coding with Andrzej</title>
<link>http://devlog.ajstepien.xyz/posts/</link> <link>http://localhost:1313/posts/</link>
<description>Recent content in Posts on Coding with Andrzej</description> <description>Recent content in Posts on Coding with Andrzej</description>
<generator>Hugo</generator> <generator>Hugo</generator>
<language>en-us</language> <language>en-us</language>
<lastBuildDate>Fri, 15 Nov 2024 22:33:10 +0100</lastBuildDate> <lastBuildDate>Sun, 24 Nov 2024 15:23:50 +0100</lastBuildDate>
<atom:link href="http://devlog.ajstepien.xyz/posts/index.xml" rel="self" type="application/rss+xml" /> <atom:link href="http://localhost:1313/posts/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Classroom Buzzer App</title>
<link>http://localhost:1313/posts/buzzer-game/</link>
<pubDate>Sun, 24 Nov 2024 15:23:50 +0100</pubDate>
<guid>http://localhost:1313/posts/buzzer-game/</guid>
<description>&lt;h2 id=&#34;i-started-working-on-a-new-project-today&#34;&gt;I started working on a new project today.&lt;/h2&gt;&#xA;&lt;p&gt;The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds&lt;/li&gt;&#xA;&lt;li&gt;allow a teacher to assign groups and pairs in&lt;/li&gt;&#xA;&lt;li&gt;allow the teacher to dynamically reassign groups without repeating combinations&lt;/li&gt;&#xA;&lt;li&gt;implement a simple score-keeping functionality&lt;/li&gt;&#xA;&lt;li&gt;be able to run a &amp;lsquo;buzzer&amp;rsquo; game&lt;/li&gt;&#xA;&lt;li&gt;have a clean, appealing, and user-friendly UI&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &amp;lsquo;buzzes&amp;rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.&lt;/p&gt;</description>
</item>
<item> <item>
<title>More cache-busting</title> <title>More cache-busting</title>
<link>http://devlog.ajstepien.xyz/posts/cache-busting-2/</link> <link>http://localhost:1313/posts/cache-busting-2/</link>
<pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate> <pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/cache-busting-2/</guid> <guid>http://localhost:1313/posts/cache-busting-2/</guid>
<description>&lt;p&gt;&lt;strong&gt;Well, that was easy.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;At the end of &lt;a href=&#34;cache-busting&#34;&gt;my last post&lt;/a&gt;, I had successfully written a script to stop stale CSS from getting stuck in the browser cache. It was a rough-and-ready solution &amp;mdash; mine usually are &amp;mdash; but it did the job. The one optimization I wanted to make was to ensure that the cache gets busted &lt;em&gt;only&lt;/em&gt; when there is fresh CSS, as opposed to on every build. I had expected to get a nice long blog post out of this, but it turns out to be a very easy job.&lt;/p&gt;</description> <description>&lt;p&gt;&lt;strong&gt;Well, that was easy.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;At the end of &lt;a href=&#34;cache-busting&#34;&gt;my last post&lt;/a&gt;, I had successfully written a script to stop stale CSS from getting stuck in the browser cache. It was a rough-and-ready solution &amp;mdash; mine usually are &amp;mdash; but it did the job. The one optimization I wanted to make was to ensure that the cache gets busted &lt;em&gt;only&lt;/em&gt; when there is fresh CSS, as opposed to on every build. I had expected to get a nice long blog post out of this, but it turns out to be a very easy job.&lt;/p&gt;</description>
</item> </item>
<item> <item>
<title>Invalidating the browser cache</title> <title>Invalidating the browser cache</title>
<link>http://devlog.ajstepien.xyz/posts/cache-busting/</link> <link>http://localhost:1313/posts/cache-busting/</link>
<pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate> <pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/cache-busting/</guid> <guid>http://localhost:1313/posts/cache-busting/</guid>
<description>&lt;p&gt;&lt;strong&gt;I had a bit of an issue with my &lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;website&lt;/a&gt; recently.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;I pushed some changes incorporating images for the first time (I know &amp;ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&amp;hellip; the images were not styled. Stranger still, they &lt;em&gt;were&lt;/em&gt; styled when I loaded the same page in Chrome.&lt;/p&gt;&#xA;&lt;p&gt;The experienced computer touchers amongst you will be saying &amp;ldquo;this is obviously a cache problem&amp;rdquo;, and you&amp;rsquo;re right, it is obviously a cache problem. Pressing &lt;code&gt;CTR + SHIFT + R&lt;/code&gt; (which forces Firefox to clear the cache and do a full reload) proved this thesis, and solved the immediate problem for me, on my machine. But what about other people&amp;rsquo;s machines? &lt;strong&gt;I needed to cache-bust.&lt;/strong&gt;&lt;/p&gt;</description> <description>&lt;p&gt;&lt;strong&gt;I had a bit of an issue with my &lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;website&lt;/a&gt; recently.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;I pushed some changes incorporating images for the first time (I know &amp;ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&amp;hellip; the images were not styled. Stranger still, they &lt;em&gt;were&lt;/em&gt; styled when I loaded the same page in Chrome.&lt;/p&gt;&#xA;&lt;p&gt;The experienced computer touchers amongst you will be saying &amp;ldquo;this is obviously a cache problem&amp;rdquo;, and you&amp;rsquo;re right, it is obviously a cache problem. Pressing &lt;code&gt;CTR + SHIFT + R&lt;/code&gt; (which forces Firefox to clear the cache and do a full reload) proved this thesis, and solved the immediate problem for me, on my machine. But what about other people&amp;rsquo;s machines? &lt;strong&gt;I needed to cache-bust.&lt;/strong&gt;&lt;/p&gt;</description>
</item> </item>
<item> <item>
<title>Permissions strike again</title> <title>Permissions strike again</title>
<link>http://devlog.ajstepien.xyz/posts/permissions-strike-again/</link> <link>http://localhost:1313/posts/permissions-strike-again/</link>
<pubDate>Wed, 13 Nov 2024 11:53:13 +0100</pubDate> <pubDate>Wed, 13 Nov 2024 11:53:13 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/permissions-strike-again/</guid> <guid>http://localhost:1313/posts/permissions-strike-again/</guid>
<description>&lt;p&gt;Configuring Apache really isn&amp;rsquo;t rocket science. There are a wealth of great tutorials online, the documentation is very well documented, and the defaults work more or less out of the box. But it&amp;rsquo;s one of those jobs that I do just infrequently enough that I always forget things in the interim, and end up making the same old mistakes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;strong&gt;And it almost always has to do with permissions.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;So, I&amp;rsquo;m writing this post both as a means of christening this devlog (&lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;Hi! I&amp;rsquo;m Andrzej! Hire me!&lt;/a&gt;) and also as a reminder to myself that &lt;em&gt;the home folder is not executable by default.&lt;/em&gt;&lt;/p&gt;</description> <description>&lt;p&gt;Configuring Apache really isn&amp;rsquo;t rocket science. There are a wealth of great tutorials online, the documentation is very well documented, and the defaults work more or less out of the box. But it&amp;rsquo;s one of those jobs that I do just infrequently enough that I always forget things in the interim, and end up making the same old mistakes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;strong&gt;And it almost always has to do with permissions.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;So, I&amp;rsquo;m writing this post both as a means of christening this devlog (&lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;Hi! I&amp;rsquo;m Andrzej! Hire me!&lt;/a&gt;) and also as a reminder to myself that &lt;em&gt;the home folder is not executable by default.&lt;/em&gt;&lt;/p&gt;</description>
</item> </item>
</channel> </channel>

View File

@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-us" dir="ltr"> <html lang="en-us" dir="ltr">
<head> <head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title> <title>
Permissions strike again | Coding with Andrzej Permissions strike again | Coding with Andrzej
</title> </title>
<link rel="alternate" type="application/rss+xml" href="http://devlog.ajstepien.xyz//index.xml" title="Coding with Andrzej"> <link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
@ -24,13 +24,13 @@
<script src="/js/main.23cd0c7d837263b9eaeb96ee2d9ccfa2969daa3fa00fa1c1fe8701a9b87251a1.js" integrity="sha256-I80MfYNyY7nq65buLZzPopadqj&#43;gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script> <script src="/js/main.js"></script>
</head> </head>
<body> <body>
<header> <header>
<a href=http://devlog.ajstepien.xyz/><h1>Coding with Andrzej</h1></a> <a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav> <nav>
<ul> <ul>

View File

@ -2,33 +2,48 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml"> xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url> <url>
<loc>http://devlog.ajstepien.xyz/tags/css/</loc> <loc>http://localhost:1313/posts/buzzer-game/</loc>
<lastmod>2024-11-24T15:23:50+01:00</lastmod>
</url><url>
<loc>http://localhost:1313/tags/concurrency/</loc>
<lastmod>2024-11-24T15:23:50+01:00</lastmod>
</url><url>
<loc>http://localhost:1313/tags/education/</loc>
<lastmod>2024-11-24T15:23:50+01:00</lastmod>
</url><url>
<loc>http://localhost:1313/tags/golang/</loc>
<lastmod>2024-11-24T15:23:50+01:00</lastmod>
</url><url>
<loc>http://localhost:1313/tags/</loc>
<lastmod>2024-11-24T15:23:50+01:00</lastmod>
</url><url>
<loc>http://localhost:1313/tags/websockets/</loc>
<lastmod>2024-11-24T15:23:50+01:00</lastmod>
</url><url>
<loc>http://localhost:1313/tags/css/</loc>
<lastmod>2024-11-15T22:33:10+01:00</lastmod> <lastmod>2024-11-15T22:33:10+01:00</lastmod>
</url><url> </url><url>
<loc>http://devlog.ajstepien.xyz/tags/linux/</loc> <loc>http://localhost:1313/tags/linux/</loc>
<lastmod>2024-11-15T22:33:10+01:00</lastmod> <lastmod>2024-11-15T22:33:10+01:00</lastmod>
</url><url> </url><url>
<loc>http://devlog.ajstepien.xyz/posts/cache-busting-2/</loc> <loc>http://localhost:1313/posts/cache-busting-2/</loc>
<lastmod>2024-11-15T22:33:10+01:00</lastmod> <lastmod>2024-11-15T22:33:10+01:00</lastmod>
</url><url> </url><url>
<loc>http://devlog.ajstepien.xyz/tags/</loc> <loc>http://localhost:1313/tags/html/</loc>
<lastmod>2024-11-15T22:33:10+01:00</lastmod>
</url><url>
<loc>http://devlog.ajstepien.xyz/tags/html/</loc>
<lastmod>2024-11-14T14:24:21+01:00</lastmod> <lastmod>2024-11-14T14:24:21+01:00</lastmod>
</url><url> </url><url>
<loc>http://devlog.ajstepien.xyz/posts/cache-busting/</loc> <loc>http://localhost:1313/posts/cache-busting/</loc>
<lastmod>2024-11-14T14:24:21+01:00</lastmod> <lastmod>2024-11-14T14:24:21+01:00</lastmod>
</url><url> </url><url>
<loc>http://devlog.ajstepien.xyz/posts/permissions-strike-again/</loc> <loc>http://localhost:1313/posts/permissions-strike-again/</loc>
<lastmod>2024-11-13T11:53:13+01:00</lastmod> <lastmod>2024-11-13T11:53:13+01:00</lastmod>
</url><url> </url><url>
<loc>http://devlog.ajstepien.xyz/posts/</loc> <loc>http://localhost:1313/posts/</loc>
<lastmod>2023-01-01T08:30:00-07:00</lastmod> <lastmod>2023-01-01T08:30:00-07:00</lastmod>
</url><url> </url><url>
<loc>http://devlog.ajstepien.xyz/</loc> <loc>http://localhost:1313/</loc>
<lastmod>2023-01-01T08:00:00-07:00</lastmod> <lastmod>2023-01-01T08:00:00-07:00</lastmod>
</url><url> </url><url>
<loc>http://devlog.ajstepien.xyz/categories/</loc> <loc>http://localhost:1313/categories/</loc>
</url> </url>
</urlset> </urlset>

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="en-us" dir="ltr">
<head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>
Concurrency | Coding with Andrzej
</title>
<link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
<link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/syntax.css" />
<link rel="stylesheet" href="/css/defaults.css" />
<script src="/js/main.js"></script>
</head>
<body>
<header>
<a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/posts/">Posts</a>
</li>
<li>
<a href="/tags/">Tags</a>
</li>
</ul>
</nav>
</header>
<main>
<h1>Concurrency</h1>
<ul class="page-list">
<li>
<h2 class="center"><a href="/posts/buzzer-game/">Classroom Buzzer App</a></h2>
<time datetime="2024-11-24T15:23:50&#43;01:00">November 24, 2024</time>
<h2 id="i-started-working-on-a-new-project-today">I started working on a new project today.</h2>
<p>The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:</p>
<ul>
<li>provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds</li>
<li>allow a teacher to assign groups and pairs in</li>
<li>allow the teacher to dynamically reassign groups without repeating combinations</li>
<li>implement a simple score-keeping functionality</li>
<li>be able to run a &lsquo;buzzer&rsquo; game</li>
<li>have a clean, appealing, and user-friendly UI</li>
</ul>
<p>A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &lsquo;buzzes&rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.</p>
<a href="/posts/buzzer-game/">Read more...</a>
</li>
</ul>
</main>
<footer>
<p>Copyright 2024. All rights reserved.</p>
</footer>
</body>
</html>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Concurrency on Coding with Andrzej</title>
<link>http://localhost:1313/tags/concurrency/</link>
<description>Recent content in Concurrency on Coding with Andrzej</description>
<generator>Hugo</generator>
<language>en-us</language>
<lastBuildDate>Sun, 24 Nov 2024 15:23:50 +0100</lastBuildDate>
<atom:link href="http://localhost:1313/tags/concurrency/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Classroom Buzzer App</title>
<link>http://localhost:1313/posts/buzzer-game/</link>
<pubDate>Sun, 24 Nov 2024 15:23:50 +0100</pubDate>
<guid>http://localhost:1313/posts/buzzer-game/</guid>
<description>&lt;h2 id=&#34;i-started-working-on-a-new-project-today&#34;&gt;I started working on a new project today.&lt;/h2&gt;&#xA;&lt;p&gt;The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds&lt;/li&gt;&#xA;&lt;li&gt;allow a teacher to assign groups and pairs in&lt;/li&gt;&#xA;&lt;li&gt;allow the teacher to dynamically reassign groups without repeating combinations&lt;/li&gt;&#xA;&lt;li&gt;implement a simple score-keeping functionality&lt;/li&gt;&#xA;&lt;li&gt;be able to run a &amp;lsquo;buzzer&amp;rsquo; game&lt;/li&gt;&#xA;&lt;li&gt;have a clean, appealing, and user-friendly UI&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &amp;lsquo;buzzes&amp;rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.&lt;/p&gt;</description>
</item>
</channel>
</rss>

View File

@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-us" dir="ltr"> <html lang="en-us" dir="ltr">
<head> <head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title> <title>
CSS | Coding with Andrzej CSS | Coding with Andrzej
</title> </title>
<link rel="alternate" type="application/rss+xml" href="http://devlog.ajstepien.xyz//index.xml" title="Coding with Andrzej"> <link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
@ -24,13 +24,13 @@
<script src="/js/main.23cd0c7d837263b9eaeb96ee2d9ccfa2969daa3fa00fa1c1fe8701a9b87251a1.js" integrity="sha256-I80MfYNyY7nq65buLZzPopadqj&#43;gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script> <script src="/js/main.js"></script>
</head> </head>
<body> <body>
<header> <header>
<a href=http://devlog.ajstepien.xyz/><h1>Coding with Andrzej</h1></a> <a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav> <nav>
<ul> <ul>

View File

@ -2,24 +2,24 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel> <channel>
<title>CSS on Coding with Andrzej</title> <title>CSS on Coding with Andrzej</title>
<link>http://devlog.ajstepien.xyz/tags/css/</link> <link>http://localhost:1313/tags/css/</link>
<description>Recent content in CSS on Coding with Andrzej</description> <description>Recent content in CSS on Coding with Andrzej</description>
<generator>Hugo</generator> <generator>Hugo</generator>
<language>en-us</language> <language>en-us</language>
<lastBuildDate>Fri, 15 Nov 2024 22:33:10 +0100</lastBuildDate> <lastBuildDate>Fri, 15 Nov 2024 22:33:10 +0100</lastBuildDate>
<atom:link href="http://devlog.ajstepien.xyz/tags/css/index.xml" rel="self" type="application/rss+xml" /> <atom:link href="http://localhost:1313/tags/css/index.xml" rel="self" type="application/rss+xml" />
<item> <item>
<title>More cache-busting</title> <title>More cache-busting</title>
<link>http://devlog.ajstepien.xyz/posts/cache-busting-2/</link> <link>http://localhost:1313/posts/cache-busting-2/</link>
<pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate> <pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/cache-busting-2/</guid> <guid>http://localhost:1313/posts/cache-busting-2/</guid>
<description>&lt;p&gt;&lt;strong&gt;Well, that was easy.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;At the end of &lt;a href=&#34;cache-busting&#34;&gt;my last post&lt;/a&gt;, I had successfully written a script to stop stale CSS from getting stuck in the browser cache. It was a rough-and-ready solution &amp;mdash; mine usually are &amp;mdash; but it did the job. The one optimization I wanted to make was to ensure that the cache gets busted &lt;em&gt;only&lt;/em&gt; when there is fresh CSS, as opposed to on every build. I had expected to get a nice long blog post out of this, but it turns out to be a very easy job.&lt;/p&gt;</description> <description>&lt;p&gt;&lt;strong&gt;Well, that was easy.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;At the end of &lt;a href=&#34;cache-busting&#34;&gt;my last post&lt;/a&gt;, I had successfully written a script to stop stale CSS from getting stuck in the browser cache. It was a rough-and-ready solution &amp;mdash; mine usually are &amp;mdash; but it did the job. The one optimization I wanted to make was to ensure that the cache gets busted &lt;em&gt;only&lt;/em&gt; when there is fresh CSS, as opposed to on every build. I had expected to get a nice long blog post out of this, but it turns out to be a very easy job.&lt;/p&gt;</description>
</item> </item>
<item> <item>
<title>Invalidating the browser cache</title> <title>Invalidating the browser cache</title>
<link>http://devlog.ajstepien.xyz/posts/cache-busting/</link> <link>http://localhost:1313/posts/cache-busting/</link>
<pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate> <pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/cache-busting/</guid> <guid>http://localhost:1313/posts/cache-busting/</guid>
<description>&lt;p&gt;&lt;strong&gt;I had a bit of an issue with my &lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;website&lt;/a&gt; recently.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;I pushed some changes incorporating images for the first time (I know &amp;ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&amp;hellip; the images were not styled. Stranger still, they &lt;em&gt;were&lt;/em&gt; styled when I loaded the same page in Chrome.&lt;/p&gt;&#xA;&lt;p&gt;The experienced computer touchers amongst you will be saying &amp;ldquo;this is obviously a cache problem&amp;rdquo;, and you&amp;rsquo;re right, it is obviously a cache problem. Pressing &lt;code&gt;CTR + SHIFT + R&lt;/code&gt; (which forces Firefox to clear the cache and do a full reload) proved this thesis, and solved the immediate problem for me, on my machine. But what about other people&amp;rsquo;s machines? &lt;strong&gt;I needed to cache-bust.&lt;/strong&gt;&lt;/p&gt;</description> <description>&lt;p&gt;&lt;strong&gt;I had a bit of an issue with my &lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;website&lt;/a&gt; recently.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;I pushed some changes incorporating images for the first time (I know &amp;ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&amp;hellip; the images were not styled. Stranger still, they &lt;em&gt;were&lt;/em&gt; styled when I loaded the same page in Chrome.&lt;/p&gt;&#xA;&lt;p&gt;The experienced computer touchers amongst you will be saying &amp;ldquo;this is obviously a cache problem&amp;rdquo;, and you&amp;rsquo;re right, it is obviously a cache problem. Pressing &lt;code&gt;CTR + SHIFT + R&lt;/code&gt; (which forces Firefox to clear the cache and do a full reload) proved this thesis, and solved the immediate problem for me, on my machine. But what about other people&amp;rsquo;s machines? &lt;strong&gt;I needed to cache-bust.&lt;/strong&gt;&lt;/p&gt;</description>
</item> </item>
</channel> </channel>

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="en-us" dir="ltr">
<head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>
Education, Golang, Go, Websockets | Coding with Andrzej
</title>
<link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
<link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/syntax.css" />
<link rel="stylesheet" href="/css/defaults.css" />
<script src="/js/main.js"></script>
</head>
<body>
<header>
<a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/posts/">Posts</a>
</li>
<li>
<a href="/tags/">Tags</a>
</li>
</ul>
</nav>
</header>
<main>
<h1>Education, Golang, Go, Websockets</h1>
<ul class="page-list">
<li>
<h2 class="center"><a href="/posts/buzzer-game/">Buzzer Game</a></h2>
<time datetime="2024-11-24T15:23:50&#43;01:00">November 24, 2024</time>
<h2 id="i-started-working-on-a-new-project-today">I started working on a new project today.</h2>
<p>The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:</p>
<ol>
<li>provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds</li>
<li>allow a teacher to assign groups and pairs in</li>
<li>allow the teacher to dynamically reassign groups without repeating combinations</li>
<li>implement a simple score-keeping functionality</li>
<li>be able to run a &lsquo;buzzer&rsquo; game</li>
<li>have a clean, appealing, and user-friendly UI</li>
</ol>
<p>A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &lsquo;buzzes&rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.</p>
<a href="/posts/buzzer-game/">Read more...</a>
</li>
</ul>
</main>
<footer>
<p>Copyright 2024. All rights reserved.</p>
</footer>
</body>
</html>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Education, Golang, Go, Websockets on Coding with Andrzej</title>
<link>http://localhost:1313/tags/education-golang-go-websockets/</link>
<description>Recent content in Education, Golang, Go, Websockets on Coding with Andrzej</description>
<generator>Hugo</generator>
<language>en-us</language>
<lastBuildDate>Sun, 24 Nov 2024 15:23:50 +0100</lastBuildDate>
<atom:link href="http://localhost:1313/tags/education-golang-go-websockets/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Buzzer Game</title>
<link>http://localhost:1313/posts/buzzer-game/</link>
<pubDate>Sun, 24 Nov 2024 15:23:50 +0100</pubDate>
<guid>http://localhost:1313/posts/buzzer-game/</guid>
<description>&lt;h2 id=&#34;i-started-working-on-a-new-project-today&#34;&gt;I started working on a new project today.&lt;/h2&gt;&#xA;&lt;p&gt;The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds&lt;/li&gt;&#xA;&lt;li&gt;allow a teacher to assign groups and pairs in&lt;/li&gt;&#xA;&lt;li&gt;allow the teacher to dynamically reassign groups without repeating combinations&lt;/li&gt;&#xA;&lt;li&gt;implement a simple score-keeping functionality&lt;/li&gt;&#xA;&lt;li&gt;be able to run a &amp;lsquo;buzzer&amp;rsquo; game&lt;/li&gt;&#xA;&lt;li&gt;have a clean, appealing, and user-friendly UI&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &amp;lsquo;buzzes&amp;rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.&lt;/p&gt;</description>
</item>
</channel>
</rss>

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="en-us" dir="ltr">
<head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>
Education | Coding with Andrzej
</title>
<link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
<link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/syntax.css" />
<link rel="stylesheet" href="/css/defaults.css" />
<script src="/js/main.js"></script>
</head>
<body>
<header>
<a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/posts/">Posts</a>
</li>
<li>
<a href="/tags/">Tags</a>
</li>
</ul>
</nav>
</header>
<main>
<h1>Education</h1>
<ul class="page-list">
<li>
<h2 class="center"><a href="/posts/buzzer-game/">Classroom Buzzer App</a></h2>
<time datetime="2024-11-24T15:23:50&#43;01:00">November 24, 2024</time>
<h2 id="i-started-working-on-a-new-project-today">I started working on a new project today.</h2>
<p>The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:</p>
<ul>
<li>provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds</li>
<li>allow a teacher to assign groups and pairs in</li>
<li>allow the teacher to dynamically reassign groups without repeating combinations</li>
<li>implement a simple score-keeping functionality</li>
<li>be able to run a &lsquo;buzzer&rsquo; game</li>
<li>have a clean, appealing, and user-friendly UI</li>
</ul>
<p>A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &lsquo;buzzes&rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.</p>
<a href="/posts/buzzer-game/">Read more...</a>
</li>
</ul>
</main>
<footer>
<p>Copyright 2024. All rights reserved.</p>
</footer>
</body>
</html>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Education on Coding with Andrzej</title>
<link>http://localhost:1313/tags/education/</link>
<description>Recent content in Education on Coding with Andrzej</description>
<generator>Hugo</generator>
<language>en-us</language>
<lastBuildDate>Sun, 24 Nov 2024 15:23:50 +0100</lastBuildDate>
<atom:link href="http://localhost:1313/tags/education/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Classroom Buzzer App</title>
<link>http://localhost:1313/posts/buzzer-game/</link>
<pubDate>Sun, 24 Nov 2024 15:23:50 +0100</pubDate>
<guid>http://localhost:1313/posts/buzzer-game/</guid>
<description>&lt;h2 id=&#34;i-started-working-on-a-new-project-today&#34;&gt;I started working on a new project today.&lt;/h2&gt;&#xA;&lt;p&gt;The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds&lt;/li&gt;&#xA;&lt;li&gt;allow a teacher to assign groups and pairs in&lt;/li&gt;&#xA;&lt;li&gt;allow the teacher to dynamically reassign groups without repeating combinations&lt;/li&gt;&#xA;&lt;li&gt;implement a simple score-keeping functionality&lt;/li&gt;&#xA;&lt;li&gt;be able to run a &amp;lsquo;buzzer&amp;rsquo; game&lt;/li&gt;&#xA;&lt;li&gt;have a clean, appealing, and user-friendly UI&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &amp;lsquo;buzzes&amp;rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.&lt;/p&gt;</description>
</item>
</channel>
</rss>

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="en-us" dir="ltr">
<head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>
Golang | Coding with Andrzej
</title>
<link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
<link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/syntax.css" />
<link rel="stylesheet" href="/css/defaults.css" />
<script src="/js/main.js"></script>
</head>
<body>
<header>
<a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/posts/">Posts</a>
</li>
<li>
<a href="/tags/">Tags</a>
</li>
</ul>
</nav>
</header>
<main>
<h1>Golang</h1>
<ul class="page-list">
<li>
<h2 class="center"><a href="/posts/buzzer-game/">Classroom Buzzer App</a></h2>
<time datetime="2024-11-24T15:23:50&#43;01:00">November 24, 2024</time>
<h2 id="i-started-working-on-a-new-project-today">I started working on a new project today.</h2>
<p>The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:</p>
<ul>
<li>provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds</li>
<li>allow a teacher to assign groups and pairs in</li>
<li>allow the teacher to dynamically reassign groups without repeating combinations</li>
<li>implement a simple score-keeping functionality</li>
<li>be able to run a &lsquo;buzzer&rsquo; game</li>
<li>have a clean, appealing, and user-friendly UI</li>
</ul>
<p>A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &lsquo;buzzes&rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.</p>
<a href="/posts/buzzer-game/">Read more...</a>
</li>
</ul>
</main>
<footer>
<p>Copyright 2024. All rights reserved.</p>
</footer>
</body>
</html>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Golang on Coding with Andrzej</title>
<link>http://localhost:1313/tags/golang/</link>
<description>Recent content in Golang on Coding with Andrzej</description>
<generator>Hugo</generator>
<language>en-us</language>
<lastBuildDate>Sun, 24 Nov 2024 15:23:50 +0100</lastBuildDate>
<atom:link href="http://localhost:1313/tags/golang/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Classroom Buzzer App</title>
<link>http://localhost:1313/posts/buzzer-game/</link>
<pubDate>Sun, 24 Nov 2024 15:23:50 +0100</pubDate>
<guid>http://localhost:1313/posts/buzzer-game/</guid>
<description>&lt;h2 id=&#34;i-started-working-on-a-new-project-today&#34;&gt;I started working on a new project today.&lt;/h2&gt;&#xA;&lt;p&gt;The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds&lt;/li&gt;&#xA;&lt;li&gt;allow a teacher to assign groups and pairs in&lt;/li&gt;&#xA;&lt;li&gt;allow the teacher to dynamically reassign groups without repeating combinations&lt;/li&gt;&#xA;&lt;li&gt;implement a simple score-keeping functionality&lt;/li&gt;&#xA;&lt;li&gt;be able to run a &amp;lsquo;buzzer&amp;rsquo; game&lt;/li&gt;&#xA;&lt;li&gt;have a clean, appealing, and user-friendly UI&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &amp;lsquo;buzzes&amp;rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.&lt;/p&gt;</description>
</item>
</channel>
</rss>

View File

@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-us" dir="ltr"> <html lang="en-us" dir="ltr">
<head> <head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title> <title>
Html | Coding with Andrzej Html | Coding with Andrzej
</title> </title>
<link rel="alternate" type="application/rss+xml" href="http://devlog.ajstepien.xyz//index.xml" title="Coding with Andrzej"> <link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
@ -24,13 +24,13 @@
<script src="/js/main.23cd0c7d837263b9eaeb96ee2d9ccfa2969daa3fa00fa1c1fe8701a9b87251a1.js" integrity="sha256-I80MfYNyY7nq65buLZzPopadqj&#43;gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script> <script src="/js/main.js"></script>
</head> </head>
<body> <body>
<header> <header>
<a href=http://devlog.ajstepien.xyz/><h1>Coding with Andrzej</h1></a> <a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav> <nav>
<ul> <ul>

View File

@ -2,17 +2,17 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel> <channel>
<title>Html on Coding with Andrzej</title> <title>Html on Coding with Andrzej</title>
<link>http://devlog.ajstepien.xyz/tags/html/</link> <link>http://localhost:1313/tags/html/</link>
<description>Recent content in Html on Coding with Andrzej</description> <description>Recent content in Html on Coding with Andrzej</description>
<generator>Hugo</generator> <generator>Hugo</generator>
<language>en-us</language> <language>en-us</language>
<lastBuildDate>Thu, 14 Nov 2024 14:24:21 +0100</lastBuildDate> <lastBuildDate>Thu, 14 Nov 2024 14:24:21 +0100</lastBuildDate>
<atom:link href="http://devlog.ajstepien.xyz/tags/html/index.xml" rel="self" type="application/rss+xml" /> <atom:link href="http://localhost:1313/tags/html/index.xml" rel="self" type="application/rss+xml" />
<item> <item>
<title>Invalidating the browser cache</title> <title>Invalidating the browser cache</title>
<link>http://devlog.ajstepien.xyz/posts/cache-busting/</link> <link>http://localhost:1313/posts/cache-busting/</link>
<pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate> <pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/cache-busting/</guid> <guid>http://localhost:1313/posts/cache-busting/</guid>
<description>&lt;p&gt;&lt;strong&gt;I had a bit of an issue with my &lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;website&lt;/a&gt; recently.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;I pushed some changes incorporating images for the first time (I know &amp;ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&amp;hellip; the images were not styled. Stranger still, they &lt;em&gt;were&lt;/em&gt; styled when I loaded the same page in Chrome.&lt;/p&gt;&#xA;&lt;p&gt;The experienced computer touchers amongst you will be saying &amp;ldquo;this is obviously a cache problem&amp;rdquo;, and you&amp;rsquo;re right, it is obviously a cache problem. Pressing &lt;code&gt;CTR + SHIFT + R&lt;/code&gt; (which forces Firefox to clear the cache and do a full reload) proved this thesis, and solved the immediate problem for me, on my machine. But what about other people&amp;rsquo;s machines? &lt;strong&gt;I needed to cache-bust.&lt;/strong&gt;&lt;/p&gt;</description> <description>&lt;p&gt;&lt;strong&gt;I had a bit of an issue with my &lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;website&lt;/a&gt; recently.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;I pushed some changes incorporating images for the first time (I know &amp;ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&amp;hellip; the images were not styled. Stranger still, they &lt;em&gt;were&lt;/em&gt; styled when I loaded the same page in Chrome.&lt;/p&gt;&#xA;&lt;p&gt;The experienced computer touchers amongst you will be saying &amp;ldquo;this is obviously a cache problem&amp;rdquo;, and you&amp;rsquo;re right, it is obviously a cache problem. Pressing &lt;code&gt;CTR + SHIFT + R&lt;/code&gt; (which forces Firefox to clear the cache and do a full reload) proved this thesis, and solved the immediate problem for me, on my machine. But what about other people&amp;rsquo;s machines? &lt;strong&gt;I needed to cache-bust.&lt;/strong&gt;&lt;/p&gt;</description>
</item> </item>
</channel> </channel>

View File

@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-us" dir="ltr"> <html lang="en-us" dir="ltr">
<head> <head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title> <title>
Tags | Coding with Andrzej Tags | Coding with Andrzej
</title> </title>
<link rel="alternate" type="application/rss+xml" href="http://devlog.ajstepien.xyz//index.xml" title="Coding with Andrzej"> <link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
@ -24,13 +24,13 @@
<script src="/js/main.23cd0c7d837263b9eaeb96ee2d9ccfa2969daa3fa00fa1c1fe8701a9b87251a1.js" integrity="sha256-I80MfYNyY7nq65buLZzPopadqj&#43;gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script> <script src="/js/main.js"></script>
</head> </head>
<body> <body>
<header> <header>
<a href=http://devlog.ajstepien.xyz/><h1>Coding with Andrzej</h1></a> <a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav> <nav>
<ul> <ul>
@ -59,6 +59,42 @@
<li>
<h2 class="center"><a href="/tags/concurrency/">Concurrency</a></h2>
</li>
<li>
<h2 class="center"><a href="/tags/education/">Education</a></h2>
</li>
<li>
<h2 class="center"><a href="/tags/golang/">Golang</a></h2>
</li>
<li>
<h2 class="center"><a href="/tags/websockets/">Websockets</a></h2>
</li>
<li> <li>
<h2 class="center"><a href="/tags/css/">CSS</a></h2> <h2 class="center"><a href="/tags/css/">CSS</a></h2>

View File

@ -2,31 +2,59 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel> <channel>
<title>Tags on Coding with Andrzej</title> <title>Tags on Coding with Andrzej</title>
<link>http://devlog.ajstepien.xyz/tags/</link> <link>http://localhost:1313/tags/</link>
<description>Recent content in Tags on Coding with Andrzej</description> <description>Recent content in Tags on Coding with Andrzej</description>
<generator>Hugo</generator> <generator>Hugo</generator>
<language>en-us</language> <language>en-us</language>
<lastBuildDate>Fri, 15 Nov 2024 22:33:10 +0100</lastBuildDate> <lastBuildDate>Sun, 24 Nov 2024 15:23:50 +0100</lastBuildDate>
<atom:link href="http://devlog.ajstepien.xyz/tags/index.xml" rel="self" type="application/rss+xml" /> <atom:link href="http://localhost:1313/tags/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Concurrency</title>
<link>http://localhost:1313/tags/concurrency/</link>
<pubDate>Sun, 24 Nov 2024 15:23:50 +0100</pubDate>
<guid>http://localhost:1313/tags/concurrency/</guid>
<description></description>
</item>
<item>
<title>Education</title>
<link>http://localhost:1313/tags/education/</link>
<pubDate>Sun, 24 Nov 2024 15:23:50 +0100</pubDate>
<guid>http://localhost:1313/tags/education/</guid>
<description></description>
</item>
<item>
<title>Golang</title>
<link>http://localhost:1313/tags/golang/</link>
<pubDate>Sun, 24 Nov 2024 15:23:50 +0100</pubDate>
<guid>http://localhost:1313/tags/golang/</guid>
<description></description>
</item>
<item>
<title>Websockets</title>
<link>http://localhost:1313/tags/websockets/</link>
<pubDate>Sun, 24 Nov 2024 15:23:50 +0100</pubDate>
<guid>http://localhost:1313/tags/websockets/</guid>
<description></description>
</item>
<item> <item>
<title>CSS</title> <title>CSS</title>
<link>http://devlog.ajstepien.xyz/tags/css/</link> <link>http://localhost:1313/tags/css/</link>
<pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate> <pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/tags/css/</guid> <guid>http://localhost:1313/tags/css/</guid>
<description></description> <description></description>
</item> </item>
<item> <item>
<title>Linux</title> <title>Linux</title>
<link>http://devlog.ajstepien.xyz/tags/linux/</link> <link>http://localhost:1313/tags/linux/</link>
<pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate> <pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/tags/linux/</guid> <guid>http://localhost:1313/tags/linux/</guid>
<description></description> <description></description>
</item> </item>
<item> <item>
<title>Html</title> <title>Html</title>
<link>http://devlog.ajstepien.xyz/tags/html/</link> <link>http://localhost:1313/tags/html/</link>
<pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate> <pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/tags/html/</guid> <guid>http://localhost:1313/tags/html/</guid>
<description></description> <description></description>
</item> </item>
</channel> </channel>

View File

@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en-us" dir="ltr"> <html lang="en-us" dir="ltr">
<head> <head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title> <title>
Linux | Coding with Andrzej Linux | Coding with Andrzej
</title> </title>
<link rel="alternate" type="application/rss+xml" href="http://devlog.ajstepien.xyz//index.xml" title="Coding with Andrzej"> <link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
@ -24,13 +24,13 @@
<script src="/js/main.23cd0c7d837263b9eaeb96ee2d9ccfa2969daa3fa00fa1c1fe8701a9b87251a1.js" integrity="sha256-I80MfYNyY7nq65buLZzPopadqj&#43;gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script> <script src="/js/main.js"></script>
</head> </head>
<body> <body>
<header> <header>
<a href=http://devlog.ajstepien.xyz/><h1>Coding with Andrzej</h1></a> <a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav> <nav>
<ul> <ul>

View File

@ -2,31 +2,31 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel> <channel>
<title>Linux on Coding with Andrzej</title> <title>Linux on Coding with Andrzej</title>
<link>http://devlog.ajstepien.xyz/tags/linux/</link> <link>http://localhost:1313/tags/linux/</link>
<description>Recent content in Linux on Coding with Andrzej</description> <description>Recent content in Linux on Coding with Andrzej</description>
<generator>Hugo</generator> <generator>Hugo</generator>
<language>en-us</language> <language>en-us</language>
<lastBuildDate>Fri, 15 Nov 2024 22:33:10 +0100</lastBuildDate> <lastBuildDate>Fri, 15 Nov 2024 22:33:10 +0100</lastBuildDate>
<atom:link href="http://devlog.ajstepien.xyz/tags/linux/index.xml" rel="self" type="application/rss+xml" /> <atom:link href="http://localhost:1313/tags/linux/index.xml" rel="self" type="application/rss+xml" />
<item> <item>
<title>More cache-busting</title> <title>More cache-busting</title>
<link>http://devlog.ajstepien.xyz/posts/cache-busting-2/</link> <link>http://localhost:1313/posts/cache-busting-2/</link>
<pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate> <pubDate>Fri, 15 Nov 2024 22:33:10 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/cache-busting-2/</guid> <guid>http://localhost:1313/posts/cache-busting-2/</guid>
<description>&lt;p&gt;&lt;strong&gt;Well, that was easy.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;At the end of &lt;a href=&#34;cache-busting&#34;&gt;my last post&lt;/a&gt;, I had successfully written a script to stop stale CSS from getting stuck in the browser cache. It was a rough-and-ready solution &amp;mdash; mine usually are &amp;mdash; but it did the job. The one optimization I wanted to make was to ensure that the cache gets busted &lt;em&gt;only&lt;/em&gt; when there is fresh CSS, as opposed to on every build. I had expected to get a nice long blog post out of this, but it turns out to be a very easy job.&lt;/p&gt;</description> <description>&lt;p&gt;&lt;strong&gt;Well, that was easy.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;At the end of &lt;a href=&#34;cache-busting&#34;&gt;my last post&lt;/a&gt;, I had successfully written a script to stop stale CSS from getting stuck in the browser cache. It was a rough-and-ready solution &amp;mdash; mine usually are &amp;mdash; but it did the job. The one optimization I wanted to make was to ensure that the cache gets busted &lt;em&gt;only&lt;/em&gt; when there is fresh CSS, as opposed to on every build. I had expected to get a nice long blog post out of this, but it turns out to be a very easy job.&lt;/p&gt;</description>
</item> </item>
<item> <item>
<title>Invalidating the browser cache</title> <title>Invalidating the browser cache</title>
<link>http://devlog.ajstepien.xyz/posts/cache-busting/</link> <link>http://localhost:1313/posts/cache-busting/</link>
<pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate> <pubDate>Thu, 14 Nov 2024 14:24:21 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/cache-busting/</guid> <guid>http://localhost:1313/posts/cache-busting/</guid>
<description>&lt;p&gt;&lt;strong&gt;I had a bit of an issue with my &lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;website&lt;/a&gt; recently.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;I pushed some changes incorporating images for the first time (I know &amp;ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&amp;hellip; the images were not styled. Stranger still, they &lt;em&gt;were&lt;/em&gt; styled when I loaded the same page in Chrome.&lt;/p&gt;&#xA;&lt;p&gt;The experienced computer touchers amongst you will be saying &amp;ldquo;this is obviously a cache problem&amp;rdquo;, and you&amp;rsquo;re right, it is obviously a cache problem. Pressing &lt;code&gt;CTR + SHIFT + R&lt;/code&gt; (which forces Firefox to clear the cache and do a full reload) proved this thesis, and solved the immediate problem for me, on my machine. But what about other people&amp;rsquo;s machines? &lt;strong&gt;I needed to cache-bust.&lt;/strong&gt;&lt;/p&gt;</description> <description>&lt;p&gt;&lt;strong&gt;I had a bit of an issue with my &lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;website&lt;/a&gt; recently.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;I pushed some changes incorporating images for the first time (I know &amp;ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&amp;hellip; the images were not styled. Stranger still, they &lt;em&gt;were&lt;/em&gt; styled when I loaded the same page in Chrome.&lt;/p&gt;&#xA;&lt;p&gt;The experienced computer touchers amongst you will be saying &amp;ldquo;this is obviously a cache problem&amp;rdquo;, and you&amp;rsquo;re right, it is obviously a cache problem. Pressing &lt;code&gt;CTR + SHIFT + R&lt;/code&gt; (which forces Firefox to clear the cache and do a full reload) proved this thesis, and solved the immediate problem for me, on my machine. But what about other people&amp;rsquo;s machines? &lt;strong&gt;I needed to cache-bust.&lt;/strong&gt;&lt;/p&gt;</description>
</item> </item>
<item> <item>
<title>Permissions strike again</title> <title>Permissions strike again</title>
<link>http://devlog.ajstepien.xyz/posts/permissions-strike-again/</link> <link>http://localhost:1313/posts/permissions-strike-again/</link>
<pubDate>Wed, 13 Nov 2024 11:53:13 +0100</pubDate> <pubDate>Wed, 13 Nov 2024 11:53:13 +0100</pubDate>
<guid>http://devlog.ajstepien.xyz/posts/permissions-strike-again/</guid> <guid>http://localhost:1313/posts/permissions-strike-again/</guid>
<description>&lt;p&gt;Configuring Apache really isn&amp;rsquo;t rocket science. There are a wealth of great tutorials online, the documentation is very well documented, and the defaults work more or less out of the box. But it&amp;rsquo;s one of those jobs that I do just infrequently enough that I always forget things in the interim, and end up making the same old mistakes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;strong&gt;And it almost always has to do with permissions.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;So, I&amp;rsquo;m writing this post both as a means of christening this devlog (&lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;Hi! I&amp;rsquo;m Andrzej! Hire me!&lt;/a&gt;) and also as a reminder to myself that &lt;em&gt;the home folder is not executable by default.&lt;/em&gt;&lt;/p&gt;</description> <description>&lt;p&gt;Configuring Apache really isn&amp;rsquo;t rocket science. There are a wealth of great tutorials online, the documentation is very well documented, and the defaults work more or less out of the box. But it&amp;rsquo;s one of those jobs that I do just infrequently enough that I always forget things in the interim, and end up making the same old mistakes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;strong&gt;And it almost always has to do with permissions.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;So, I&amp;rsquo;m writing this post both as a means of christening this devlog (&lt;a href=&#34;https://demos.ajstepien.xyz&#34;&gt;Hi! I&amp;rsquo;m Andrzej! Hire me!&lt;/a&gt;) and also as a reminder to myself that &lt;em&gt;the home folder is not executable by default.&lt;/em&gt;&lt;/p&gt;</description>
</item> </item>
</channel> </channel>

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="en-us" dir="ltr">
<head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>
Websockets | Coding with Andrzej
</title>
<link rel="alternate" type="application/rss+xml" href="http://localhost:1313//index.xml" title="Coding with Andrzej">
<link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/syntax.css" />
<link rel="stylesheet" href="/css/defaults.css" />
<script src="/js/main.js"></script>
</head>
<body>
<header>
<a href=http://localhost:1313/><h1>Coding with Andrzej</h1></a>
<nav>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/posts/">Posts</a>
</li>
<li>
<a href="/tags/">Tags</a>
</li>
</ul>
</nav>
</header>
<main>
<h1>Websockets</h1>
<ul class="page-list">
<li>
<h2 class="center"><a href="/posts/buzzer-game/">Classroom Buzzer App</a></h2>
<time datetime="2024-11-24T15:23:50&#43;01:00">November 24, 2024</time>
<h2 id="i-started-working-on-a-new-project-today">I started working on a new project today.</h2>
<p>The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:</p>
<ul>
<li>provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds</li>
<li>allow a teacher to assign groups and pairs in</li>
<li>allow the teacher to dynamically reassign groups without repeating combinations</li>
<li>implement a simple score-keeping functionality</li>
<li>be able to run a &lsquo;buzzer&rsquo; game</li>
<li>have a clean, appealing, and user-friendly UI</li>
</ul>
<p>A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &lsquo;buzzes&rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.</p>
<a href="/posts/buzzer-game/">Read more...</a>
</li>
</ul>
</main>
<footer>
<p>Copyright 2024. All rights reserved.</p>
</footer>
</body>
</html>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Websockets on Coding with Andrzej</title>
<link>http://localhost:1313/tags/websockets/</link>
<description>Recent content in Websockets on Coding with Andrzej</description>
<generator>Hugo</generator>
<language>en-us</language>
<lastBuildDate>Sun, 24 Nov 2024 15:23:50 +0100</lastBuildDate>
<atom:link href="http://localhost:1313/tags/websockets/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Classroom Buzzer App</title>
<link>http://localhost:1313/posts/buzzer-game/</link>
<pubDate>Sun, 24 Nov 2024 15:23:50 +0100</pubDate>
<guid>http://localhost:1313/posts/buzzer-game/</guid>
<description>&lt;h2 id=&#34;i-started-working-on-a-new-project-today&#34;&gt;I started working on a new project today.&lt;/h2&gt;&#xA;&lt;p&gt;The client is an educational services provider and wants me to develop a tool to facilitate in-person group activities. This tool should:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;provide a platform which students can log into from a mobile device, in a frictionless process that takes seconds&lt;/li&gt;&#xA;&lt;li&gt;allow a teacher to assign groups and pairs in&lt;/li&gt;&#xA;&lt;li&gt;allow the teacher to dynamically reassign groups without repeating combinations&lt;/li&gt;&#xA;&lt;li&gt;implement a simple score-keeping functionality&lt;/li&gt;&#xA;&lt;li&gt;be able to run a &amp;lsquo;buzzer&amp;rsquo; game&lt;/li&gt;&#xA;&lt;li&gt;have a clean, appealing, and user-friendly UI&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A quick read of this brief should make it clear that what is required here is a server capable of handling multiple, live, two-way connections. The server needs to be able to update the clients whenever the teacher wants to shuffle the groups, and the buzzer game requires that when a student &amp;lsquo;buzzes&amp;rsquo;, state is propagated via the server to all other clients. The solution to this problem is websockets, and a server capable of handling concurrency.&lt;/p&gt;</description>
</item>
</channel>
</rss>

View File

@ -186,6 +186,10 @@ nav>ul {
gap: 2rem; gap: 2rem;
} }
nav>ul>li {
list-style-type: none;
}
nav>ul>li>a { nav>ul>li>a {
color: pink; color: pink;
font-size: 2rem; font-size: 2rem;
@ -199,7 +203,7 @@ nav>ul>li>a {
border-radius: 1rem; border-radius: 1rem;
margin-bottom: 1rem; margin-bottom: 1rem;
min-width: 24em; min-width: 24em;
; list-style-type: none;
} }
@ -208,6 +212,15 @@ nav>ul>li>a {
margin: auto; margin: auto;
} }
li {
list-style-type: '>';
padding: 0.6em;
}
li::marker {
color: var(--rp-pine);
}
/* TAGS */ /* TAGS */
.post-tags { .post-tags {
display: flex; display: flex;
@ -215,8 +228,6 @@ nav>ul>li>a {
} }
.post-tags>li { .post-tags>li {
@media screen and (min-width:600px) { @media screen and (min-width:600px) {
font-size: 3rem; font-size: 3rem;
} }
@ -224,4 +235,5 @@ nav>ul>li>a {
background-image: linear-gradient(to bottom, var(--rp-overlay) 80%, var(--rp-base)); background-image: linear-gradient(to bottom, var(--rp-overlay) 80%, var(--rp-base));
padding: 0.4em; padding: 0.4em;
border-radius: 0.6em 0.6em 0 0; border-radius: 0.6em 0.6em 0 0;
list-style-type: none;
} }