Přeskočit na obsah

Tato stránka byla automaticky přeložena z angličtiny, jediného jazyka, ve kterém se tento web píše. Číst originál.

mesh.link.sync

Replikační kolo, které propojený runtime posílá při každém heartbeatu, podepsané pod jeho id odkazu s rostoucím čítačem: jeho značky a události, které tomuto runtime chybí. Přijme se — ověří od začátku do konce, deduplikuje, aplikuje v pořadí streamu — a odpoví se podepsaně se značkami tohoto runtime a událostmi, které chybí peerovi. Neznámému odkazu nebo restartovanému peerovi se řekne, aby pozdravil znovu.

Replikační kolo, které propojený runtime posílá při každém heartbeatu, podepsané pod jeho id odkazu s rostoucím čítačem: jeho značky a události, které tomuto runtime chybí. Přijme se — ověří od začátku do konce, deduplikuje, aplikuje v pořadí streamu — a odpoví se podepsaně se značkami tohoto runtime a událostmi, které chybí peerovi. Neznámému odkazu nebo restartovanému peerovi se řekne, aby pozdravil znovu.

  • command
  • experimentální
  • modul mesh
  • #mesh
  • #cooperation
  • #link

Zpřístupnění

Kde je tato jedna definice dosažitelná. Absence je explicitní: povrch, který není uveden, ji nenese.

povrchjako
MCP—
HTTPPOST /api/v1/mesh/link/sync operationId mesh.link.sync
příkazová řádka—

Schémata

Kanonický vstup a výstup z typů Rustu; schéma nástroje MCP a parametry a odpovědi OpenAPI se odvozují z nich.

vstup · Podepsáno

Podepsaná zpráva: tělo JSON a podpis Ed25519 nad jeho kanonickými bajty pod doménou zprávy. Tělo zůstává JSON, aby pole, která přidá novější peer, přežila zdejší ověření beze změny.

Uchování těla jako JSON, a ne jako bajtů, které byly podepsány, činí protokol rozšiřitelným: pole, které přidal novější peer, projde ověřením nedotčené, protože podpis se kontroluje nad kanonickou podobou všeho, co tam je, a ne nad tvarem, který tato verze zná.

use majordomus_cli::mesh::identity::NodeIdentity;
use majordomus_cli::mesh::link::{sign, verify_signed, Domain, Signed};

let node = NodeIdentity::ephemeral().unwrap();
let signed: Signed = sign(&node, Domain::SyncRequest, serde_json::json!({ "b": 2, "a": 1 }));
assert_eq!(signed.sig.len(), 128, "hex Ed25519");

// key order is not content, so a round trip through JSON still verifies
let wire = serde_json::to_string(&signed).unwrap();
let back: Signed = serde_json::from_str(&wire).unwrap();
assert!(verify_signed(&node.public.public_key, Domain::SyncRequest, &back));
vlastnosttyppovinnépopis
tělo object ano Zpráva.
sig string ano Hex Ed25519 přes doménu a kanonický JSON body.
JSON Schema
{
  "description": "A signed message: a JSON body and the Ed25519 signature over its canonical bytes under\nthe message's domain. The body stays JSON so that fields a newer peer adds survive\nverification here unchanged.\n\nKeeping the body as JSON rather than as the bytes that were signed is what makes the\nprotocol extensible: a field a newer peer added is carried through verification\nuntouched, because the signature is checked over the canonical form of whatever is\nthere rather than over a shape this version knows.\n\n```\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::link::{sign, verify_signed, Domain, Signed};\n\nlet node = NodeIdentity::ephemeral().unwrap();\nlet signed: Signed = sign(&node, Domain::SyncRequest, serde_json::json!({ \"b\": 2, \"a\": 1 }));\nassert_eq!(signed.sig.len(), 128, \"hex Ed25519\");\n\n// key order is not content, so a round trip through JSON still verifies\nlet wire = serde_json::to_string(&signed).unwrap();\nlet back: Signed = serde_json::from_str(&wire).unwrap();\nassert!(verify_signed(&node.public.public_key, Domain::SyncRequest, &back));\n```",
  "properties": {
    "body": {
      "description": "The message."
    },
    "sig": {
      "description": "Hex Ed25519 over the domain and the canonical JSON of `body`.",
      "type": "string"
    }
  },
  "required": [
    "body",
    "sig"
  ],
  "title": "Signed",
  "type": "object"
}

výstup · LinkReply

