diff --git a/topology.go b/topology.go new file mode 100644 index 0000000..78f3aa0 --- /dev/null +++ b/topology.go @@ -0,0 +1,74 @@ +// Copyright 2024 Blink Labs Software +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package node + +import ( + "encoding/json" + "io" + "os" +) + +// TopologyConfig represents a Cardano node topology config +type TopologyConfig struct { + Producers []TopologyConfigLegacyProducer `json:"Producers"` + LocalRoots []TopologyConfigP2PLocalRoot `json:"localRoots"` + PublicRoots []TopologyConfigP2PPublicRoot `json:"publicRoots"` + UseLedgerAfterSlot uint64 `json:"useLedgerAfterSlot"` +} + +type TopologyConfigLegacyProducer struct { + Address string `json:"addr"` + Port uint `json:"port"` + Valency uint `json:"valency"` + Continent string `json:"continent"` + State string `json:"state"` +} + +type TopologyConfigP2PAccessPoint struct { + Address string `json:"address"` + Port uint `json:"port"` +} + +type TopologyConfigP2PLocalRoot struct { + AccessPoints []TopologyConfigP2PAccessPoint `json:"accessPoints"` + Advertise bool `json:"advertise"` + Valency uint `json:"valency"` +} + +type TopologyConfigP2PPublicRoot struct { + AccessPoints []TopologyConfigP2PAccessPoint `json:"accessPoints"` + Advertise bool `json:"advertise"` + Valency uint `json:"valency"` +} + +func NewTopologyConfigFromFile(path string) (*TopologyConfig, error) { + dataFile, err := os.Open(path) + if err != nil { + return nil, err + } + return NewTopologyConfigFromReader(dataFile) +} + +func NewTopologyConfigFromReader(r io.Reader) (*TopologyConfig, error) { + t := &TopologyConfig{} + data, err := io.ReadAll(r) + if err != nil { + return nil, err + } + if err := json.Unmarshal(data, t); err != nil { + return nil, err + } + return t, nil +} diff --git a/topology_test.go b/topology_test.go new file mode 100644 index 0000000..b4f08f0 --- /dev/null +++ b/topology_test.go @@ -0,0 +1,135 @@ +// Copyright 2024 Blink Labs Software +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package node_test + +import ( + "reflect" + "strings" + "testing" + + "github.com/blinklabs-io/node" +) + +type topologyTestDefinition struct { + jsonData string + expectedObject *node.TopologyConfig +} + +var topologyTests = []topologyTestDefinition{ + { + jsonData: ` +{ + "Producers": [ + { + "addr": "backbone.cardano.iog.io", + "port": 3001, + "valency": 2 + } + ] +} +`, + expectedObject: &node.TopologyConfig{ + Producers: []node.TopologyConfigLegacyProducer{ + { + Address: "backbone.cardano.iog.io", + Port: 3001, + Valency: 2, + }, + }, + }, + }, + { + jsonData: ` +{ + "localRoots": [ + { + "accessPoints": [], + "advertise": false, + "valency": 1 + } + ], + "publicRoots": [ + { + "accessPoints": [ + { + "address": "backbone.cardano.iog.io", + "port": 3001 + } + ], + "advertise": false + }, + { + "accessPoints": [ + { + "address": "backbone.mainnet.emurgornd.com", + "port": 3001 + } + ], + "advertise": false + } + ], + "useLedgerAfterSlot": 99532743 +} +`, + expectedObject: &node.TopologyConfig{ + LocalRoots: []node.TopologyConfigP2PLocalRoot{ + { + AccessPoints: []node.TopologyConfigP2PAccessPoint{}, + Advertise: false, + Valency: 1, + }, + }, + PublicRoots: []node.TopologyConfigP2PPublicRoot{ + { + AccessPoints: []node.TopologyConfigP2PAccessPoint{ + { + Address: "backbone.cardano.iog.io", + Port: 3001, + }, + }, + Advertise: false, + }, + { + AccessPoints: []node.TopologyConfigP2PAccessPoint{ + { + Address: "backbone.mainnet.emurgornd.com", + Port: 3001, + }, + }, + Advertise: false, + }, + }, + UseLedgerAfterSlot: 99532743, + }, + }, +} + +func TestParseTopologyConfig(t *testing.T) { + for _, test := range topologyTests { + topology, err := node.NewTopologyConfigFromReader( + strings.NewReader(test.jsonData), + ) + if err != nil { + t.Fatalf("failed to load TopologyConfig from JSON data: %s", err) + } + if !reflect.DeepEqual(topology, test.expectedObject) { + t.Fatalf( + "did not get expected object\n got:\n %#v\n wanted:\n %#v", + topology, + test.expectedObject, + ) + } + } +}