package broker import ( "fmt" "strings" "github.com/novox/mesh-controller/internal/envfile" ) // Whether this mesh's own traffic is on the bus being built. // // **One switch, read in one place** (novox/hq ADR 0116 step 5). Every seam the bus change went // behind ships both implementations, and until the rollout every one of them chooses the bus the // mesh runs on today. This is what the rollout flips, and it is deliberately a single fact rather // than a fact per component: a controller whose outbound is on one bus and whose inbound is on the // other is a mesh that hears nothing, and no test of either half would catch it. // NATSVar is where the controller finds the bus being built. Unset is the ordinary case and means // the mesh runs on the bus it has always run on. const NATSVar = "MESH_BUS_NATS" // OnNATS is the address of the bus being built, and whether the mesh is on it. // // Read from the node's own settings rather than baked in, for the reason the broker's address is // (novox/hq 04-ISSUES/102): an address recorded once does not follow a node's ports. func OnNATS() (address string, on bool, err error) { address, err = envfile.Placed(NATSVar) if err != nil { return "", false, err } address = strings.TrimSpace(address) if address == "" { return "", false, nil } return address, true, nil } // CredentialIn reads the user and password out of a bus address, and the address without them. // // The controller's own credential arrives in its address, the way the old bus's does. Split out so the // controller can record a hash of what it is actually using: its user is created by the installer at a // bootstrap password, before the controller exists to mint one, and a composition that left itself out // would produce a bus the writer cannot connect to. func CredentialIn(address string) (user, password, bare string) { at := strings.LastIndex(address, "@") if at < 0 { return "", "", address } scheme := "" rest := address[:at] if i := strings.Index(rest, "://"); i >= 0 { scheme, rest = rest[:i+3], rest[i+3:] } user, password, _ = strings.Cut(rest, ":") return user, password, scheme + address[at+1:] } // BareAddress is a bus address with any credential stripped, for something that only needs to know // whether a server is answering there. func BareAddress(address string) string { _, _, bare := CredentialIn(address) if bare == "" { return address } if strings.Contains(bare, "://") { return bare } return "nats://" + bare } // BusAddress is where the mesh's bus is, with this process's credential, and refuses to be empty: // there is one bus, and a control plane without it can hold records and answer nothing (novox/hq // ADR 0131, design 28 task 5.5). func BusAddress() (string, error) { address, _, err := OnNATS() if err != nil { return "", err } if address == "" { return "", fmt.Errorf("this control plane has no %s, so it cannot reach the mesh's bus", NATSVar) } return address, nil }