buzzer game
This commit is contained in:
parent
eac5573121
commit
7fab5277e6
|
@ -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.
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head>
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>
|
||||
Categories | Coding with Andrzej
|
||||
</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+gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script>
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<ul>
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<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>
|
||||
<generator>Hugo</generator>
|
||||
<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>
|
||||
</rss>
|
||||
|
|
|
@ -186,6 +186,10 @@ nav>ul {
|
|||
gap: 2rem;
|
||||
}
|
||||
|
||||
nav>ul>li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
nav>ul>li>a {
|
||||
color: pink;
|
||||
font-size: 2rem;
|
||||
|
@ -199,7 +203,7 @@ nav>ul>li>a {
|
|||
border-radius: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
min-width: 24em;
|
||||
;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
|
||||
|
@ -208,6 +212,15 @@ nav>ul>li>a {
|
|||
margin: auto;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style-type: '>';
|
||||
padding: 0.6em;
|
||||
}
|
||||
|
||||
li::marker {
|
||||
color: var(--rp-pine);
|
||||
}
|
||||
|
||||
/* TAGS */
|
||||
.post-tags {
|
||||
display: flex;
|
||||
|
@ -215,8 +228,6 @@ nav>ul>li>a {
|
|||
}
|
||||
|
||||
.post-tags>li {
|
||||
|
||||
|
||||
@media screen and (min-width:600px) {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
@ -224,4 +235,5 @@ nav>ul>li>a {
|
|||
background-image: linear-gradient(to bottom, var(--rp-overlay) 80%, var(--rp-base));
|
||||
padding: 0.4em;
|
||||
border-radius: 0.6em 0.6em 0 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head>
|
||||
<meta name="generator" content="Hugo 0.138.0">
|
||||
<meta name="generator" content="Hugo 0.138.0"><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>
|
||||
Coding with Andrzej
|
||||
</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+gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script>
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<ul>
|
||||
|
@ -55,10 +55,19 @@
|
|||
|
||||
<h1>Latest...</h1>
|
||||
|
||||
<h2><a href="/posts/cache-busting-2/">More cache-busting</a></h2>
|
||||
<p><strong>Well, that was easy.</strong></p>
|
||||
<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 — mine usually are — 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>
|
||||
<a href="/posts/cache-busting-2/">Read more...</a>
|
||||
<h2><a href="/posts/buzzer-game/">Classroom Buzzer App</a></h2>
|
||||
<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 ‘buzzer’ 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 ‘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.</p>
|
||||
<a href="/posts/buzzer-game/">Read more...</a>
|
||||
|
||||
|
||||
</main>
|
||||
|
|
|
@ -2,31 +2,38 @@
|
|||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<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>
|
||||
<generator>Hugo</generator>
|
||||
<language>en-us</language>
|
||||
<lastBuildDate>Fri, 15 Nov 2024 22:33:10 +0100</lastBuildDate>
|
||||
<atom:link href="http://devlog.ajstepien.xyz/index.xml" rel="self" type="application/rss+xml" />
|
||||
<lastBuildDate>Sun, 24 Nov 2024 15:23:50 +0100</lastBuildDate>
|
||||
<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><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></description>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/cache-busting-2/</guid>
|
||||
<guid>http://localhost:1313/posts/cache-busting-2/</guid>
|
||||
<description><p><strong>Well, that was easy.</strong></p>
<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></description>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/cache-busting/</guid>
|
||||
<guid>http://localhost:1313/posts/cache-busting/</guid>
|
||||
<description><p><strong>I had a bit of an issue with my <a href="https://demos.ajstepien.xyz">website</a> recently.</strong></p>
<p>I pushed some changes incorporating images for the first time (I know &ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&hellip; the images were not styled. Stranger still, they <em>were</em> styled when I loaded the same page in Chrome.</p>
<p>The experienced computer touchers amongst you will be saying &ldquo;this is obviously a cache problem&rdquo;, and you&rsquo;re right, it is obviously a cache problem. Pressing <code>CTR + SHIFT + R</code> (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&rsquo;s machines? <strong>I needed to cache-bust.</strong></p></description>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/permissions-strike-again/</guid>
|
||||
<guid>http://localhost:1313/posts/permissions-strike-again/</guid>
|
||||
<description><p>Configuring Apache really isn&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&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.</p>
<p><em><strong>And it almost always has to do with permissions.</strong></em></p>
<p>So, I&rsquo;m writing this post both as a means of christening this devlog (<a href="https://demos.ajstepien.xyz">Hi! I&rsquo;m Andrzej! Hire me!</a>) and also as a reminder to myself that <em>the home folder is not executable by default.</em></p></description>
|
||||
</item>
|
||||
</channel>
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&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+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 ‘buzzer’ 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 ‘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.</p>
|
||||
<p>Now I’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’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’t hate myself <em>quite that much</em>, I’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">"log"</span>
|
||||
</span></span><span class="line"><span class="cl"> <span class="s">"net/http"</span>
|
||||
</span></span><span class="line"><span class="cl"> <span class="s">"sync"</span>
|
||||
</span></span><span class="line"><span class="cl">
|
||||
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/gorilla/websocket"</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">"Error while upgrading connection to websocket: %s"</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">"New websocket connection. There are now %v\n"</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">"8080"</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">"/"</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">"listening on port %s...\n"</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">"localhost:8080"</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’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’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">"Error while upgrading connection to websocket: %s"</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">"New websocket connection. There are now %v\n"</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">"Error trying to read message from client: %s"</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">"this server does not support binary messages"</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">"Error trying to send message to client: %s"</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">"received message from client: %s"</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">"Message received!"</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’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’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>
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head>
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>
|
||||
More cache-busting | Coding with Andrzej
|
||||
</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+gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script>
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<ul>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head>
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>
|
||||
Invalidating the browser cache | Coding with Andrzej
|
||||
</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+gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script>
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<ul>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head>
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>
|
||||
Posts | Coding with Andrzej
|
||||
</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+gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script>
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<ul>
|
||||
|
@ -58,6 +58,28 @@
|
|||
<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+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 ‘buzzer’ 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 ‘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.</p>
|
||||
|
||||
<a href="/posts/buzzer-game/">Read more...</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<h2 class="center"><a href="/posts/cache-busting-2/">More cache-busting</a></h2>
|
||||
|
||||
|
|
|
@ -2,31 +2,38 @@
|
|||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<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>
|
||||
<generator>Hugo</generator>
|
||||
<language>en-us</language>
|
||||
<lastBuildDate>Fri, 15 Nov 2024 22:33:10 +0100</lastBuildDate>
|
||||
<atom:link href="http://devlog.ajstepien.xyz/posts/index.xml" rel="self" type="application/rss+xml" />
|
||||
<lastBuildDate>Sun, 24 Nov 2024 15:23:50 +0100</lastBuildDate>
|
||||
<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><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></description>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/cache-busting-2/</guid>
|
||||
<guid>http://localhost:1313/posts/cache-busting-2/</guid>
|
||||
<description><p><strong>Well, that was easy.</strong></p>
<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></description>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/cache-busting/</guid>
|
||||
<guid>http://localhost:1313/posts/cache-busting/</guid>
|
||||
<description><p><strong>I had a bit of an issue with my <a href="https://demos.ajstepien.xyz">website</a> recently.</strong></p>
<p>I pushed some changes incorporating images for the first time (I know &ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&hellip; the images were not styled. Stranger still, they <em>were</em> styled when I loaded the same page in Chrome.</p>
<p>The experienced computer touchers amongst you will be saying &ldquo;this is obviously a cache problem&rdquo;, and you&rsquo;re right, it is obviously a cache problem. Pressing <code>CTR + SHIFT + R</code> (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&rsquo;s machines? <strong>I needed to cache-bust.</strong></p></description>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/permissions-strike-again/</guid>
|
||||
<guid>http://localhost:1313/posts/permissions-strike-again/</guid>
|
||||
<description><p>Configuring Apache really isn&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&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.</p>
<p><em><strong>And it almost always has to do with permissions.</strong></em></p>
<p>So, I&rsquo;m writing this post both as a means of christening this devlog (<a href="https://demos.ajstepien.xyz">Hi! I&rsquo;m Andrzej! Hire me!</a>) and also as a reminder to myself that <em>the home folder is not executable by default.</em></p></description>
|
||||
</item>
|
||||
</channel>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head>
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>
|
||||
Permissions strike again | Coding with Andrzej
|
||||
</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+gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script>
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<ul>
|
||||
|
|
|
@ -2,33 +2,48 @@
|
|||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
</url><url>
|
||||
<loc>http://devlog.ajstepien.xyz/tags/</loc>
|
||||
<lastmod>2024-11-15T22:33:10+01:00</lastmod>
|
||||
</url><url>
|
||||
<loc>http://devlog.ajstepien.xyz/tags/html/</loc>
|
||||
<loc>http://localhost:1313/tags/html/</loc>
|
||||
<lastmod>2024-11-14T14:24:21+01:00</lastmod>
|
||||
</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>
|
||||
</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>
|
||||
</url><url>
|
||||
<loc>http://devlog.ajstepien.xyz/posts/</loc>
|
||||
<loc>http://localhost:1313/posts/</loc>
|
||||
<lastmod>2023-01-01T08:30:00-07:00</lastmod>
|
||||
</url><url>
|
||||
<loc>http://devlog.ajstepien.xyz/</loc>
|
||||
<loc>http://localhost:1313/</loc>
|
||||
<lastmod>2023-01-01T08:00:00-07:00</lastmod>
|
||||
</url><url>
|
||||
<loc>http://devlog.ajstepien.xyz/categories/</loc>
|
||||
<loc>http://localhost:1313/categories/</loc>
|
||||
</url>
|
||||
</urlset>
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&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+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 ‘buzzer’ 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 ‘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.</p>
|
||||
|
||||
<a href="/posts/buzzer-game/">Read more...</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
<footer>
|
||||
<p>Copyright 2024. All rights reserved.</p>
|
||||
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -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><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></description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head>
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>
|
||||
CSS | Coding with Andrzej
|
||||
</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+gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script>
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<ul>
|
||||
|
|
|
@ -2,24 +2,24 @@
|
|||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<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>
|
||||
<generator>Hugo</generator>
|
||||
<language>en-us</language>
|
||||
<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>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/cache-busting-2/</guid>
|
||||
<guid>http://localhost:1313/posts/cache-busting-2/</guid>
|
||||
<description><p><strong>Well, that was easy.</strong></p>
<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></description>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/cache-busting/</guid>
|
||||
<guid>http://localhost:1313/posts/cache-busting/</guid>
|
||||
<description><p><strong>I had a bit of an issue with my <a href="https://demos.ajstepien.xyz">website</a> recently.</strong></p>
<p>I pushed some changes incorporating images for the first time (I know &ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&hellip; the images were not styled. Stranger still, they <em>were</em> styled when I loaded the same page in Chrome.</p>
<p>The experienced computer touchers amongst you will be saying &ldquo;this is obviously a cache problem&rdquo;, and you&rsquo;re right, it is obviously a cache problem. Pressing <code>CTR + SHIFT + R</code> (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&rsquo;s machines? <strong>I needed to cache-bust.</strong></p></description>
|
||||
</item>
|
||||
</channel>
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&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+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 ‘buzzer’ 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 ‘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.</p>
|
||||
|
||||
<a href="/posts/buzzer-game/">Read more...</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
<footer>
|
||||
<p>Copyright 2024. All rights reserved.</p>
|
||||
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -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><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></description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -0,0 +1,91 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&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+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 ‘buzzer’ 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 ‘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.</p>
|
||||
|
||||
<a href="/posts/buzzer-game/">Read more...</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
<footer>
|
||||
<p>Copyright 2024. All rights reserved.</p>
|
||||
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -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><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></description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -0,0 +1,91 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&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+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 ‘buzzer’ 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 ‘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.</p>
|
||||
|
||||
<a href="/posts/buzzer-game/">Read more...</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
<footer>
|
||||
<p>Copyright 2024. All rights reserved.</p>
|
||||
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -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><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></description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head>
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>
|
||||
Html | Coding with Andrzej
|
||||
</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+gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script>
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<ul>
|
||||
|
|
|
@ -2,17 +2,17 @@
|
|||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<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>
|
||||
<generator>Hugo</generator>
|
||||
<language>en-us</language>
|
||||
<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>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/cache-busting/</guid>
|
||||
<guid>http://localhost:1313/posts/cache-busting/</guid>
|
||||
<description><p><strong>I had a bit of an issue with my <a href="https://demos.ajstepien.xyz">website</a> recently.</strong></p>
<p>I pushed some changes incorporating images for the first time (I know &ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&hellip; the images were not styled. Stranger still, they <em>were</em> styled when I loaded the same page in Chrome.</p>
<p>The experienced computer touchers amongst you will be saying &ldquo;this is obviously a cache problem&rdquo;, and you&rsquo;re right, it is obviously a cache problem. Pressing <code>CTR + SHIFT + R</code> (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&rsquo;s machines? <strong>I needed to cache-bust.</strong></p></description>
|
||||
</item>
|
||||
</channel>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head>
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>
|
||||
Tags | Coding with Andrzej
|
||||
</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+gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script>
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<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>
|
||||
<h2 class="center"><a href="/tags/css/">CSS</a></h2>
|
||||
|
||||
|
|
|
@ -2,31 +2,59 @@
|
|||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<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>
|
||||
<generator>Hugo</generator>
|
||||
<language>en-us</language>
|
||||
<lastBuildDate>Fri, 15 Nov 2024 22:33:10 +0100</lastBuildDate>
|
||||
<atom:link href="http://devlog.ajstepien.xyz/tags/index.xml" rel="self" type="application/rss+xml" />
|
||||
<lastBuildDate>Sun, 24 Nov 2024 15:23:50 +0100</lastBuildDate>
|
||||
<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>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/tags/css/</guid>
|
||||
<guid>http://localhost:1313/tags/css/</guid>
|
||||
<description></description>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/tags/linux/</guid>
|
||||
<guid>http://localhost:1313/tags/linux/</guid>
|
||||
<description></description>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/tags/html/</guid>
|
||||
<guid>http://localhost:1313/tags/html/</guid>
|
||||
<description></description>
|
||||
</item>
|
||||
</channel>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head>
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>
|
||||
Linux | Coding with Andrzej
|
||||
</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+gD6HB/ocBqbhyUaE=" crossorigin="anonymous"></script>
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<ul>
|
||||
|
|
|
@ -2,31 +2,31 @@
|
|||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<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>
|
||||
<generator>Hugo</generator>
|
||||
<language>en-us</language>
|
||||
<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>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/cache-busting-2/</guid>
|
||||
<guid>http://localhost:1313/posts/cache-busting-2/</guid>
|
||||
<description><p><strong>Well, that was easy.</strong></p>
<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></description>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/cache-busting/</guid>
|
||||
<guid>http://localhost:1313/posts/cache-busting/</guid>
|
||||
<description><p><strong>I had a bit of an issue with my <a href="https://demos.ajstepien.xyz">website</a> recently.</strong></p>
<p>I pushed some changes incorporating images for the first time (I know &ndash; very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site in Firefox&hellip; the images were not styled. Stranger still, they <em>were</em> styled when I loaded the same page in Chrome.</p>
<p>The experienced computer touchers amongst you will be saying &ldquo;this is obviously a cache problem&rdquo;, and you&rsquo;re right, it is obviously a cache problem. Pressing <code>CTR + SHIFT + R</code> (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&rsquo;s machines? <strong>I needed to cache-bust.</strong></p></description>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<guid>http://devlog.ajstepien.xyz/posts/permissions-strike-again/</guid>
|
||||
<guid>http://localhost:1313/posts/permissions-strike-again/</guid>
|
||||
<description><p>Configuring Apache really isn&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&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.</p>
<p><em><strong>And it almost always has to do with permissions.</strong></em></p>
<p>So, I&rsquo;m writing this post both as a means of christening this devlog (<a href="https://demos.ajstepien.xyz">Hi! I&rsquo;m Andrzej! Hire me!</a>) and also as a reminder to myself that <em>the home folder is not executable by default.</em></p></description>
|
||||
</item>
|
||||
</channel>
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<head><script src="/livereload.js?mindelay=10&v=2&port=1313&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+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 ‘buzzer’ 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 ‘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.</p>
|
||||
|
||||
<a href="/posts/buzzer-game/">Read more...</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
<footer>
|
||||
<p>Copyright 2024. All rights reserved.</p>
|
||||
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -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><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></description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -186,6 +186,10 @@ nav>ul {
|
|||
gap: 2rem;
|
||||
}
|
||||
|
||||
nav>ul>li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
nav>ul>li>a {
|
||||
color: pink;
|
||||
font-size: 2rem;
|
||||
|
@ -199,7 +203,7 @@ nav>ul>li>a {
|
|||
border-radius: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
min-width: 24em;
|
||||
;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
|
||||
|
@ -208,6 +212,15 @@ nav>ul>li>a {
|
|||
margin: auto;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style-type: '>';
|
||||
padding: 0.6em;
|
||||
}
|
||||
|
||||
li::marker {
|
||||
color: var(--rp-pine);
|
||||
}
|
||||
|
||||
/* TAGS */
|
||||
.post-tags {
|
||||
display: flex;
|
||||
|
@ -215,8 +228,6 @@ nav>ul>li>a {
|
|||
}
|
||||
|
||||
.post-tags>li {
|
||||
|
||||
|
||||
@media screen and (min-width:600px) {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
@ -224,4 +235,5 @@ nav>ul>li>a {
|
|||
background-image: linear-gradient(to bottom, var(--rp-overlay) 80%, var(--rp-base));
|
||||
padding: 0.4em;
|
||||
border-radius: 0.6em 0.6em 0 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue