Reference Implementations

Complete, runnable implementations of the RCAN protocol in multiple languages.


Python (ContinuonBrain)

Full RURI parsing, role management, and RCAN client.

"""
RCAN Protocol Reference Implementation (Python)
"""
import re
import asyncio
import websockets
from dataclasses import dataclass
from typing import Optional
from enum import IntEnum

# RURI Pattern
RURI_PATTERN = re.compile(
    r'^rcan://([a-z0-9][a-z0-9.-]*[a-z0-9])/'
    r'([a-z0-9][a-z0-9-]*[a-z0-9])/'
    r'([a-z0-9][a-z0-9-]*[a-z0-9])/'
    r'([0-9a-f]{8}(?:-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})?)'
    r'(?::(d{1,5}))?'
    r'(/[a-z][a-z0-9/-]*)?$'
)

@dataclass
class RURI:
    """Robot Universal Resource Identifier"""
    registry: str
    manufacturer: str
    model: str
    device_id: str
    port: int = 8080
    capability: Optional[str] = None
    
    @classmethod
    def parse(cls, ruri_string: str) -> 'RURI':
        match = RURI_PATTERN.match(ruri_string)
        if not match:
            raise ValueError(f"Invalid RURI: {ruri_string}")
        return cls(
            registry=match.group(1),
            manufacturer=match.group(2),
            model=match.group(3),
            device_id=match.group(4),
            port=int(match.group(5)) if match.group(5) else 8080,
            capability=match.group(6)
        )
    
    @classmethod
    def is_valid(cls, ruri_string: str) -> bool:
        return RURI_PATTERN.match(ruri_string) is not None
    
    def __str__(self) -> str:
        s = f"rcan://{self.registry}/{self.manufacturer}/{self.model}/{self.device_id}"
        if self.port != 8080:
            s += f":{self.port}"
        if self.capability:
            s += self.capability
        return s

class Role(IntEnum):
    """RCAN Role Hierarchy"""
    GUEST = 1
    USER = 2
    LEASEE = 3
    OWNER = 4
    CREATOR = 5
    
    def can_access(self, required_role: 'Role') -> bool:
        return self.value >= required_role.value

# Usage
ruri = RURI.parse("rcan://continuon.cloud/continuon/companion-v1/d3a4b5c6")
print(f"Registry: {ruri.registry}")
print(f"Model: {ruri.model}")
print(f"Valid: {RURI.is_valid(str(ruri))}")

TypeScript (Node.js)

interface RURI {
  registry: string;
  manufacturer: string;
  model: string;
  deviceId: string;
  port: number;
  capability: string | null;
}

const RURI_REGEX = /^rcan:\/\/([a-z0-9][a-z0-9.-]*[a-z0-9])\/([a-z0-9][a-z0-9-]*[a-z0-9])\/([a-z0-9][a-z0-9-]*[a-z0-9])\/([0-9a-f]{8}(?:-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})?)(?::(\d{1,5}))?(\/[a-z][a-z0-9\/-]*)?$/;

function parseRURI(ruri: string): RURI {
  const match = ruri.match(RURI_REGEX);
  if (!match) throw new Error(`Invalid RURI: ${ruri}`);
  
  return {
    registry: match[1],
    manufacturer: match[2],
    model: match[3],
    deviceId: match[4],
    port: match[5] ? parseInt(match[5]) : 8080,
    capability: match[6] || null,
  };
}

function formatRURI(ruri: RURI): string {
  let s = `rcan://${ruri.registry}/${ruri.manufacturer}/${ruri.model}/${ruri.deviceId}`;
  if (ruri.port !== 8080) s += `:${ruri.port}`;
  if (ruri.capability) s += ruri.capability;
  return s;
}

enum Role { GUEST = 1, USER = 2, LEASEE = 3, OWNER = 4, CREATOR = 5 }

function canAccess(role: Role, required: Role): boolean {
  return role >= required;
}

Dart (Flutter/ContinuonAI)

enum Role { guest, user, leasee, owner, creator }

class RURI {
  final String registry;
  final String manufacturer;
  final String model;
  final String deviceId;
  final int port;
  final String? capability;

  RURI({
    required this.registry,
    required this.manufacturer,
    required this.model,
    required this.deviceId,
    this.port = 8080,
    this.capability,
  });

  static final _pattern = RegExp(
    r'^rcan://([a-z0-9][a-z0-9.-]*[a-z0-9])/([a-z0-9][a-z0-9-]*[a-z0-9])/([a-z0-9][a-z0-9-]*[a-z0-9])/([0-9a-f]{8}(?:-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})?)(?::(\d{1,5}))?(/[a-z][a-z0-9/-]*)?$'
  );

  factory RURI.parse(String ruri) {
    final match = _pattern.firstMatch(ruri);
    if (match == null) throw FormatException('Invalid RURI: $ruri');
    
    return RURI(
      registry: match.group(1)!,
      manufacturer: match.group(2)!,
      model: match.group(3)!,
      deviceId: match.group(4)!,
      port: match.group(5) != null ? int.parse(match.group(5)!) : 8080,
      capability: match.group(6),
    );
  }

  static bool isValid(String ruri) => _pattern.hasMatch(ruri);

  @override
  String toString() {
    var s = 'rcan://$registry/$manufacturer/$model/$deviceId';
    if (port != 8080) s += ':$port';
    if (capability != null) s += capability;
    return s;
  }
}

Installation

Python (pip)

# Coming soon
pip install rcan

Node.js (npm)

# Coming soon
npm install @rcan/protocol

Dart (pub)

# Coming soon
dependencies:
  rcan: ^1.0.0

Contributing

Want to add an implementation in another language?