| package model |
| |
| import ( |
| "context" |
| "fmt" |
| "net" |
| "strconv" |
| ) |
| |
| func (m *sqlModel) GetCheckablePeers(ctx context.Context) ([]*Peer, error) { |
| |
| data := []struct { |
| sqlPeer `db:"peers"` |
| sqlPeerRouter `db:"peer_routers"` |
| }{} |
| q := ` |
| SELECT |
| peers.id "peers.id", |
| peers.asn "peers.asn", |
| peers.name "peers.name", |
| |
| peer_routers.peer_id "peer_routers.peer_id", |
| peer_routers.v6 "peer_routers.v6", |
| peer_routers.v4 "peer_routers.v4" |
| FROM peers |
| LEFT JOIN peer_routers |
| ON peer_routers.peer_id = peers.id |
| ` |
| if err := m.db.SelectContext(ctx, &data, q); err != nil { |
| return nil, fmt.Errorf("SELECT peers/peerRouters: %v", err) |
| } |
| |
| // Collapse peers into map |
| // ID -> Peer |
| peers := make(map[string]*Peer) |
| |
| for _, row := range data { |
| peer, ok := peers[row.sqlPeer.ID] |
| if !ok { |
| asn, err := strconv.ParseInt(row.sqlPeer.ASN, 10, 64) |
| if err != nil { |
| return nil, fmt.Errorf("data corruption: invalid ASN %q", row.sqlPeer.ASN) |
| } |
| peer = &Peer{ |
| ASN: asn, |
| Name: row.sqlPeer.Name, |
| Routers: []*Router{}, |
| } |
| peers[row.sqlPeer.ID] = peer |
| } |
| |
| var v6 net.IP |
| var v4 net.IP |
| |
| if row.sqlPeerRouter.V6.Valid { |
| v6 = net.ParseIP(row.sqlPeerRouter.V6.String) |
| } |
| if row.sqlPeerRouter.V4.Valid { |
| v4 = net.ParseIP(row.sqlPeerRouter.V4.String) |
| } |
| |
| peer.Routers = append(peer.Routers, &Router{ |
| V6: v6, |
| V4: v4, |
| }) |
| } |
| |
| res := make([]*Peer, len(peers)) |
| i := 0 |
| for _, peer := range peers { |
| res[i] = peer |
| i += 1 |
| } |
| |
| return res, nil |
| } |