@Summary Get DERP map updates @ID get-derp-map-updates @Security CoderSessionToken @Tags Agents @Success 101 @Router /api/v2/derp-map [get]
(rw http.ResponseWriter, r *http.Request)
| 1223 | // @Success 101 |
| 1224 | // @Router /api/v2/derp-map [get] |
| 1225 | func (api *API) derpMapUpdates(rw http.ResponseWriter, r *http.Request) { |
| 1226 | ctx := r.Context() |
| 1227 | |
| 1228 | api.WebsocketWaitMutex.Lock() |
| 1229 | api.WebsocketWaitGroup.Add(1) |
| 1230 | api.WebsocketWaitMutex.Unlock() |
| 1231 | defer api.WebsocketWaitGroup.Done() |
| 1232 | |
| 1233 | ws, err := websocket.Accept(rw, r, nil) |
| 1234 | if err != nil { |
| 1235 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 1236 | Message: "Failed to accept websocket.", |
| 1237 | Detail: err.Error(), |
| 1238 | }) |
| 1239 | return |
| 1240 | } |
| 1241 | encoder := wsjson.NewEncoder[*tailcfg.DERPMap](ws, websocket.MessageBinary) |
| 1242 | defer encoder.Close(websocket.StatusGoingAway) |
| 1243 | |
| 1244 | // Log the request immediately instead of after it completes. |
| 1245 | if rl := loggermw.RequestLoggerFromContext(ctx); rl != nil { |
| 1246 | rl.WriteLog(ctx, http.StatusAccepted) |
| 1247 | } |
| 1248 | |
| 1249 | go func(ctx context.Context) { |
| 1250 | // TODO(mafredri): Is this too frequent? Use separate ping disconnect timeout? |
| 1251 | t := time.NewTicker(api.AgentConnectionUpdateFrequency) |
| 1252 | defer t.Stop() |
| 1253 | |
| 1254 | for { |
| 1255 | select { |
| 1256 | case <-t.C: |
| 1257 | case <-ctx.Done(): |
| 1258 | return |
| 1259 | } |
| 1260 | |
| 1261 | ctx, cancel := context.WithTimeout(ctx, 30*time.Second) |
| 1262 | err := ws.Ping(ctx) |
| 1263 | cancel() |
| 1264 | if err != nil { |
| 1265 | _ = ws.Close(websocket.StatusGoingAway, "ping failed") |
| 1266 | return |
| 1267 | } |
| 1268 | } |
| 1269 | }(ctx) |
| 1270 | |
| 1271 | ticker := time.NewTicker(api.Options.DERPMapUpdateFrequency) |
| 1272 | defer ticker.Stop() |
| 1273 | |
| 1274 | var lastDERPMap *tailcfg.DERPMap |
| 1275 | for { |
| 1276 | derpMap := api.DERPMap() |
| 1277 | if lastDERPMap == nil || !tailnet.CompareDERPMaps(lastDERPMap, derpMap) { |
| 1278 | err := encoder.Encode(derpMap) |
| 1279 | if err != nil { |
| 1280 | return |
| 1281 | } |
| 1282 | lastDERPMap = derpMap |
nothing calls this directly
no test coverage detected