| ... | ... | @@ -179,18 +179,53 @@ export const layer = Layer.effect( |
| 179 | 179 | }, |
| 180 | 180 | ); |
| 181 | 181 | |
| 182 | | const loadLocalStatus = Effect.fn("VcsStatusBroadcaster.loadLocalStatus")(function* ( |
| 182 | const updateCachedStatus = Effect.fn("VcsStatusBroadcaster.updateCachedStatus")(function* ( |
| 183 | 183 | cwd: string, |
| 184 | local: VcsStatusLocalResult, |
| 185 | remote: VcsStatusRemoteResult | null, |
| 186 | options?: { publish?: boolean }, |
| 184 | 187 | ) { |
| 185 | | const local = yield* workflow.localStatus({ cwd }); |
| 186 | | return yield* updateCachedLocalStatus(cwd, local); |
| 188 | const nextLocal = { |
| 189 | fingerprint: fingerprintStatusPart(local), |
| 190 | value: local, |
| 191 | } satisfies CachedValue<VcsStatusLocalResult>; |
| 192 | const nextRemote = { |
| 193 | fingerprint: fingerprintStatusPart(remote), |
| 194 | value: remote, |
| 195 | } satisfies CachedValue<VcsStatusRemoteResult | null>; |
| 196 | const shouldPublish = yield* Ref.modify(cacheRef, (cache) => { |
| 197 | const previous = cache.get(cwd) ?? { local: null, remote: null }; |
| 198 | const nextCache = new Map(cache); |
| 199 | nextCache.set(cwd, { |
| 200 | local: nextLocal, |
| 201 | remote: nextRemote, |
| 202 | }); |
| 203 | return [ |
| 204 | previous.local?.fingerprint !== nextLocal.fingerprint || |
| 205 | previous.remote?.fingerprint !== nextRemote.fingerprint, |
| 206 | nextCache, |
| 207 | ] as const; |
| 208 | }); |
| 209 | |
| 210 | if (options?.publish && shouldPublish) { |
| 211 | yield* PubSub.publish(changesPubSub, { |
| 212 | cwd, |
| 213 | event: { |
| 214 | _tag: "snapshot", |
| 215 | local, |
| 216 | remote, |
| 217 | }, |
| 218 | }); |
| 219 | } |
| 220 | |
| 221 | return mergeGitStatusParts(local, remote); |
| 187 | 222 | }); |
| 188 | 223 | |
| 189 | | const loadRemoteStatus = Effect.fn("VcsStatusBroadcaster.loadRemoteStatus")(function* ( |
| 224 | const loadLocalStatus = Effect.fn("VcsStatusBroadcaster.loadLocalStatus")(function* ( |
| 190 | 225 | cwd: string, |
| 191 | 226 | ) { |
| 192 | | const remote = yield* workflow.remoteStatus({ cwd }); |
| 193 | | return yield* updateCachedRemoteStatus(cwd, remote); |
| 227 | const local = yield* workflow.localStatus({ cwd }); |
| 228 | return yield* updateCachedLocalStatus(cwd, local); |
| 194 | 229 | }); |
| 195 | 230 | |
| 196 | 231 | const getOrLoadLocalStatus = Effect.fn("VcsStatusBroadcaster.getOrLoadLocalStatus")(function* ( |
| ... | ... | @@ -203,36 +238,39 @@ export const layer = Layer.effect( |
| 203 | 238 | return yield* loadLocalStatus(cwd); |
| 204 | 239 | }); |
| 205 | 240 | |
| 206 | | const getOrLoadRemoteStatus = Effect.fn("VcsStatusBroadcaster.getOrLoadRemoteStatus")( |
| 207 | | function* (cwd: string) { |
| 208 | | const cached = yield* getCachedStatus(cwd); |
| 209 | | if (cached?.remote) { |
| 210 | | return cached.remote.value; |
| 211 | | } |
| 212 | | return yield* loadRemoteStatus(cwd); |
| 213 | | }, |
| 214 | | ); |
| 215 | | |
| 216 | 241 | const withFileSystem = Effect.provideService(FileSystem.FileSystem, fs); |
| 217 | 242 | |
| 218 | 243 | const getStatus: VcsStatusBroadcasterShape["getStatus"] = Effect.fn( |
| 219 | 244 | "VcsStatusBroadcaster.getStatus", |
| 220 | 245 | )(function* (input) { |
| 221 | 246 | const cwd = yield* withFileSystem(normalizeCwd(input.cwd)); |
| 222 | | const [local, remote] = yield* Effect.all([ |
| 223 | | getOrLoadLocalStatus(cwd), |
| 224 | | getOrLoadRemoteStatus(cwd), |
| 225 | | ]); |
| 226 | | return mergeGitStatusParts(local, remote); |
| 247 | const cached = yield* getCachedStatus(cwd); |
| 248 | if (cached?.local && cached.remote) { |
| 249 | return mergeGitStatusParts(cached.local.value, cached.remote.value); |
| 250 | } |
| 251 | const [local, remote] = yield* Effect.all( |
| 252 | [ |
| 253 | cached?.local ? Effect.succeed(cached.local.value) : workflow.localStatus({ cwd }), |
| 254 | cached?.remote ? Effect.succeed(cached.remote.value) : workflow.remoteStatus({ cwd }), |
| 255 | ], |
| 256 | { concurrency: "unbounded" }, |
| 257 | ); |
| 258 | return yield* updateCachedStatus(cwd, local, remote); |
| 227 | 259 | }); |
| 228 | 260 | |
| 261 | const refreshLocalStatusCore = Effect.fn("VcsStatusBroadcaster.refreshLocalStatusCore")( |
| 262 | function* (cwd: string) { |
| 263 | yield* workflow.invalidateLocalStatus(cwd); |
| 264 | const local = yield* workflow.localStatus({ cwd }); |
| 265 | return yield* updateCachedLocalStatus(cwd, local, { publish: true }); |
| 266 | }, |
| 267 | ); |
| 268 | |
| 229 | 269 | const refreshLocalStatus: VcsStatusBroadcasterShape["refreshLocalStatus"] = Effect.fn( |
| 230 | 270 | "VcsStatusBroadcaster.refreshLocalStatus", |
| 231 | 271 | )(function* (rawCwd) { |
| 232 | 272 | const cwd = yield* withFileSystem(normalizeCwd(rawCwd)); |
| 233 | | yield* workflow.invalidateLocalStatus(cwd); |
| 234 | | const local = yield* workflow.localStatus({ cwd }); |
| 235 | | return yield* updateCachedLocalStatus(cwd, local, { publish: true }); |
| 273 | return yield* refreshLocalStatusCore(cwd); |
| 236 | 274 | }); |
| 237 | 275 | |
| 238 | 276 | const refreshRemoteStatus = Effect.fn("VcsStatusBroadcaster.refreshRemoteStatus")(function* ( |
| ... | ... | @@ -247,11 +285,15 @@ export const layer = Layer.effect( |
| 247 | 285 | "VcsStatusBroadcaster.refreshStatus", |
| 248 | 286 | )(function* (rawCwd) { |
| 249 | 287 | const cwd = yield* withFileSystem(normalizeCwd(rawCwd)); |
| 250 | | const [local, remote] = yield* Effect.all([ |
| 251 | | refreshLocalStatus(cwd), |
| 252 | | refreshRemoteStatus(cwd), |
| 253 | | ]); |
| 254 | | return mergeGitStatusParts(local, remote); |
| 288 | yield* Effect.all( |
| 289 | [workflow.invalidateLocalStatus(cwd), workflow.invalidateRemoteStatus(cwd)], |
| 290 | { concurrency: "unbounded", discard: true }, |
| 291 | ); |
| 292 | const [local, remote] = yield* Effect.all( |
| 293 | [workflow.localStatus({ cwd }), workflow.remoteStatus({ cwd })], |
| 294 | { concurrency: "unbounded" }, |
| 295 | ); |
| 296 | return yield* updateCachedStatus(cwd, local, remote, { publish: true }); |
| 255 | 297 | }); |
| 256 | 298 | |
| 257 | 299 | const makeRemoteRefreshLoop = ( |