Co hello nebo sync odpovídá po drátě: podepsanou zprávu nebo odmítnutí. Obojí jsou úspěšné odpovědi — transport je nese stejně a ani jedno není chyba — protože odmítnutí je rozhodnutí, které tento protokol chce mít zaznamenané a viditelné, a odpověď, která by dorazila jako selhání HTTP, by se nedala odlišit od peera, který je mimo provoz.

use majordomus_cli::mesh::identity::NodeIdentity;
use majordomus_cli::mesh::link::{sign, Domain, LinkReply, RefusalCode};

let node = NodeIdentity::ephemeral().unwrap();
let accepted = LinkReply::accepted(sign(&node, Domain::Welcome, serde_json::json!({})));
assert!(accepted.signed.is_some() && accepted.refusal.is_none());

let refused = LinkReply::refused(RefusalCode::SelfLink, "this runtime dialled itself");
assert!(refused.signed.is_none());
assert_eq!(refused.refusal.unwrap().code, RefusalCode::SelfLink);
vlastnosttyppovinnépopis
odmítnutí jedno ze 2 ne Odmítnutí, když ne.
podepsáno jedno ze 2 ne Podepsaná odpověď welcome nebo sync, pokud byla přijata.
JSON Schema
{
  "$defs": {
    "LinkRefusal": {
      "description": "A refusal: the code, the reason in words, and the protocol range of the refuser so a\nversion mismatch is diagnosable from either end.\n\nCarrying the refuser's protocol range in every refusal, not only in the one about\nprotocols, is what makes a version problem visible from the side that has the log: the\ndialer sees what the answerer speaks without anyone having to read the other machine.\n\n```\nuse majordomus_cli::mesh::link::{LinkRefusal, RefusalCode, LINK_PROTOCOL_MAX};\n\nlet refusal = LinkRefusal::new(RefusalCode::Untrusted, \"the key is not in the allowlist\");\nassert_eq!(refusal.code, RefusalCode::Untrusted);\nassert_eq!(refusal.proto_max, LINK_PROTOCOL_MAX);\nassert_eq!(refusal.to_string(), \"untrusted: the key is not in the allowlist\");\n```",
      "properties": {
        "code": {
          "$ref": "#/$defs/RefusalCode",
          "description": "The rule that refused."
        },
        "detail": {
          "description": "Why, in words.",
          "type": "string"
        },
        "proto_max": {
          "description": "The refuser's newest protocol.",
          "format": "uint32",
          "minimum": 0,
          "type": "integer"
        },
        "proto_min": {
          "description": "The refuser's oldest protocol.",
          "format": "uint32",
          "minimum": 0,
          "type": "integer"
        }
      },
      "required": [
        "code",
        "detail",
        "proto_min",
        "proto_max"
      ],
      "type": "object"
    },
    "RefusalCode": {
      "description": "Why a link message was turned down. Every refusal is typed, counted and shown: a mesh\nthat refuses a peer says which rule did, instead of dropping a socket.\n\nThe codes are the diagnosis a person needs when two runtimes will not link, and they\nare deliberately distinct where the remedies differ: `Untrusted` is a key to add,\n`RepositoryMismatch` is two different repositories, `SelfLink` is a configuration that\ndials its own endpoint, and `UnknownLink` is not a failure at all but an instruction to\nsay hello again.\n\n```\nuse majordomus_cli::mesh::link::RefusalCode;\n\n// the wire word is the code's identity across surfaces, and it is stable\nassert_eq!(RefusalCode::RepositoryMismatch.as_str(), \"repository_mismatch\");\nassert_eq!(\n    serde_json::to_value(RefusalCode::Untrusted).unwrap(),\n    serde_json::json!(\"untrusted\"),\n);\nassert_ne!(RefusalCode::Untrusted, RefusalCode::RepositoryMismatch);\n```",
      "oneOf": [
        {
          "const": "malformed",
          "description": "Not the shape of the message.",
          "type": "string"
        },
        {
          "const": "oversized",
          "description": "Over `MAX_LINK_MESSAGE`.",
          "type": "string"
        },
        {
          "const": "protocol_unsupported",
          "description": "The protocol ranges do not meet.",
          "type": "string"
        },
        {
          "const": "signature",
          "description": "The signature does not verify.",
          "type": "string"
        },
        {
          "const": "stale",
          "description": "The timestamp is outside the skew window.",
          "type": "string"
        },
        {
          "const": "replay",
          "description": "A nonce or a counter already seen.",
          "type": "string"
        },
        {
          "const": "repository_mismatch",
          "description": "The peer serves another repository: the isolation rule.",
          "type": "string"
        },
        {
          "const": "untrusted",
          "description": "The peer's key is not trusted by this runtime's policy: discovery is not trust.",
          "type": "string"
        },
        {
          "const": "self_link",
          "description": "The peer is this very runtime.",
          "type": "string"
        },
        {
          "const": "not_active",
          "description": "This runtime's cooperation is not active.",
          "type": "string"
        },
        {
          "const": "unknown_link",
          "description": "The link id is unknown here: the answerer restarted or expired the link; say hello.",
          "type": "string"
        },
        {
          "const": "capacity",
          "description": "A bound of this runtime is full.",
          "type": "string"
        },
        {
          "const": "feature_unsupported",
          "description": "The peer lacks a feature the operation needs.",
          "type": "string"
        },
        {
          "const": "misaddressed",
          "description": "A hello addressed to another runtime: captured on its way there and replayed here.",
          "type": "string"
        }
      ]
    },
    "Signed": {
      "description": "A signed message: a JSON body and the Ed25519 signature over its canonical bytes under\nthe message's domain. The body stays JSON so that fields a newer peer adds survive\nverification here unchanged.\n\nKeeping the body as JSON rather than as the bytes that were signed is what makes the\nprotocol extensible: a field a newer peer added is carried through verification\nuntouched, because the signature is checked over the canonical form of whatever is\nthere rather than over a shape this version knows.\n\n```\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::link::{sign, verify_signed, Domain, Signed};\n\nlet node = NodeIdentity::ephemeral().unwrap();\nlet signed: Signed = sign(&node, Domain::SyncRequest, serde_json::json!({ \"b\": 2, \"a\": 1 }));\nassert_eq!(signed.sig.len(), 128, \"hex Ed25519\");\n\n// key order is not content, so a round trip through JSON still verifies\nlet wire = serde_json::to_string(&signed).unwrap();\nlet back: Signed = serde_json::from_str(&wire).unwrap();\nassert!(verify_signed(&node.public.public_key, Domain::SyncRequest, &back));\n```",
      "properties": {
        "body": {
          "description": "The message."
        },
        "sig": {
          "description": "Hex Ed25519 over the domain and the canonical JSON of `body`.",
          "type": "string"
        }
      },
      "required": [
        "body",
        "sig"
      ],
      "type": "object"
    }
  },
  "description": "What a hello or a sync answers over the wire: a signed message or a refusal. Both are\nsuccessful replies — the transport carries them the same way and neither is an error —\nbecause a refusal is a decision this protocol wants recorded and shown, and an answer\nthat arrived as an HTTP failure would be indistinguishable from a peer that is down.\n\n```\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::link::{sign, Domain, LinkReply, RefusalCode};\n\nlet node = NodeIdentity::ephemeral().unwrap();\nlet accepted = LinkReply::accepted(sign(&node, Domain::Welcome, serde_json::json!({})));\nassert!(accepted.signed.is_some() && accepted.refusal.is_none());\n\nlet refused = LinkReply::refused(RefusalCode::SelfLink, \"this runtime dialled itself\");\nassert!(refused.signed.is_none());\nassert_eq!(refused.refusal.unwrap().code, RefusalCode::SelfLink);\n```",
  "properties": {
    "refusal": {
      "anyOf": [
        {
          "$ref": "#/$defs/LinkRefusal"
        },
        {
          "type": "null"
        }
      ],
      "description": "The refusal, when not."
    },
    "signed": {
      "anyOf": [
        {
          "$ref": "#/$defs/Signed"
        },
        {
          "type": "null"
        }
      ],
      "description": "The signed welcome or sync answer, when accepted."
    }
  },
  "title": "LinkReply",
  "type": "object"
}

Politiky

benchmark
povinné — cíl na každém transportu, který expozice deklaruje; případy jsou ty ze vstupního typu
cache
vypnuto — každé volání spustí handler

Cíle benchmarku

Odvozeno z registru pro tento repozitář: jeden požadavek na transport a případy, které poskytuje typ vstupu. Celá matice je na stránce měření výkonu.

transportstatepřípadytargets
directpokryto1poškozeno
httppokryto1poškozeno

Prohledává názvy a popisy všech stránek, které tento web publikuje.