A repo showing compiletime and runtime driver loading in Go.

Overview

Compiletime and Runtime drivers

This post explores adding and building drivers both at compiletime and runtime.

Go Register

When building web apps with Go, one of the first packages you probably encounter is database/sql. This package must be used in conjunction with a database driver like lib/pq for postgres.

The documentation for lib/pq provides a handy example for getting started.

import (
	"database/sql"

	_ "github.com/lib/pq"
)

func main() {
	connStr := "user=pqgotest dbname=pqgotest sslmode=verify-full"
	db, err := sql.Open("postgres", connStr)
	if err != nil {
		log.Fatal(err)
	}

	age := 21
	rows, err := db.Query("SELECT name FROM users WHERE age = $1", age)
	…
}

An interesting point about this snippet is the import with a leading _ - an "anonymous import". Why would we want to import a library if we don't plan on calling it? Well, the imported package still runs initialization meaning all variable declarations and init() functions are evaluated. If we inspect the init() of pg/conn.go, we see it interacts with a Register(...) method in database/sql.

func init() {
	sql.Register("postgres", &Driver{})
}

This is handy because it provides our common interface of database/sql with a driver for postgres. If you check out the source for sql.Register(...), you see it just stores that driver in map keyed by the provided string.

var (
	driversMu sync.RWMutex // mutex protects the drivers map during concurrent access
	drivers   = make(map[string]driver.Driver)
)

func Register(name string, driver driver.Driver) {
	driversMu.Lock()
	defer driversMu.Unlock()
	if driver == nil {
		panic("sql: Register driver is nil")
	}
	if _, dup := drivers[name]; dup {
		panic("sql: Register called twice for driver " + name)
	}
	drivers[name] = driver
}

Writing our own Drivers

Of course we can copy this pattern to create our own interfaces and drivers that magically wire themselves up.

Here's a very simple interface to a foreign exchange (forex) service.

type Currency string

const (
	USD Currency = "USD"
	CAD Currency = "CAD"
	EUR Currency = "EUR"
	GBP Currency = "GBP"
)

// ForexService is an interface that provides methods for querying foreign exchange rates.
type ForexService interface {
	// GetRate returns the exchange rate of a currency pair in basis points or an error if one occurred.
	GetRate(c1, c2 Currency) (int, error)
}

I've implemented drivers for this interface using both fawazahmed0/currency-api and freeforexapi. Just like the database example in the standard lib, you can anonymously import one of the drivers and use the ForexService.

package main

import (
	"fmt"

	"github.com/belljustin/register"
	_ "github.com/belljustin/register/drivers/freeforex"
)

func main() {
	forexService := register.Open("freeforex")
	rate, _ := forexService.GetRate(register.USD,register.CAD)
	fmt.Println(rate)  // outputs the rate in bips
}

Dynamic Loading

Building the above creates an executable with fixed behaviour at compile time. However, the Go compiler also features a buildmode that creates a Go plugin.

go build -buildmode=plugin -o ./bin/freeforex.so ./drivers/freeforex/plugin

You can then load this plugin at runtime using the std lib.

plugin.Open("./bin/freeforex.so")

This will run all the initialization but not the main() function of the opened package. Without compiling or deploying the application, you can add new functionality.

Though, it's worth noting if you try to re-open the same plugin path, it will simply return the existing path. Worse still, if you recompile the same package to another path and try to open that, it will result in an error.

panic: plugin.Open("plugins/freeforexV2"): plugin already loaded

At the time of writing, closing an existing plugin and reloading is not a supported feature. It will likely continue to be unsupported because one would have to keep track of all the references to the plugin and clean them up in order to avoid seg faults. So this is not a way to do hot-reloading or continuously deploy code without downtime.

Nonetheless, it is a cool way to load new functionality at runtime. Perhaps more practically, it allows for smaller binaries because you can build the main component, and individual plugins seperately. Then users can link only the individual plugins they want to use.

Owner
Justin Bell
Justin Bell
simple-jwt-provider - Simple and lightweight provider which exhibits JWTs, supports login, password-reset (via mail) and user management.

Simple and lightweight JWT-Provider written in go (golang). It exhibits JWT for the in postgres persisted user, which can be managed via api. Also, a password-reset flow via mail verification is available. User specific custom-claims also available for jwt-generation and mail rendering.

Max 24 Apr 25, 2022
Package gorilla/sessions provides cookie and filesystem sessions and infrastructure for custom session backends.

