(id uuid.UUID)
| 189 | } |
| 190 | |
| 191 | func (c *pgCoord) Node(id uuid.UUID) *agpl.Node { |
| 192 | // We're going to directly query the database, since we would only have the mapping stored locally if we had |
| 193 | // a tunnel peer connected, which is not always the case. |
| 194 | peers, err := c.store.GetTailnetPeers(c.ctx, id) |
| 195 | if err != nil { |
| 196 | c.logger.Error(c.ctx, "failed to query peers", slog.Error(err)) |
| 197 | return nil |
| 198 | } |
| 199 | mappings := make([]mapping, 0, len(peers)) |
| 200 | for _, peer := range peers { |
| 201 | pNode := new(proto.Node) |
| 202 | err := gProto.Unmarshal(peer.Node, pNode) |
| 203 | if err != nil { |
| 204 | c.logger.Critical(c.ctx, "failed to unmarshal node", slog.F("bytes", peer.Node), slog.Error(err)) |
| 205 | return nil |
| 206 | } |
| 207 | mappings = append(mappings, mapping{ |
| 208 | peer: peer.ID, |
| 209 | coordinator: peer.CoordinatorID, |
| 210 | updatedAt: peer.UpdatedAt, |
| 211 | node: pNode, |
| 212 | }) |
| 213 | } |
| 214 | mappings = c.querier.heartbeats.filter(mappings) |
| 215 | var bestT time.Time |
| 216 | var bestN *proto.Node |
| 217 | for _, m := range mappings { |
| 218 | if m.updatedAt.After(bestT) { |
| 219 | bestN = m.node |
| 220 | bestT = m.updatedAt |
| 221 | } |
| 222 | } |
| 223 | if bestN == nil { |
| 224 | return nil |
| 225 | } |
| 226 | node, err := agpl.ProtoToNode(bestN) |
| 227 | if err != nil { |
| 228 | c.logger.Critical(c.ctx, "failed to convert node", slog.F("node", bestN), slog.Error(err)) |
| 229 | return nil |
| 230 | } |
| 231 | return node |
| 232 | } |
| 233 | |
| 234 | func (c *pgCoord) Close() error { |
| 235 | c.logger.Info(c.ctx, "closing coordinator") |
nothing calls this directly
no test coverage detected