smokex

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 26, 2026 License: MIT Imports: 7 Imported by: 0

README

smokex

A compact, sigil-based DSL for expressing port sets in Go.

SmokeX turns patterns like ~!$0:1023!#8080 or @web@k8s-api into lazy iter.Seq[int] iterators — no intermediate slices, context-aware, and safe for concurrent use.

~!$0:1023          → all 64512 non-privileged ports
#80#443$8000:8999  → 80, 443, and 8000–8999
@web!#8080         → web alias minus 8080
$1024:65535!$9000:9100!#8080  → range with layered exclusions

Requirements

  • Go 1.23 or later (iter.Seq and range-over-func)

Installation

go get github.com/buzzlightyear1309/smokex-ports

Quick start

package main

import (
	"context"
	"fmt"
	"github.com/buzzlightyear1309/smokex-ports"
)

func main() {
	ps := smokex.MustParse("$8000:8010!#8005")

	fmt.Println(ps.Len())    // 10
	fmt.Println(ps.String()) // $8000:8004$8006:8010

	for port := range ps.All(context.Background()) {
		fmt.Println(port)
	}
}

Sigil reference

Sigil Meaning Example Resolves to
#<port> Single port #443 443
$<lo>:<hi> Inclusive range $8000:8003 8000 8001 8002 8003
~ All ports (0–65535) ~ 0 … 65535
!#<port> Exclude single port $8000:8003!#8001 8000 8002 8003
!$<lo>:<hi> Exclude range $0:10!$3:6 0 1 2 7 8 9 10
@<n> Named alias @https 443 4443 8443

Exclusion binding: ! always binds to the immediately preceding $ or ~ token. A bare #port cannot carry exclusions — #80!#443 is a parse error.

Spaces anywhere in the expression are stripped before parsing, so $ 8000 : 8010 ! # 8005 is valid.


API

Parsing
// Parse compiles a SmokeX expression. Returns a descriptive ParseError on failure.
ps, err := smokex.Parse("~!#22!#3389")

// MustParse panics on error. Useful for package-level vars and test fixtures.
var privileged = smokex.MustParse("$0:1023")

ParseError carries both a human-readable message and the byte position in the (space-stripped) input where parsing failed:

ps, err := smokex.Parse("$500:100") // start > end
var pe *smokex.ParseError
if errors.As(err, &pe) {
fmt.Println(pe.Pos, pe.Msg)
}
Iterating — iter.Seq[int]
ctx := context.Background()

for port := range ps.All(ctx) {
scan(port)
}

All yields ports in ascending order. It stops early if the context is cancelled or the caller's range body executes break:

// Stop after the first match
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

for port := range ps.All(ctx) {
if isOpen(port) {
fmt.Println("first open port:", port)
cancel()
}
}
Membership — Contains

O(log n) binary search on the normalised interval list.

ps := smokex.MustParse("$1024:65535!$9000:9100")
ps.Contains(8080)  // true
ps.Contains(9050)  // false — excluded
ps.Contains(70000) // false — out of range
Cardinality — Len

O(1). Computed once at parse time.

smokex.MustParse("~").Len()           // 65536
smokex.MustParse("~!$0:1023").Len()  // 64512
smokex.MustParse("#80#443").Len()     // 2
Materialising — ToSlice

Pre-allocates exactly Len() capacity. Respects context cancellation.

ports := smokex.MustParse("#22#80#443").ToSlice(context.Background())
// []int{22, 80, 443}
Canonical form — String

String() returns a minimal, round-trippable SmokeX expression. Overlapping inputs are merged; duplicates are removed.

ps := smokex.MustParse("#80#80$0:100$50:200")
ps.String() // "$0:200"
ps.Len()    // 201

// Round-trip guarantee
ps2, _ := smokex.Parse(ps.String())
ps2.Len() == ps.Len() // always true

Interval normalisation

