bgpwtf/cccampix/peeringdb: init

First pass at a proxy to expose PeeringDB data.

Change-Id: I844973755473b3abc5d334586744004b86d1c3a3
diff --git a/bgpwtf/cccampix/peeringdb/main.go b/bgpwtf/cccampix/peeringdb/main.go
new file mode 100644
index 0000000..fa11651
--- /dev/null
+++ b/bgpwtf/cccampix/peeringdb/main.go
@@ -0,0 +1,97 @@
+package main
+
+import (
+	"context"
+	"flag"
+
+	"github.com/golang/glog"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+
+	"code.hackerspace.pl/hscloud/bgpwtf/cccampix/peeringdb/schema"
+	pb "code.hackerspace.pl/hscloud/bgpwtf/cccampix/proto"
+	"code.hackerspace.pl/hscloud/go/mirko"
+)
+
+type service struct {
+}
+
+func (s *service) GetIXMembers(ctx context.Context, req *pb.GetIXMembersRequest) (*pb.GetIXMembersResponse, error) {
+	if req.Id == 0 {
+		return nil, status.Error(codes.InvalidArgument, "IX id must be given")
+	}
+
+	// First, get netixlans (membership info) for the given IX.
+	js := struct {
+		Data []schema.NetIXLan `json:"Data"`
+	}{}
+	err := schema.Get(ctx, &js, schema.NetIXLanInIXURL(req.Id))
+	if err != nil {
+		return nil, status.Errorf(codes.Unavailable, "PeeringDB query error: %v", err)
+	}
+
+	// Build set of seen Nets/ASs.
+	netids := make(map[int64]bool)
+	for _, netixlan := range js.Data {
+		netids[netixlan.NetID] = true
+	}
+
+	// Convert set to unique list.
+	nets := make([]int64, len(netids))
+	i := 0
+	for id, _ := range netids {
+		nets[i] = id
+		i += 1
+	}
+
+	// Request information about nets/ASNs:
+	js2 := struct {
+		Data []schema.Net `json:"Data"`
+	}{}
+	err = schema.Get(ctx, &js2, schema.NetURLMulti(nets))
+	if err != nil {
+		return nil, status.Errorf(codes.Unavailable, "PeeringDB query error: %v", err)
+	}
+
+	// Make map net id -> Net
+	netidsNet := make(map[int64]*schema.Net)
+	for _, net := range js2.Data {
+		net := net
+		netidsNet[net.ID] = &net
+	}
+
+	// Build joined response.
+
+	res := &pb.GetIXMembersResponse{
+		Members: make([]*pb.GetIXMembersResponse_Member, len(js.Data)),
+	}
+
+	for i, netixlan := range js.Data {
+		res.Members[i] = &pb.GetIXMembersResponse_Member{
+			Asn:  netixlan.ASN,
+			Ipv4: netixlan.IPv4,
+			Ipv6: netixlan.IPv6,
+			Name: netidsNet[netixlan.NetID].Name,
+		}
+	}
+
+	return res, nil
+}
+
+func main() {
+	flag.Parse()
+	mi := mirko.New()
+
+	if err := mi.Listen(); err != nil {
+		glog.Exitf("Listen failed: %v", err)
+	}
+
+	s := &service{}
+	pb.RegisterPeeringDBProxyServer(mi.GRPC(), s)
+
+	if err := mi.Serve(); err != nil {
+		glog.Exitf("Serve failed: %v", err)
+	}
+
+	<-mi.Done()
+}