Files
CHORUS/pkg/ucxl/address.go
anthonyrawlins 543ab216f9 Complete BZZZ functionality port to CHORUS
🎭 CHORUS now contains full BZZZ functionality adapted for containers

Core systems ported:
- P2P networking (libp2p with DHT and PubSub)
- Task coordination (COOEE protocol)
- HMMM collaborative reasoning
- SHHH encryption and security
- SLURP admin election system
- UCXL content addressing
- UCXI server integration
- Hypercore logging system
- Health monitoring and graceful shutdown
- License validation with KACHING

Container adaptations:
- Environment variable configuration (no YAML files)
- Container-optimized logging to stdout/stderr
- Auto-generated agent IDs for container deployments
- Docker-first architecture

All proven BZZZ P2P protocols, AI integration, and collaboration
features are now available in containerized form.

Next: Build and test container deployment.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-02 20:02:37 +10:00

369 lines
10 KiB
Go

package ucxl
import (
"fmt"
"regexp"
"strconv"
"strings"
)
// Address represents a parsed UCXL address
// Format: ucxl://agent:role@project:task/temporal_segment/path
type Address struct {
// Core components
Agent string `json:"agent"`
Role string `json:"role"`
Project string `json:"project"`
Task string `json:"task"`
// Temporal component
TemporalSegment TemporalSegment `json:"temporal_segment"`
// Path component
Path string `json:"path"`
// Original raw address for reference
Raw string `json:"raw"`
}
// TemporalSegment represents temporal navigation information
type TemporalSegment struct {
Type TemporalType `json:"type"`
Direction Direction `json:"direction,omitempty"`
Count int `json:"count,omitempty"`
}
// TemporalType defines the type of temporal navigation
type TemporalType string
const (
TemporalLatest TemporalType = "latest" // *^
TemporalAny TemporalType = "any" // *~
TemporalSpecific TemporalType = "specific" // *~N
TemporalRelative TemporalType = "relative" // ~~N, ^^N
)
// Direction defines temporal navigation direction
type Direction string
const (
DirectionBackward Direction = "backward" // ~~
DirectionForward Direction = "forward" // ^^
)
// ValidationError represents an address validation error
type ValidationError struct {
Field string
Message string
Raw string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("UCXL address validation error in %s: %s (address: %s)", e.Field, e.Message, e.Raw)
}
// Regular expressions for validation
var (
// Component validation patterns
componentPattern = regexp.MustCompile(`^[a-zA-Z0-9_\-]+$|^any$`)
pathPattern = regexp.MustCompile(`^[a-zA-Z0-9_\-/\.]*$`)
// Temporal segment patterns
temporalLatestPattern = regexp.MustCompile(`^\*\^$`) // *^
temporalAnyPattern = regexp.MustCompile(`^\*~$`) // *~
temporalSpecificPattern = regexp.MustCompile(`^\*~(\d+)$`) // *~N
temporalBackwardPattern = regexp.MustCompile(`^~~(\d+)$`) // ~~N
temporalForwardPattern = regexp.MustCompile(`^\^\^(\d+)$`) // ^^N
// Full address pattern for initial validation
ucxlAddressPattern = regexp.MustCompile(`^ucxl://([^:]+):([^@]+)@([^:]+):([^/]+)/([^/]+)/?(.*)$`)
)
// Parse parses a UCXL address string into an Address struct
func Parse(address string) (*Address, error) {
if address == "" {
return nil, &ValidationError{
Field: "address",
Message: "address cannot be empty",
Raw: address,
}
}
// Normalize the address (trim whitespace, convert to lowercase for scheme)
normalized := strings.TrimSpace(address)
if !strings.HasPrefix(strings.ToLower(normalized), "ucxl://") {
return nil, &ValidationError{
Field: "scheme",
Message: "address must start with 'ucxl://'",
Raw: address,
}
}
// Check scheme manually since our format doesn't follow standard URL format
if !strings.HasPrefix(strings.ToLower(normalized), "ucxl://") {
return nil, &ValidationError{
Field: "scheme",
Message: "scheme must be 'ucxl'",
Raw: address,
}
}
// Use regex for detailed component extraction
// Convert to lowercase for scheme but keep original for case-sensitive parts
normalizedForPattern := strings.ToLower(normalized[:7]) + normalized[7:] // normalize "ucxl://" part
matches := ucxlAddressPattern.FindStringSubmatch(normalizedForPattern)
if matches == nil || len(matches) != 7 {
return nil, &ValidationError{
Field: "format",
Message: "address format must be 'ucxl://agent:role@project:task/temporal_segment/path'",
Raw: address,
}
}
addr := &Address{
Agent: normalizeComponent(matches[1]),
Role: normalizeComponent(matches[2]),
Project: normalizeComponent(matches[3]),
Task: normalizeComponent(matches[4]),
Path: matches[6], // Path can be empty
Raw: address,
}
// Parse temporal segment
temporalSegment, err := parseTemporalSegment(matches[5])
if err != nil {
return nil, &ValidationError{
Field: "temporal_segment",
Message: err.Error(),
Raw: address,
}
}
addr.TemporalSegment = *temporalSegment
// Validate all components
if err := addr.Validate(); err != nil {
return nil, err
}
return addr, nil
}
// parseTemporalSegment parses the temporal segment component
func parseTemporalSegment(segment string) (*TemporalSegment, error) {
if segment == "" {
return nil, fmt.Errorf("temporal segment cannot be empty")
}
// Check for latest (*^)
if temporalLatestPattern.MatchString(segment) {
return &TemporalSegment{Type: TemporalLatest}, nil
}
// Check for any (*~)
if temporalAnyPattern.MatchString(segment) {
return &TemporalSegment{Type: TemporalAny}, nil
}
// Check for specific version (*~N)
if matches := temporalSpecificPattern.FindStringSubmatch(segment); matches != nil {
count, err := strconv.Atoi(matches[1])
if err != nil {
return nil, fmt.Errorf("invalid version number in specific temporal segment: %s", matches[1])
}
if count < 0 {
return nil, fmt.Errorf("version number cannot be negative: %d", count)
}
return &TemporalSegment{
Type: TemporalSpecific,
Count: count,
}, nil
}
// Check for backward navigation (~~N)
if matches := temporalBackwardPattern.FindStringSubmatch(segment); matches != nil {
count, err := strconv.Atoi(matches[1])
if err != nil {
return nil, fmt.Errorf("invalid count in backward temporal segment: %s", matches[1])
}
if count < 0 {
return nil, fmt.Errorf("backward count cannot be negative: %d", count)
}
return &TemporalSegment{
Type: TemporalRelative,
Direction: DirectionBackward,
Count: count,
}, nil
}
// Check for forward navigation (^^N)
if matches := temporalForwardPattern.FindStringSubmatch(segment); matches != nil {
count, err := strconv.Atoi(matches[1])
if err != nil {
return nil, fmt.Errorf("invalid count in forward temporal segment: %s", matches[1])
}
if count < 0 {
return nil, fmt.Errorf("forward count cannot be negative: %d", count)
}
return &TemporalSegment{
Type: TemporalRelative,
Direction: DirectionForward,
Count: count,
}, nil
}
return nil, fmt.Errorf("invalid temporal segment format: %s", segment)
}
// normalizeComponent normalizes address components (case-insensitive)
func normalizeComponent(component string) string {
return strings.ToLower(strings.TrimSpace(component))
}
// Validate validates the Address components according to BNF grammar rules
func (a *Address) Validate() error {
// Validate agent component
if err := validateComponent("agent", a.Agent); err != nil {
return &ValidationError{
Field: "agent",
Message: err.Error(),
Raw: a.Raw,
}
}
// Validate role component
if err := validateComponent("role", a.Role); err != nil {
return &ValidationError{
Field: "role",
Message: err.Error(),
Raw: a.Raw,
}
}
// Validate project component
if err := validateComponent("project", a.Project); err != nil {
return &ValidationError{
Field: "project",
Message: err.Error(),
Raw: a.Raw,
}
}
// Validate task component
if err := validateComponent("task", a.Task); err != nil {
return &ValidationError{
Field: "task",
Message: err.Error(),
Raw: a.Raw,
}
}
// Validate path component (can be empty)
if a.Path != "" && !pathPattern.MatchString(a.Path) {
return &ValidationError{
Field: "path",
Message: "path can only contain alphanumeric characters, underscores, hyphens, forward slashes, and dots",
Raw: a.Raw,
}
}
return nil
}
// validateComponent validates individual address components
func validateComponent(name, component string) error {
if component == "" {
return fmt.Errorf("%s cannot be empty", name)
}
if !componentPattern.MatchString(component) {
return fmt.Errorf("%s can only contain alphanumeric characters, underscores, hyphens, or be 'any'", name)
}
return nil
}
// String returns the canonical string representation of the address
func (a *Address) String() string {
temporalStr := a.TemporalSegment.String()
if a.Path != "" {
return fmt.Sprintf("ucxl://%s:%s@%s:%s/%s/%s", a.Agent, a.Role, a.Project, a.Task, temporalStr, a.Path)
}
return fmt.Sprintf("ucxl://%s:%s@%s:%s/%s", a.Agent, a.Role, a.Project, a.Task, temporalStr)
}
// String returns the string representation of the temporal segment
func (ts *TemporalSegment) String() string {
switch ts.Type {
case TemporalLatest:
return "*^"
case TemporalAny:
return "*~"
case TemporalSpecific:
return fmt.Sprintf("*~%d", ts.Count)
case TemporalRelative:
if ts.Direction == DirectionBackward {
return fmt.Sprintf("~~%d", ts.Count)
}
return fmt.Sprintf("^^%d", ts.Count)
default:
return "*^" // Default to latest
}
}
// IsWildcard returns true if the address uses wildcard patterns
func (a *Address) IsWildcard() bool {
return a.Agent == "any" || a.Role == "any" || a.Project == "any" || a.Task == "any"
}
// Matches returns true if this address matches the pattern address
// Supports wildcard matching where "any" matches any value
func (a *Address) Matches(pattern *Address) bool {
if pattern == nil {
return false
}
// Check each component for wildcard or exact match
if pattern.Agent != "any" && a.Agent != pattern.Agent {
return false
}
if pattern.Role != "any" && a.Role != pattern.Role {
return false
}
if pattern.Project != "any" && a.Project != pattern.Project {
return false
}
if pattern.Task != "any" && a.Task != pattern.Task {
return false
}
// Path matching (if pattern has path, address must match or be subset)
if pattern.Path != "" {
if a.Path == "" {
return false
}
// Simple prefix matching for paths
if !strings.HasPrefix(a.Path, pattern.Path) {
return false
}
}
return true
}
// Clone creates a deep copy of the address
func (a *Address) Clone() *Address {
return &Address{
Agent: a.Agent,
Role: a.Role,
Project: a.Project,
Task: a.Task,
TemporalSegment: a.TemporalSegment, // TemporalSegment is a value type, safe to copy
Path: a.Path,
Raw: a.Raw,
}
}
// IsValid performs comprehensive validation and returns true if the address is valid
func (a *Address) IsValid() bool {
return a.Validate() == nil
}