# How Are Transports Registered in OpenFlux: Complete Guide to the Factory Pattern

> Learn how transports register in OpenFlux using the factory pattern. Discover the central registry and self-registration process in this complete guide.

- Repository: [p1neappleXpress/OpenFlux](https://github.com/p1neappleXpress/OpenFlux)
- Tags: how-to-guide
- Published: 2026-09-14

---

**OpenFlux uses a central registry pattern where each transport package self-registers via an `init()` function that maps a string name to a factory function in the global `transportFactories` map defined in [`transport/transport.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/transport/transport.go).**

The OpenFlux messaging framework implements a pluggable transport architecture that allows new protocols to be added without modifying core application code. Understanding how transports register themselves is essential for extending the library or troubleshooting transport loading issues. This pattern leverages Go's package initialization system to build a declarative, self-organizing registry.

## The Central Transport Registry

At the heart of OpenFlux transport management lies a package-level map in [`transport/transport.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/transport/transport.go) that associates string identifiers with constructor functions. This registry enables runtime polymorphism, allowing the application to instantiate concrete transport implementations by name.

The registry structure consists of:

- **`transportFactories`**: A private `map[string]func(cfg TransportConfig) Transport` that stores factory functions
- **`RegisterTransport`**: A public helper that adds entries to the map
- **`NewTransport`**: A lookup function that instantiates transports by name

```go
// transport/transport.go
var transportFactories = map[string]func(cfg TransportConfig) Transport{}

// RegisterTransport adds a new transport type to the registry.
func RegisterTransport(name string, factory func(cfg TransportConfig) Transport) {
    transportFactories[name] = factory
}

// NewTransport looks up the name in the registry and creates the transport.
func NewTransport(name string, cfg TransportConfig) (Transport, error) {
    if f, ok := transportFactories[name]; ok {
        return f(cfg), nil
    }
    return nil, fmt.Errorf("transport %q not registered", name)
}

```

The `Transport` interface itself is defined in this same file, establishing the contract that all registered implementations must satisfy.

## Self-Registration via Package init()

Rather than requiring a central manifest file, OpenFlux employs Go's `init()` function mechanism to allow each transport package to self-register during program initialization. This decouples transport implementations from the core registry logic.

### The Registration Mechanism

When a transport package is imported (even with the blank identifier `_`), its `init()` function executes automatically, calling `RegisterTransport` with the transport's canonical name and a closure that returns a concrete implementation.

According to the source code in `p1neappleXpress/OpenFlux`, this pattern appears consistently across all transport implementations:

**Yandex Transport** ([`transport/yandex/yandex.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/transport/yandex/yandex.go)):

```go
func init() {
    RegisterTransport("yandex", func(cfg TransportConfig) Transport {
        return NewYandexTransport(cfg)
    })
}

```

**Oneme Transport** ([`transport/oneme/max_transport.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/transport/oneme/max_transport.go)):

```go
func init() {
    RegisterTransport("oneme", func(cfg TransportConfig) Transport {
        return NewMaxTransport(cfg)
    })
}

```

**Encrypted Transport** ([`transport/encrypted.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/transport/encrypted.go)):

```go
func init() {
    RegisterTransport("encrypted", func(cfg TransportConfig) Transport {
        return NewEncryptedTransport(cfg)
    })
}

```

This pattern also extends to other implementations like [`transport/cupsonline/cupsonline.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/transport/cupsonline/cupsonline.go), ensuring architectural consistency across the codebase.

## Instantiating Transports with NewTransport

Once registration is complete during program startup, the application retrieves transport instances through the `NewTransport` function. This function performs a map lookup and executes the stored factory function with the provided configuration.

```go
cfg := transport.DefaultConfig()
tr, err := transport.NewTransport("yandex", cfg)
if err != nil {
    // Handle unregistered transport error
    log.Fatal(err)
}
// tr now satisfies the Transport interface and is ready for use

```

The factory pattern allows the configuration object (`TransportConfig`) to be passed at instantiation time while keeping the registration logic free of configuration specifics.

## Complete Working Example

The following example demonstrates importing transports for their side effects (registration), creating instances by name, and registering custom transports at runtime:

```go
package main

import (
    "log"
    
    // Import for side effects to trigger init() registration
    _ "github.com/p1neappleXpress/OpenFlux/transport/yandex"
    _ "github.com/p1neappleXpress/OpenFlux/transport/oneme"
    
    "github.com/p1neappleXpress/OpenFlux/transport"
)

type MyCustomTransport struct {
    config transport.TransportConfig
}

func (m *MyCustomTransport) Start() error { return nil }
func (m *MyCustomTransport) Send(data []byte) error { return nil }
func (m *MyCustomTransport) Stop() error { return nil }

func main() {
    cfg := transport.DefaultConfig()
    
    // Create registered transports by name
    yandexTr, err := transport.NewTransport("yandex", cfg)
    if err != nil {
        log.Fatalf("failed to create yandex transport: %v", err)
    }
    
    // Register a custom transport at runtime
    transport.RegisterTransport("mycustom", func(c transport.TransportConfig) transport.Transport {
        return &MyCustomTransport{config: c}
    })
    
    // Instantiate the custom transport
    customTr, err := transport.NewTransport("mycustom", cfg)
    if err != nil {
        log.Fatalf("failed to create custom transport: %v", err)
    }
    
    // Use the transport
    if err := yandexTr.Start(); err != nil {
        log.Fatalf("failed to start: %v", err)
    }
    defer yandexTr.Stop()
    
    if err := yandexTr.Send([]byte("hello world")); err != nil {
        log.Printf("send error: %v", err)
    }
}

```

## Summary

- OpenFlux maintains a private `transportFactories` map in [`transport/transport.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/transport/transport.go) that stores factory functions keyed by string names.
- The `RegisterTransport` function populates this map, while `NewTransport` retrieves and executes factory functions to create concrete instances.
- Each transport package (such as `transport/yandex`, `transport/oneme`, and `transport/encrypted`) contains an `init()` function that self-registers by calling `RegisterTransport` with a closure constructor.
- This pattern eliminates hard-coded transport lists and allows third-party transports to integrate by simply importing the package and calling the registration API.
- Runtime registration is also supported, enabling dynamic plugin architectures.

## Frequently Asked Questions

### Where is the transport registry defined in OpenFlux?

The transport registry is defined in [`transport/transport.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/transport/transport.go) as a package-level variable `transportFactories` of type `map[string]func(cfg TransportConfig) Transport`. This file also contains the `RegisterTransport` and `NewTransport` functions that manage the registry operations.

### Can I register a custom transport at runtime?

Yes. You can call `transport.RegisterTransport(name, factory)` at any point after import. Pass a unique string identifier and a factory function that accepts `TransportConfig` and returns a type implementing the `Transport` interface. The transport becomes immediately available via `transport.NewTransport(name, cfg)`.

### What happens if I request an unregistered transport name?

The `NewTransport` function returns an error formatted as `transport "name" not registered` when the requested string key does not exist in the `transportFactories` map. This error handling prevents nil pointer panics and provides clear diagnostic information about missing imports or typos in transport names.

### Do all transport implementations follow the same registration pattern?

Yes. According to the source analysis of `p1neappleXpress/OpenFlux`, all built-in transports including Yandex, Oneme, and Encrypted follow the identical pattern: an `init()` function that calls `RegisterTransport` with a constructor closure. This consistency ensures predictable behavior across the transport subsystem.