After parsing, SmokeX merges all base tokens and exclusions into a sorted, non-overlapping list of closed intervals. Consequences:

  • Duplicates (#80#80) are silently deduplicated — one port.
  • Overlapping ranges ($0:100$50:200) are coalesced — $0:200.
  • Adjacent ranges ($10:20$21:30) are merged — $10:30.
  • A single port inside a range (#80$70:100) is not double-counted.
  • Contains is O(log n); Len is O(1).

Named aliases

Aliases expand to a SmokeX pattern before parsing. They can be combined with other tokens and carry exclusions.

smokex.MustParse("@ssh")           // #22
smokex.MustParse("@web!#8080")     // #80#443#8443
smokex.MustParse("@ssh@web")       // #22#80#443#8080#8443
smokex.MustParse("@vnc!#5905")     // $5900:5904$5906:5910
Built-in aliases
Alias Expands to
@http #80
@https #443#8443#4443
@http-alt #8080#8008
@web #80#443#8080#8443
@ssh #22
@rdp #3389
@vnc $5900:5910
@telnet #23
@dns #53
@ftp #20#21
@smtp #25#465#587
@imap #143#993
@pop3 #110#995
@mail #25#465#587#143#993#110#995
@mysql #3306
@postgres #5432
@mssql #1433
@oracle #1521
@redis #6379
@mongodb #27017
@elastic #9200#9300
@ldap #389#636
@k8s-api #6443#8443
@k8s-node $10250:10255
@etcd #2379#2380
@docker #2375#2376
@prometheus #9090#9091
@grafana #3000
@alertmanager #9093
@kafka $9092:9093
@rabbitmq #5672#5671#15672
@nats #4222#6222#8222
@vault #8200#8201
@consul #8300#8301#8500#8501#8600
Registering custom aliases

Register validates the expansion pattern before committing it. Aliases are global and safe to register concurrently.

// Register once at startup (e.g. in an init function)
if err := smokex.Register("@myapp", "#9000#9001$9100:9110"); err != nil {
log.Fatal(err)
}

ps := smokex.MustParse("@myapp!#9105")
ps.Len()    // 12
ps.String() // #9000#9001$9100:9104$9106:9110

Aliases cannot reference other aliases — one level of expansion only. Circular or chained aliases are rejected at registration time.

Inspecting the registry
all := smokex.Aliases() // returns a map[string]string snapshot
fmt.Println(len(all))   // 33 built-ins + any custom registrations

Concurrency

*PortSet is immutable after Parse returns. All, Contains, Len, String, and ToSlice are safe to call concurrently from any number of goroutines without additional synchronisation.

The alias registry (Register, Aliases, and alias expansion during Parse) uses an internal sync.RWMutex and is also concurrency-safe.


Nil safety

All *PortSet methods are nil-safe:

var ps *smokex.PortSet
ps.Len()                          // 0
ps.Contains(80)                   // false
ps.String()                       // ""
ps.ToSlice(context.Background())  // nil
for range ps.All(ctx) {}          // iterates zero times

Error reference

All parse failures return *ParseError with a byte position:

Input Error
"" empty expression
"#99999" port 99999 out of range [0, 65535]
"$500:100" range start 500 > end 100
"$60000:70000" port 70000 out of range [0, 65535]
"#" expected digit at position 1
"$10001000" $ range missing : after 10001000
"!#80" ! exclusion must follow a $ range or ~ wildcard
"$0:100!" ! at end of input with no target
"~1024" ~ wildcard takes no arguments
"@unknown" unknown alias "@unknown"

License

MIT

Documentation

Overview

Package smokex implements the SmokeX sigil-based port pattern language.

SmokeX lets you express complex port sets in a compact, unambiguous string:

#80#443                          → ports 80 and 443
$1024:65535                      → range 1024–65535
$1024:65535!#8080                → range minus port 8080
$1024:65535!$9000:9100!#8080     → range minus sub-range and a single port
~!#22!#3389                      → all ports except SSH and RDP
#80#443$8000:8999!#8080          → 80, 443, and 8000–8999 except 8080
@https                           → named alias expanding to #443#8443#4443
@web!#8080                       → alias with exclusion

Sigil reference

#<port>         single port (no exclusions allowed)     #443
$<lo>:<hi>      inclusive range                         $8000:8090
~               all ports 0–65535                       ~
!#<port>        exclude single port from preceding base !#22
!$<lo>:<hi>     exclude range from preceding base       !$9000:9100
@<name>         named alias (expands before parsing)    @https

Exclusions bind to the immediately preceding $ or ~ token. A bare #port cannot carry exclusions.

Interval normalisation

After parsing, overlapping and duplicate ranges are merged into a sorted, non-overlapping list of intervals. This means:

  • Duplicate ports (#80#80) are silently deduplicated.
  • Overlapping ranges ($0:100$50:200) are coalesced into $0:200.
  • Contains() is O(log n) via binary search.
  • Len() is O(1) after parse.
  • String() produces a canonical, minimal representation.

Thread safety

A *PortSet is immutable after Parse returns. All methods (Contains, All, Len, String, Iter) are safe to call concurrently from multiple goroutines. The alias registry uses its own RWMutex and is also concurrency-safe.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Aliases

func Aliases() map[string]string

Aliases returns a snapshot of all currently registered aliases.

func Register

func Register(name, pattern string) error

Register adds or overwrites a named alias in the global registry. The name must begin with '@'. The expansion must be a valid SmokeX pattern. Aliases may not reference other aliases (one level of expansion only).

smokex.Register("@myapp", "#9000#9001")

Types

type ParseError

type ParseError struct {
	Pos int
	Msg string
}

ParseError reports the position in the (space-stripped) input where parsing failed and a human-readable explanation.

func (*ParseError) Error

func (e *ParseError) Error() string

type PortSet

type PortSet struct {
	// contains filtered or unexported fields
}

PortSet is the compiled, normalised representation of a SmokeX expression. It is immutable after creation and safe for concurrent use.

func MustParse

func MustParse(expr string) *PortSet

MustParse is like Parse but panics on error. Useful for package-level vars and test fixtures.

func Parse

func Parse(expr string) (*PortSet, error)

Parse compiles a SmokeX expression into a *PortSet.

Leading/trailing whitespace and internal spaces are stripped before parsing, so "# 80 $ 443:8443" is equivalent to "#80$443:8443".

func (*PortSet) All

func (ps *PortSet) All(ctx context.Context) iter.Seq[int]

All returns a context-aware iterator that yields each port in ascending order. Iteration stops when ctx is cancelled or the caller returns false. Safe to call on a nil *PortSet (yields nothing).

for port := range ps.All(ctx) {
    fmt.Println(port)
}

func (*PortSet) Contains

func (ps *PortSet) Contains(port int) bool

Contains reports whether port is in the set. O(log n). Safe to call on a nil *PortSet (returns false).

func (*PortSet) Len

func (ps *PortSet) Len() int

Len returns the total number of ports in the set. O(1). Safe to call on a nil *PortSet (returns 0).

func (*PortSet) String

func (ps *PortSet) String() string

String returns a canonical, minimal SmokeX representation of the set. Single-port intervals are rendered as #port; multi-port as $lo:hi. The result round-trips through Parse. Safe to call on a nil *PortSet (returns "").

func (*PortSet) ToSlice

func (ps *PortSet) ToSlice(ctx context.Context) []int

ToSlice materialises all ports into a []int pre-allocated to Len(). Respects context cancellation; may return a partial slice. Safe to call on a nil *PortSet (returns nil).

Directories

Path Synopsis
cmd
demo command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL