avatar

Closeable time ticker and multiple receivers in Go

Problem

Once, I wanted to have multiple goroutines to listen on the same time.Ticker channel and have different behaviours. This can't be achieved that easily because if you pass the same channel to two different goroutines, they will alternate the receive action. The first one will catch the first signal, the second one the second, then the first one will receive the third signal, etc...
The second problem I found is that I wanted to stop the said ticker. If the ticker stops, there is no reason for all the goroutines started using this ticker to keep running.

Let's say that we have two functions that will be run as goroutines. These two functions will be the base for this article :

func doThing(c <-chan time.Time) {
    for range c {
        log.Println("Hello from doThing")
    }
}

func doOtherThing(c <-chan time.Time) {
    for range c {
        log.Println("Hello from doOtherThing")
    }
}

Note the use of the range keyword. This is useful to detect if a channel has been closed (among other things).

The multiTicker base function

As a basic solution, someone (sorry I can't remember his name) on the #go-nuts irc channel told me that it was pretty easy to create a function that takes a time.Ticker as an argument and returns two channels. Let's see how to do that :

func multiTicker(c <-chan time.Time) (chan time.Time, chan time.Time) {
    a := make(chan time.Time)
    b := make(chan time.Time)
    go func() {
        for t := range c {
            a <- t
            b <- t
        }
    }()
    return a, b
}

func main() {
    tc := time.Tick(1 * time.Second)
    a, b := multiTicker(tc)
    go doThing(a)
    go doOtherThing(b)
    fmt.Scanln()
    log.Println("Exiting")
}

That solution works just fine. Once the multiTicker function is called, a goroutine is started and listens on the tc channel. Once it receives data from that channel it immediatly forwards it to the two channels created earlier a and b.

There is one problem though, what if my program grows bigger and at one point I want to stop that ticker ? First of all we shouldn't use the time.Tick function because it doesn't allow us to stop the said ticker. But even if we used a real ticker (using tc := time.NewTicker and then tc.C.Stop(), the two goroutines we started will keep running and wait for data, as well as the internal goroutine of multiTicker. This isn't efficient at all and it limits the control we have over all these elements.

Another channel to rule them all

The solution is actually pretty simple. First of all let's declare a new structure and the associated stop() method :

type closableTicker struct {
    ticker *time.Ticker
    halt   chan bool
}

func (ct *closableTicker) stop() {
    ct.ticker.Stop()
    close(ct.halt)
}

As you can see we the stop method will do two things. It will stop the ticker and close the halt channel. Doesn't make any sense for now but let's modify our multiTicker function as follow :

func multiTicker(ct closableTicker) (chan time.Time, chan time.Time) {
    a := make(chan time.Time)
    b := make(chan time.Time)
    go func() {
        for {
            select {
            case t := <-ct.ticker.C:
                a <- t
                b <- t
            case <-ct.halt:
                close(a)
                close(b)
                return
            }
        }
    }()
    return a, b
}

Here we're using a subtle mecanism of Go about channels. When you close a channel it actually sends something to that channel. So our halt channel will never be used directly but once it's closed, we can close the two channels we declared (a and b) and terminate the goroutine. Using the range technique on doThing and doOtherThing, once the a and b channels will be closed, these two goroutines will return. Let's have a look at the main function :

func main() {
    ct := closableTicker{
        ticker: time.NewTicker(1 * time.Second),
        halt:   make(chan bool, 1),
    }
    a, b := multiTicker(ct)
    go doThing(a)
    go doOtherThing(b)
    time.Sleep(3 * time.Second)
    ct.stop()
    fmt.Scanln()
    log.Println("Exit")
}

Now, the program will work as expected for 3 seconds and then all the goroutines will return, the channels will be closed and back to normal !

Introduction

It has been a while, at least five years, since I last worked with SDL. I forgot almost everything on how to work with that lib and, in the meantime, SDL 2.0 came out. So I decided to get back to it, just for fun, see how it works. First of all I tried to find any recommendations on the internet that could point out why it might be a good idea to work with the SDL in Go. But everyone is going for Rust, C++, C#, Unity and such. Sure the garbage collector is a drawback, but PyGame works fine and it's the Python binding. Python has some pretty bad performances compared to Go, so I didn't see any reasons not to give a shot at the SDL with Go.

go-sdl2

First you'll need to install the go-sdl2 lib. Just click on the link and follow the instructions. As pointed out in the documentation og go-sdl2, you will, of course, need the sdl2 library.

package main

import (
    "github.com/veandco/go-sdl2/sdl"
    "github.com/veandco/go-sdl2/sdl_image"
)

func perror(err error) {
    if err != nil {
        panic(err)
    }
}

// Returns a sdl.Rect that represents the centered src surface on the dst surface
func CalculateCenterRect(src *sdl.Surface, dst *sdl.Surface) (centerRect sdl.Rect) {
    centerRect = src.ClipRect
    centerRect.X = dst.ClipRect.H/2 - centerRect.H/2
    centerRect.Y = dst.ClipRect.W/2 - centerRect.W/2
    return
}

// Blits the src surface with its raw dimensions to the center of the dst surface
// Note : This function is for testing purpose.
func BlitRawCenter(src *sdl.Surface, dst *sdl.Surface) error {
    centerRect := CalculateCenterRect(src, dst)
    return src.Blit(nil, dst, &centerRect)
}

// Blits the src surface with dimensions of srcRect to the center of the dst surface
// Note : This function is for testing purpose
func BlitCenter(srcRect *sdl.Rect, src *sdl.Surface, dst *sdl.Surface) error {
    centerRect := CalculateCenterRect(src, dst)
    return src.Blit(srcRect, dst, &centerRect)
}

// Blits an image to the center of the dst surface
func BlitCenterImage(file string, dst *sdl.Surface) error {
    imgSurface, err := img.Load(file)
    if err != nil {
        return err
    }
    // I don't know what's going on here. Is the resource free at the end of the function ?
    // Is it the intended behaviour ? I should look into it.
    defer imgSurface.Free()
    return BlitRawCenter(imgSurface, dst)
}

func main() {
    sdl.Init(sdl.INIT_EVERYTHING | img.INIT_PNG)

    window, err := sdl.CreateWindow("test", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
        800, 600, sdl.WINDOW_SHOWN)
    perror(err)
    defer window.Destroy()

    // To do : Add handling for events like closing the window.

    // To do : Understand what are renderers
    // renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED|sdl.RENDERER_PRESENTVSYNC)
    // perror(err)

    surface, err := window.GetSurface()
    perror(err)

    BlitCenterImage("res/sdl_img.png", surface)
    window.UpdateSurface()

    sdl.Delay(5000)
    sdl.Quit()
}

Handle dynamic subdomains with Flask's blueprints and nginx !


Note : This post is actually a merge between some of my other posts.


Part I : Problem !


First of all, why would you even want to do something like that ? Dynamic subdomains I mean. Well for example that's what I used to create MarkdownBlog. Each user that registers on here gets a subdomain of his slugged username. This allows the users to feel more detached from the platform. Like "I got my own .com blog !" and not something like markdownblog.com/user.

Admit it, it's pretty cool right ? So, how are we going to do that with Flask ? The answer is pretty simple. Blueprints !


Part II : The Flask side.


Note : This tutorial will assume you have the basis of web application development using Flask. If you don't I'd suggest you to read the quickstart page.

Introduction and minimal application

What are blueprints ? How can you use them ? Do you remember how to create a single-file application with Flask ? Let's start fresh with a single-file app. I chose this way of showing blueprints dynamic subdomains because it's a lot easier to understand. Once the example is complete I'll give a small example architecture for a more modular way of using blueprints (which is after all, the whole point of blueprints).

main.py

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

Now if you run python main.py and head to 127.0.0.1:5000 you should see a pretty "Hello World!" in your browser. That's the most basic web application you can write with Flask, and it's on the front page of the Flask's quickstart guide.

Modifying the /etc/hosts file

Warning : This operation is only useful for testing on your local/development machine. Don't do that on your server, if configured properly, it already uses bind ! In other words, DO NOT do that on any distant server.

Note : I assume you're running Linux. If you're running Windows or OSX (or whatever really), you're on your own for that part. It's a mandatory step to test blueprints on your local machine.

Before we can go any further and in order to test the subdomain handling, we'll modify the /etc/hosts file. The hosts file technique is pretty limited because you need to declare each and everyone of the subdomains you're going to test. Let's start by adding the following lines at the end of our /etc/hosts files :

127.0.0.1    flask.dev                localhost    silence
127.0.0.1    test.flask.dev            localhost    silence
127.0.0.1    othertest.flask.dev        localhost    silence

Now you can run your Flask server and go to flask.dev:5000 in your browser. Note that we added two other hosts, that are subdomains of our application. Also note that flask.dev is just an alias for localhost or 127.0.0.1. Time to add the following line just under the declaration of our app :

#...
app = Flask(__name__)
app.config['SERVER_NAME'] = 'flask.dev:5000'
#...

There ! Now we can start using blueprints. If we didn't do these steps, the Flask dev server wouldn't understand the subdomains and wouldn't even bother to use the blueprint we're going to define.

Using blueprints

from flask import Flask
from flask import Blueprint

app = Flask(__name__)
app.config['SERVER_NAME'] = 'flask.dev:5000'

@app.route('/')
def hello_world():
    return 'Hello World!'

# Blueprint declaration
bp = Blueprint('subdomain', __name__, subdomain="<user>")

# Add a route to the blueprint
@bp.route("/")
def home(user):
    return 'Welcome to your subdomain, {}'.format(user)

# Register the blueprint into the application
app.register_blueprint(bp)

if __name__ == '__main__':
    app.run(debug=True)

Start the server and see what happens when you go to flask.dev:5000 and then test.flask.dev:5000. Same uri, different subdomain, different behaviour ! Now you can start doing some useful stuff. I'm pretty sure you have tons of idea on how to use the user variable you get. And of course, you're not forced to use a dynamic subdomain, you can also declare your blueprint with just a string in the subdomain parameter.

Example architecture

.
├── app
│   ├── api
│   ├── forms
│   ├── models
│   ├── modules
│   │   └── blog
│   ├── static
│   │   ├── css
│   │   │   └── syntax
│   │   ├── fonts
│   │   ├── img
│   │   └── js
│   ├── templates
│   │   └── blog
│   ├── utils
│   └── views
├── database
└── env

As you can see, the only blueprint I'm using is located in the modules/blog subdirectory. It's organized as a standard application, views, forms, etc...


Part III : Nginx side.


Note : Remember to change the SERVER_NAME configuration variable to match your actual domain name in production

Your application is ready, you know what to do with your dynamic subdomain. There is still one problem left though. Nginx. What happens if someones goes to www.yourdomain.com ? Your application will think www is a subdomain but it's actually not. So what are you going to do about that ? Simple. Strip the www part and redirect to the url without it but keeping the subdomain. Here is how I did that for MarkdownBlog :

server {
    listen 80;
    listen 443 ssl;

    ssl_certificate /usr/local/nginx/ssl/nginx.crt;
    ssl_certificate_key /usr/local/nginx/ssl/nginx.key;

    server_name ~^www\.(?<user>.+\.)?markdownblog\.com$;
    return 301 "$scheme://${user}markdownblog.com$request_uri";
}

server {
       listen 80;
       listen 443 ssl;

       ssl_certificate /usr/local/nginx/ssl/nginx.crt;
       ssl_certificate_key /usr/local/nginx/ssl/nginx.key;

       server_name ~^.+\.markdownblog\.com$ markdownblog.com;

       location / {
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://127.0.0.1:8085;
    }
}

I spent hours on that. The fact is that, the regex was correct but was never executed. As said in the Nginx Documentation about Wildcards Server Names, you can use the .domain.com to match every subdomain. This also includes the www.domain.com, which I don't want, otherwise my application would think www is a user (and a blog url) which is wrong. Fact is that the .domain.com syntax isn't considered as a regex. Nginx executes regex tests if all the over url checks failed. This behaviour made my regex pointless as it was not even executed by nginx. That configuration is used to catch the username part in the url and strip out the www part.