Hub server
A hub server is the control plane of a NanoPing setup: nodes authenticate with it, and every node on the same hub can find and manage the others. Use this service to list the nodes on the hub, follow them as they come and go, remove nodes, and approve or reject nodes that ask to join. The node hosting the API must host the hub server or be authenticated with one, otherwise calls fail with FailedPrecondition.
Get nodes
Get the nodes authenticated with the hub server, optionally filtered.
- REST
- gRPC
/v1/nodesmetadata_filtersmap<string, NodeMetadataItem>Metadata filters keyed by metadata key. A node is included only if it has every key with an equal value of the same type. Leave empty to not filter by metadata.
service_filtersNodeService[]Service filters. A node is included only if it offers every listed service. Leave empty to not filter by service.
- TypeScript
- Python
- curl
import { NanopingClient } from "@nanoping/api";
const client = new NanopingClient({ baseUrl: "http://127.0.0.1:10565" });
const response = await client.hubServer.getNodes({
metadataFilters: {
key: {
bytesValue: ""
}
},
serviceFilters: [
"HUB_SERVER"
]
});
from nanoping_api import NanopingClient, NodeMetadataItem, NodeService
client = NanopingClient("http://127.0.0.1:10565")
response = client.hub_server.get_nodes(
metadata_filters={"key": NodeMetadataItem(string_value="example")},
service_filters=[NodeService.HUB_SERVER],
)
curl 'http://127.0.0.1:10565/v1/nodes'
/v1/nodes/searchmetadataFiltersmap<string, NodeMetadataItem>Metadata filters keyed by metadata key. A node is included only if it has every key with an equal value of the same type. Leave empty to not filter by metadata.
serviceFiltersNodeService[]Service filters. A node is included only if it offers every listed service. Leave empty to not filter by service.
- TypeScript
- Python
- curl
import { NanopingClient } from "@nanoping/api";
const client = new NanopingClient({ baseUrl: "http://127.0.0.1:10565" });
const response = await client.hubServer.getNodes({
metadataFilters: {
key: {
bytesValue: ""
}
},
serviceFilters: [
"HUB_SERVER"
]
});
from nanoping_api import NanopingClient, NodeMetadataItem, NodeService
client = NanopingClient("http://127.0.0.1:10565")
response = client.hub_server.get_nodes(
metadata_filters={"key": NodeMetadataItem(string_value="example")},
service_filters=[NodeService.HUB_SERVER],
)
curl -X POST 'http://127.0.0.1:10565/v1/nodes/search' \
-H 'Content-Type: application/json' \
-d '{
"metadataFilters": {
"key": {
"bytesValue": ""
}
},
"serviceFilters": [
"HUB_SERVER"
]
}'
nodesNode[]The nodes matching the filters.
rpc getNodes(GetNodesRequest) returns (GetNodesResponse)
Method /nanopinggrpc.hub.HubServerService/getNodes
metadata_filtersmap<string, NodeMetadataItem>Metadata filters keyed by metadata key. A node is included only if it has every key with an equal value of the same type. Leave empty to not filter by metadata.
service_filtersNodeService[]Service filters. A node is included only if it offers every listed service. Leave empty to not filter by service.
nodesNode[]The nodes matching the filters.
- Go
- Go (generated gRPC)
import (
client "github.com/nanoping-labs/nanoping-api-go/v11"
"github.com/nanoping-labs/nanoping-api-go/v11/hub_node"
"github.com/nanoping-labs/nanoping-api-go/v11/hub_server"
)
c, err := client.Connect("127.0.0.1:10432")
defer c.Close()
response, err := c.HubServer.GetNodes(ctx, &hub_server.GetNodesRequest{
MetadataFilters: map[string]*hub_node.NodeMetadataItem{
"key": &hub_node.NodeMetadataItem{
Value: &hub_node.NodeMetadataItem_StringValue{StringValue: "example"},
},
},
ServiceFilters: []hub_node.NodeService{
hub_node.NodeService_HUB_SERVER,
},
})
import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"github.com/nanoping-labs/nanoping-api-go/v11/hub_node"
"github.com/nanoping-labs/nanoping-api-go/v11/hub_server"
)
conn, err := grpc.NewClient("127.0.0.1:10432", grpc.WithTransportCredentials(insecure.NewCredentials()))
defer conn.Close()
stub := hub_server.NewHubServerServiceClient(conn)
response, err := stub.GetNodes(ctx, &hub_server.GetNodesRequest{
MetadataFilters: map[string]*hub_node.NodeMetadataItem{
"key": &hub_node.NodeMetadataItem{
Value: &hub_node.NodeMetadataItem_StringValue{StringValue: "example"},
},
},
ServiceFilters: []hub_node.NodeService{
hub_node.NodeService_HUB_SERVER,
},
})
Remove node
Remove a node from the hub server. This disconnects the node from the hub server and removes it from its networks.
- REST
- gRPC
/v1/nodes/{node_id}node_idstringId of the node to remove.
- TypeScript
- Python
- curl
import { NanopingClient } from "@nanoping/api";
const client = new NanopingClient({ baseUrl: "http://127.0.0.1:10565" });
await client.hubServer.removeNode({
nodeId: "3f2b1c9e-8d4a-4f6b-9c2e-1a7d5e8b0c4f"
});
from nanoping_api import NanopingClient
client = NanopingClient("http://127.0.0.1:10565")
client.hub_server.remove_node(node_id="3f2b1c9e-8d4a-4f6b-9c2e-1a7d5e8b0c4f")
curl -X DELETE 'http://127.0.0.1:10565/v1/nodes/<node_id>'
No fields.
rpc removeNode(RemoveNodeRequest) returns (RemoveNodeResponse)
Method /nanopinggrpc.hub.HubServerService/removeNode
node_idstringId of the node to remove.
No fields.
- Go
- Go (generated gRPC)
import (
client "github.com/nanoping-labs/nanoping-api-go/v11"
"github.com/nanoping-labs/nanoping-api-go/v11/hub_server"
)
c, err := client.Connect("127.0.0.1:10432")
defer c.Close()
_, err = c.HubServer.RemoveNode(ctx, &hub_server.RemoveNodeRequest{
NodeId: "3f2b1c9e-8d4a-4f6b-9c2e-1a7d5e8b0c4f",
})
import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"github.com/nanoping-labs/nanoping-api-go/v11/hub_server"
)
conn, err := grpc.NewClient("127.0.0.1:10432", grpc.WithTransportCredentials(insecure.NewCredentials()))
defer conn.Close()
stub := hub_server.NewHubServerServiceClient(conn)
_, err = stub.RemoveNode(ctx, &hub_server.RemoveNodeRequest{
NodeId: "3f2b1c9e-8d4a-4f6b-9c2e-1a7d5e8b0c4f",
})
Stream nodes
Stream the nodes authenticated with the hub server. The matching nodes are sent first, followed by an update every time a node is authenticated, deauthenticated, connects, disconnects or changes its details. Updates are not filtered. The stream stays open until the caller closes it.
- REST
- gRPC
/v1/streams/nodesServer-sent events. A : ready comment is sent when the stream is ready, then each message is a data: line holding the response below. A failure after that is an error event.
metadata_filtersmap<string, NodeMetadataItem>Metadata filters keyed by metadata key. A node is included only if it has every key with an equal value of the same type. Leave empty to not filter by metadata.
service_filtersNodeService[]Service filters. A node is included only if it offers every listed service. Leave empty to not filter by service.
- TypeScript
- Python
- curl
import { NanopingClient } from "@nanoping/api";
const client = new NanopingClient({ baseUrl: "http://127.0.0.1:10565" });
for await (const response of client.hubServer.streamNodes({
metadataFilters: {
key: {
bytesValue: ""
}
},
serviceFilters: [
"HUB_SERVER"
]
})) {
}
from nanoping_api import NanopingClient, NodeMetadataItem, NodeService
client = NanopingClient("http://127.0.0.1:10565")
for response in client.hub_server.stream_nodes(
metadata_filters={"key": NodeMetadataItem(string_value="example")},
service_filters=[NodeService.HUB_SERVER],
):
print(response)
curl -N 'http://127.0.0.1:10565/v1/streams/nodes'
/v1/streams/nodesServer-sent events. A : ready comment is sent when the stream is ready, then each message is a data: line holding the response below. A failure after that is an error event.
metadataFiltersmap<string, NodeMetadataItem>Metadata filters keyed by metadata key. A node is included only if it has every key with an equal value of the same type. Leave empty to not filter by metadata.
serviceFiltersNodeService[]Service filters. A node is included only if it offers every listed service. Leave empty to not filter by service.
- TypeScript
- Python
- curl
import { NanopingClient } from "@nanoping/api";
const client = new NanopingClient({ baseUrl: "http://127.0.0.1:10565" });
for await (const response of client.hubServer.streamNodes({
metadataFilters: {
key: {
bytesValue: ""
}
},
serviceFilters: [
"HUB_SERVER"
]
})) {
}
from nanoping_api import NanopingClient, NodeMetadataItem, NodeService
client = NanopingClient("http://127.0.0.1:10565")
for response in client.hub_server.stream_nodes(
metadata_filters={"key": NodeMetadataItem(string_value="example")},
service_filters=[NodeService.HUB_SERVER],
):
print(response)
curl -N -X POST 'http://127.0.0.1:10565/v1/streams/nodes' \
-H 'Content-Type: application/json' \
-d '{
"metadataFilters": {
"key": {
"bytesValue": ""
}
},
"serviceFilters": [
"HUB_SERVER"
]
}'
initialResponseStreamNodesInitialResponseone of responseSent once as the first message, with the nodes matching the filters when the stream opened.
updateResponseStreamNodesUpdateResponseone of responseSent for every later change to a node.
rpc streamNodes(GetNodesRequest) returns (stream StreamNodesResponse)
Method /nanopinggrpc.hub.HubServerService/streamNodes
metadata_filtersmap<string, NodeMetadataItem>Metadata filters keyed by metadata key. A node is included only if it has every key with an equal value of the same type. Leave empty to not filter by metadata.
service_filtersNodeService[]Service filters. A node is included only if it offers every listed service. Leave empty to not filter by service.
initialResponseStreamNodesInitialResponseone of responseSent once as the first message, with the nodes matching the filters when the stream opened.
updateResponseStreamNodesUpdateResponseone of responseSent for every later change to a node.
- Go
- Go (generated gRPC)
import (
client "github.com/nanoping-labs/nanoping-api-go/v11"
"github.com/nanoping-labs/nanoping-api-go/v11/hub_node"
"github.com/nanoping-labs/nanoping-api-go/v11/hub_server"
)
c, err := client.Connect("127.0.0.1:10432")
defer c.Close()
stream, err := c.HubServer.StreamNodes(ctx, &hub_server.GetNodesRequest{
MetadataFilters: map[string]*hub_node.NodeMetadataItem{
"key": &hub_node.NodeMetadataItem{
Value: &hub_node.NodeMetadataItem_StringValue{StringValue: "example"},
},
},
ServiceFilters: []hub_node.NodeService{
hub_node.NodeService_HUB_SERVER,
},
})
for response, err := range client.Receive(stream) {
if err != nil {
return err
}
}
import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"github.com/nanoping-labs/nanoping-api-go/v11/hub_node"
"github.com/nanoping-labs/nanoping-api-go/v11/hub_server"
)
conn, err := grpc.NewClient("127.0.0.1:10432", grpc.WithTransportCredentials(insecure.NewCredentials()))
defer conn.Close()
stub := hub_server.NewHubServerServiceClient(conn)
stream, err := stub.StreamNodes(ctx, &hub_server.GetNodesRequest{
MetadataFilters: map[string]*hub_node.NodeMetadataItem{
"key": &hub_node.NodeMetadataItem{
Value: &hub_node.NodeMetadataItem_StringValue{StringValue: "example"},
},
},
ServiceFilters: []hub_node.NodeService{
hub_node.NodeService_HUB_SERVER,
},
})
for {
response, err := stream.Recv()
if err != nil {
return err
}
}
Authentication by requests
Receive the authentication requests sent to the hub server on the node hosting the API, and accept or reject each one. Nothing is sent when the stream opens. A request is sent each time a node asks to authenticate, and the caller answers it by sending an answer for that request.
Use this on the node hosting the hub server to decide which nodes may join. Every node that calls authenticate by request arrives as a request. Answer it before the request times out; the node's call returns as soon as the answer is in.
- REST
- gRPC
/v1/streams/hub-server/authentication-requestsWebSocket. Send each request below as a JSON text message. Each message received holds a result with the response below, or an error.
requestIduint64Id of the request being answered, as received in the request.
acceptboolTrue to accept the request, false to reject it.
- TypeScript
- Python
- Message
import { NanopingClient, answerJoinRequests } from "@nanoping/api";
const client = new NanopingClient({ baseUrl: "http://127.0.0.1:10565" });
// Let nodes named "edge-node-1" join, and reject the rest. Runs until the
// signal aborts.
const stop = new AbortController();
await answerJoinRequests(client, (request) => request.node?.name === "edge-node-1", { signal: stop.signal });
from nanoping_api import NanopingClient
client = NanopingClient("http://127.0.0.1:10565")
# Let nodes named "edge-node-1" join, and reject the rest. Runs until the
# stream ends.
client.answer_join_requests(lambda request: request.node.name == "edge-node-1")
ws://127.0.0.1:10565/v1/streams/hub-server/authentication-requests
{
"requestId": "0",
"accept": false
}
nodeNodeInformation about the node asking to authenticate.
requestIduint64Id of the request, used when answering it.
rpc authenticationByRequests(stream AuthenticationByRequestAnswer) returns (stream AuthenticationByRequestRequest)
Method /nanopinggrpc.hub.HubServerService/authenticationByRequests
request_iduint64Id of the request being answered, as received in the request.
acceptboolTrue to accept the request, false to reject it.
nodeNodeInformation about the node asking to authenticate.
request_iduint64Id of the request, used when answering it.
- Go
- Go (generated gRPC)
import (
client "github.com/nanoping-labs/nanoping-api-go/v11"
"github.com/nanoping-labs/nanoping-api-go/v11/hub_server"
)
c, err := client.Connect("127.0.0.1:10432")
defer c.Close()
// Let nodes named "edge-node-1" join, and reject the rest. Runs until ctx is
// canceled.
err = c.AnswerJoinRequests(ctx, func(request *hub_server.AuthenticationByRequestRequest) bool {
return request.Node.Name == "edge-node-1"
})
import (
"github.com/nanoping-labs/nanoping-api-go/v11/hub_server"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
conn, err := grpc.NewClient("127.0.0.1:10432", grpc.WithTransportCredentials(insecure.NewCredentials()))
defer conn.Close()
stub := hub_server.NewHubServerServiceClient(conn)
stream, err := stub.AuthenticationByRequests(ctx)
if err != nil {
return err
}
for {
request, err := stream.Recv()
if err != nil {
return err
}
// Let nodes named "edge-node-1" join, and reject the rest.
err = stream.Send(&hub_server.AuthenticationByRequestAnswer{
RequestId: request.RequestId,
Accept: request.Node.Name == "edge-node-1",
})
if err != nil {
return err
}
}