mirror of
https://github.com/luxfi/api.git
synced 2026-09-24 00:24:53 +00:00
A ZAP field is an offset. Eight of these replies held a map, which has no order to give one, so the reply could not cross between two processes at all. Two more held values whose fields are every one unexported — netip.AddrPort, time.Time — and those are worse: they are not refused, they derive an EMPTY layout, so the reply crossed, reported no error and carried nothing. GetNodeIPReply has one field, so its whole answer was blank. And a health check says what it likes, so its details were an `any`, which has no shape until it holds something. Each map is now a list of a stated element type, ordered by the key it was an object of. An address is the text netip already wrote for it, an instant is three numbers, and a check details are the bytes of their own JSON — the one shape an object, a string and a list all share. The JSON does not move. Every list marshals to the object it replaced and reads one back, and wire_test.go holds that against the old shape spelled out as a literal rather than against itself. The order is new where there was none: a map answered the same question two ways. APIReply also states the status it carries, so the 503 a probe reads and the healthy a person reads are one fact computed once.
255 lines
6.9 KiB
Go
255 lines
6.9 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Operating a node.
|
|
//
|
|
// THREE SHAPES HERE ARE AN OBJECT ON THE JSON WIRE AND A LIST IN GO — the logger
|
|
// levels, the installed VMs, and what a reload found. A ZAP field is an offset
|
|
// and a map has no order to give one, so a reply carrying a map cannot cross
|
|
// between two processes at all. Each list is ordered by the key it was an object
|
|
// of; the JSON is unchanged.
|
|
package admin
|
|
|
|
import (
|
|
"encoding/json"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/luxfi/api/types"
|
|
"github.com/luxfi/ids"
|
|
)
|
|
|
|
// AliasArgs are the arguments for calling Alias.
|
|
type AliasArgs struct {
|
|
Endpoint string `json:"endpoint"`
|
|
Alias string `json:"alias"`
|
|
}
|
|
|
|
// AliasChainArgs are the arguments for calling AliasChain.
|
|
type AliasChainArgs struct {
|
|
Chain string `json:"chain"`
|
|
Alias string `json:"alias"`
|
|
}
|
|
|
|
// GetChainAliasesArgs are the arguments for calling GetChainAliases.
|
|
type GetChainAliasesArgs struct {
|
|
Chain string `json:"chain"`
|
|
}
|
|
|
|
// GetChainAliasesReply are the aliases of the given chain.
|
|
type GetChainAliasesReply struct {
|
|
Aliases []string `json:"aliases"`
|
|
}
|
|
|
|
// SetLoggerLevelArgs are the arguments for setting a logger's levels.
|
|
type SetLoggerLevelArgs struct {
|
|
LoggerName string `json:"loggerName"`
|
|
LogLevel string `json:"logLevel"`
|
|
DisplayLevel string `json:"displayLevel"`
|
|
}
|
|
|
|
// LogAndDisplayLevels pairs log and display levels.
|
|
type LogAndDisplayLevels struct {
|
|
LogLevel string `json:"logLevel"`
|
|
DisplayLevel string `json:"displayLevel"`
|
|
}
|
|
|
|
// LoggerLevel is one logger and the two levels it is set to.
|
|
type LoggerLevel struct {
|
|
// Logger is the logger's name, the key it appears under on the JSON wire.
|
|
Logger string `json:"logger"`
|
|
// Levels are what it writes to its file and to the display.
|
|
Levels LogAndDisplayLevels `json:"levels"`
|
|
}
|
|
|
|
// LoggerLevels are the levels every named logger is set to: an object keyed by
|
|
// logger name on the JSON wire, a list ordered by that name here.
|
|
type LoggerLevels []LoggerLevel
|
|
|
|
func (l LoggerLevels) MarshalJSON() ([]byte, error) {
|
|
m := make(map[string]LogAndDisplayLevels, len(l))
|
|
for _, e := range l {
|
|
m[e.Logger] = e.Levels
|
|
}
|
|
return json.Marshal(m)
|
|
}
|
|
|
|
func (l *LoggerLevels) UnmarshalJSON(b []byte) error {
|
|
var m map[string]LogAndDisplayLevels
|
|
if err := json.Unmarshal(b, &m); err != nil {
|
|
return err
|
|
}
|
|
*l = make(LoggerLevels, 0, len(m))
|
|
for name, levels := range m {
|
|
*l = append(*l, LoggerLevel{Logger: name, Levels: levels})
|
|
}
|
|
slices.SortFunc(*l, func(x, y LoggerLevel) int { return strings.Compare(x.Logger, y.Logger) })
|
|
return nil
|
|
}
|
|
|
|
// LoggerLevelReply are the levels of the loggers.
|
|
type LoggerLevelReply struct {
|
|
LoggerLevels LoggerLevels `json:"loggerLevels"`
|
|
}
|
|
|
|
// GetLoggerLevelArgs are the arguments for getting logger levels.
|
|
type GetLoggerLevelArgs struct {
|
|
LoggerName string `json:"loggerName"`
|
|
}
|
|
|
|
// LoadedVM is one VM a reload brought in and the names it answers to.
|
|
type LoadedVM struct {
|
|
// VM is the VM's id, the key it appears under on the JSON wire.
|
|
VM ids.ID `json:"vm"`
|
|
// Aliases are the names it also answers to.
|
|
Aliases []string `json:"aliases"`
|
|
}
|
|
|
|
// LoadedVMs are the VMs a reload brought in: an object keyed by VM id on the
|
|
// JSON wire, a list ordered by that id here.
|
|
type LoadedVMs []LoadedVM
|
|
|
|
func (l LoadedVMs) MarshalJSON() ([]byte, error) {
|
|
m := make(map[ids.ID][]string, len(l))
|
|
for _, e := range l {
|
|
m[e.VM] = e.Aliases
|
|
}
|
|
return json.Marshal(m)
|
|
}
|
|
|
|
func (l *LoadedVMs) UnmarshalJSON(b []byte) error {
|
|
var m map[ids.ID][]string
|
|
if err := json.Unmarshal(b, &m); err != nil {
|
|
return err
|
|
}
|
|
*l = make(LoadedVMs, 0, len(m))
|
|
for vm, aliases := range m {
|
|
*l = append(*l, LoadedVM{VM: vm, Aliases: aliases})
|
|
}
|
|
slices.SortFunc(*l, func(x, y LoadedVM) int { return x.VM.Compare(y.VM) })
|
|
return nil
|
|
}
|
|
|
|
// FailedVM is one VM a reload could not bring in, and why.
|
|
type FailedVM struct {
|
|
// VM is the VM's id, the key it appears under on the JSON wire.
|
|
VM ids.ID `json:"vm"`
|
|
// Error is what stopped it loading.
|
|
Error string `json:"error"`
|
|
}
|
|
|
|
// FailedVMs are the VMs a reload could not bring in: an object keyed by VM id
|
|
// on the JSON wire, a list ordered by that id here.
|
|
type FailedVMs []FailedVM
|
|
|
|
func (f FailedVMs) MarshalJSON() ([]byte, error) {
|
|
m := make(map[ids.ID]string, len(f))
|
|
for _, e := range f {
|
|
m[e.VM] = e.Error
|
|
}
|
|
return json.Marshal(m)
|
|
}
|
|
|
|
func (f *FailedVMs) UnmarshalJSON(b []byte) error {
|
|
var m map[ids.ID]string
|
|
if err := json.Unmarshal(b, &m); err != nil {
|
|
return err
|
|
}
|
|
*f = make(FailedVMs, 0, len(m))
|
|
for vm, why := range m {
|
|
*f = append(*f, FailedVM{VM: vm, Error: why})
|
|
}
|
|
slices.SortFunc(*f, func(x, y FailedVM) int { return x.VM.Compare(y.VM) })
|
|
return nil
|
|
}
|
|
|
|
// LoadVMsReply contains the response for LoadVMs.
|
|
type LoadVMsReply struct {
|
|
NewVMs LoadedVMs `json:"newVMs"`
|
|
FailedVMs FailedVMs `json:"failedVMs"`
|
|
ChainsRetried int `json:"chainsRetried"`
|
|
}
|
|
|
|
// DBGetArgs are the arguments for DBGet.
|
|
type DBGetArgs struct {
|
|
Key string `json:"key"`
|
|
}
|
|
|
|
// DBGetReply is the reply for DBGet.
|
|
type DBGetReply struct {
|
|
Value string `json:"value"`
|
|
}
|
|
|
|
// VMInfo contains information about a registered VM.
|
|
type VMInfo struct {
|
|
ID string `json:"id"`
|
|
Aliases []string `json:"aliases"`
|
|
Path string `json:"path,omitempty"`
|
|
}
|
|
|
|
// InstalledVMs are the VMs on a node: an object keyed by VM id on the JSON
|
|
// wire, a list ordered by that id here. The id is on the element too — it is
|
|
// [VMInfo.ID] — so the key is the element's own name rather than a second one.
|
|
type InstalledVMs []VMInfo
|
|
|
|
func (v InstalledVMs) MarshalJSON() ([]byte, error) {
|
|
m := make(map[string]VMInfo, len(v))
|
|
for _, e := range v {
|
|
m[e.ID] = e
|
|
}
|
|
return json.Marshal(m)
|
|
}
|
|
|
|
func (v *InstalledVMs) UnmarshalJSON(b []byte) error {
|
|
var m map[string]VMInfo
|
|
if err := json.Unmarshal(b, &m); err != nil {
|
|
return err
|
|
}
|
|
*v = make(InstalledVMs, 0, len(m))
|
|
for id, info := range m {
|
|
info.ID = id
|
|
*v = append(*v, info)
|
|
}
|
|
slices.SortFunc(*v, func(x, y VMInfo) int { return strings.Compare(x.ID, y.ID) })
|
|
return nil
|
|
}
|
|
|
|
// ListVMsReply contains the response for ListVMs.
|
|
type ListVMsReply struct {
|
|
VMs InstalledVMs `json:"vms"`
|
|
}
|
|
|
|
// SnapshotArgs are the arguments for Snapshot.
|
|
type SnapshotArgs struct {
|
|
Path string `json:"path"`
|
|
Since uint64 `json:"since"`
|
|
}
|
|
|
|
// SnapshotReply is the response for Snapshot.
|
|
type SnapshotReply struct {
|
|
Version uint64 `json:"version"`
|
|
}
|
|
|
|
// LoadArgs are the arguments for Load.
|
|
type LoadArgs struct {
|
|
Path string `json:"path"`
|
|
}
|
|
|
|
// SetTrackedChainsArgs are the arguments for SetTrackedChains.
|
|
type SetTrackedChainsArgs struct {
|
|
Chains []string `json:"chains"`
|
|
}
|
|
|
|
// SetTrackedChainsReply is the response for SetTrackedChains.
|
|
type SetTrackedChainsReply struct {
|
|
TrackedChains []string `json:"trackedChains"`
|
|
}
|
|
|
|
// GetTrackedChainsReply is the response for GetTrackedChains.
|
|
type GetTrackedChainsReply struct {
|
|
TrackedChains []string `json:"trackedChains"`
|
|
}
|
|
|
|
// EmptyReply is an alias to common empty reply.
|
|
type EmptyReply = types.EmptyReply
|