sessions gorilla/sessions provides cookie and filesystem sessions and infrastructure for custom session backends. The key features are: Simple API: us

Gorilla Web Toolkit 2.3k May 17, 2022
Package gorilla/securecookie encodes and decodes authenticated and optionally encrypted cookie values for Go web applications.

securecookie securecookie encodes and decodes authenticated and optionally encrypted cookie values. Secure cookies can't be forged, because their valu

Gorilla Web Toolkit 570 May 9, 2022
Certificate authority and access plane for SSH, Kubernetes, web applications, and databases

Teleport is an identity-aware, multi-protocol access proxy which understands SSH, HTTPS, Kubernetes API, MySQL and PostgreSQL wire protocols.

Teleport 11.7k May 12, 2022
🍪CookieMonster is a command-line tool and API for decoding and modifying vulnerable session cookies from several different frameworks.

?? CookieMonster CookieMonster is a command-line tool and API for decoding and modifying vulnerable session cookies from several different frameworks.

Ian Carroll 421 May 1, 2022
A simple and lightweight library for creating, formatting, manipulating, signing, and validating JSON Web Tokens in Go.

GoJWT - JSON Web Tokens in Go GoJWT is a simple and lightweight library for creating, formatting, manipulating, signing and validating Json Web Tokens

Toby 5 Feb 7, 2022
Authorization and authentication. Learning go by writing a simple authentication and authorization service.

Authorization and authentication. Learning go by writing a simple authentication and authorization service.

Dinesh Bhattarai 0 Jan 30, 2022
Package goth provides a simple, clean, and idiomatic way to write authentication packages for Go web applications.

Goth: Multi-Provider Authentication for Go Package goth provides a simple, clean, and idiomatic way to write authentication packages for Go web applic

Mark Bates 3.7k May 16, 2022
Safe, simple and fast JSON Web Tokens for Go

jwt JSON Web Token for Go RFC 7519, also see jwt.io for more. The latest version is v3. Rationale There are many JWT libraries, but many of them are h

cristaltech 541 May 16, 2022
Time-Based One-Time Password (TOTP) and HMAC-Based One-Time Password (HOTP) library for Go.

otpgo HMAC-Based and Time-Based One-Time Password (HOTP and TOTP) library for Go. Implements RFC 4226 and RFC 6238. Contents Supported Operations Read

Jose Torres 34 May 8, 2022
:closed_lock_with_key: Middleware for keeping track of users, login states and permissions

Permissions2 Middleware for keeping track of users, login states and permissions. Online API Documentation godoc.org Features and limitations Uses sec

Alexander F. Rødseth 456 May 11, 2022
Fast, secure and efficient secure cookie encoder/decoder

Encode and Decode secure cookies This package provides functions to encode and decode secure cookie values. A secure cookie has its value ciphered and

Christophe Meessen 56 May 18, 2022
[DEPRECATED] Go package authcookie implements creation and verification of signed authentication cookies.

Package authcookie import "github.com/dchest/authcookie" Package authcookie implements creation and verification of signed authentication cookies. Co

Dmitry Chestnykh 112 Nov 19, 2021
Basic and Digest HTTP Authentication for golang http

HTTP Authentication implementation in Go This is an implementation of HTTP Basic and HTTP Digest authentication in Go language. It is designed as a si

Lev Shamardin 516 May 9, 2022
Herbert Fischer 196 Nov 17, 2021
A library for performing OAuth Device flow and Web application flow in Go client apps.

oauth A library for Go client applications that need to perform OAuth authorization against a server, typically GitHub.com. Traditionally,

GitHub CLI 326 May 8, 2022
an SSO and OAuth / OIDC login solution for Nginx using the auth_request module

Vouch Proxy An SSO solution for Nginx using the auth_request module. Vouch Proxy can protect all of your websites at once. Vouch Proxy supports many O

Vouch 1.9k May 18, 2022
Interactive package manager and resource monitor designed for the GNU/Linux.

pkgtop is an interactive package manager & resource monitor tool designed for the GNU/Linux. Package management (install/upgrade/remove etc.) can be a

Orhun Parmaksız 244 May 14, 2022
a Framework for creating mesh networks using technologies and design patterns of Erlang/OTP in Golang

Ergo Framework Implementation of Erlang/OTP in Golang. Up to x5 times faster than original Erlang/OTP. The easiest drop-in replacement for your hot no

Taras Halturin 1.4k May 10, 2022