Add Effect v4 support, Fast Refresh tooling, and revamped docs #56
@@ -1,4 +1,4 @@
|
|||||||
import { type Cause, Context, DateTime, type Duration, Effect, Equal, Exit, HashMap, Layer, Option, Order, Scope, Semaphore, Stream, SubscriptionRef } from "effect"
|
import { type Cause, Context, DateTime, type Duration, Effect, Equal, Exit, flow, HashMap, Layer, Option, Order, Scope, Semaphore, Stream, SubscriptionRef } from "effect"
|
||||||
|
|
||||||
|
|
||||||
export interface ScopeRegistryService {
|
export interface ScopeRegistryService {
|
||||||
@@ -39,14 +39,13 @@ export class ScopeRegistryServiceImpl implements ScopeRegistryService {
|
|||||||
readonly runSemaphore: Semaphore.Semaphore,
|
readonly runSemaphore: Semaphore.Semaphore,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|
||||||
register(
|
register(
|
||||||
key: ScopeRegistryService.Key,
|
key: ScopeRegistryService.Key,
|
||||||
options: ScopeRegistryService.RegisterOptions,
|
options: ScopeRegistryService.RegisterOptions,
|
||||||
): Effect.Effect<ScopeRegistryService.Entry> {
|
): Effect.Effect<ScopeRegistryService.Entry> {
|
||||||
return Effect.gen({ self: this }, function*() {
|
return Effect.gen({ self: this }, function*() {
|
||||||
const now = yield* DateTime.now
|
const now = yield* DateTime.now
|
||||||
const entry = Equal.byReference<ScopeRegistryService.Entry>({
|
const entry = Equal.byReference({
|
||||||
scope: yield* Scope.make(options.finalizerExecutionStrategy),
|
scope: yield* Scope.make(options.finalizerExecutionStrategy),
|
||||||
expiresAt: Option.some(DateTime.addDuration(now, options.finalizerExecutionDebounce)),
|
expiresAt: Option.some(DateTime.addDuration(now, options.finalizerExecutionDebounce)),
|
||||||
finalizerExecutionDebounce: options.finalizerExecutionDebounce,
|
finalizerExecutionDebounce: options.finalizerExecutionDebounce,
|
||||||
@@ -58,21 +57,34 @@ export class ScopeRegistryServiceImpl implements ScopeRegistryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
commit(key: ScopeRegistryService.Key): Effect.Effect<ScopeRegistryService.Entry, Cause.NoSuchElementError> {
|
commit(key: ScopeRegistryService.Key): Effect.Effect<ScopeRegistryService.Entry, Cause.NoSuchElementError> {
|
||||||
return this.updateEntry(key, entry => Equal.byReference({
|
return SubscriptionRef.get(this.ref).pipe(
|
||||||
|
Effect.map(HashMap.get(key)),
|
||||||
|
Effect.flatMap(Effect.fromOption),
|
||||||
|
Effect.map(entry => Equal.byReference<ScopeRegistryService.Entry>({
|
||||||
...entry,
|
...entry,
|
||||||
expiresAt: Option.none(),
|
expiresAt: Option.none(),
|
||||||
}))
|
})),
|
||||||
|
Effect.tap(entry => SubscriptionRef.update(this.ref, HashMap.set(key, entry))),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
release(key: ScopeRegistryService.Key): Effect.Effect<ScopeRegistryService.Entry, Cause.NoSuchElementError> {
|
release(key: ScopeRegistryService.Key): Effect.Effect<ScopeRegistryService.Entry, Cause.NoSuchElementError> {
|
||||||
return Effect.flatMap(DateTime.now, now => this.updateEntry(key, entry => Equal.byReference({
|
return SubscriptionRef.get(this.ref).pipe(
|
||||||
|
Effect.map(HashMap.get(key)),
|
||||||
|
Effect.flatMap(option => Effect.all([
|
||||||
|
DateTime.now,
|
||||||
|
Effect.fromOption(option),
|
||||||
|
])),
|
||||||
|
Effect.map(([now, entry]) => Equal.byReference<ScopeRegistryService.Entry>({
|
||||||
...entry,
|
...entry,
|
||||||
expiresAt: Option.some(DateTime.addDuration(now, entry.finalizerExecutionDebounce)),
|
expiresAt: Option.some(DateTime.addDuration(now, entry.finalizerExecutionDebounce)),
|
||||||
})))
|
})),
|
||||||
|
Effect.tap(entry => SubscriptionRef.update(this.ref, HashMap.set(key, entry))),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get run(): Effect.Effect<void> {
|
get run(): Effect.Effect<void> {
|
||||||
return this.runSemaphore.withPermits(1)(SubscriptionRef.changes(this.ref).pipe(
|
return SubscriptionRef.changes(this.ref).pipe(
|
||||||
Stream.switchMap(entries => Option.match(this.getNextExpiration(entries), {
|
Stream.switchMap(entries => Option.match(this.getNextExpiration(entries), {
|
||||||
onNone: () => Stream.never,
|
onNone: () => Stream.never,
|
||||||
onSome: expiresAt => Stream.fromEffect(DateTime.now.pipe(
|
onSome: expiresAt => Stream.fromEffect(DateTime.now.pipe(
|
||||||
@@ -83,7 +95,8 @@ export class ScopeRegistryServiceImpl implements ScopeRegistryService {
|
|||||||
)),
|
)),
|
||||||
})),
|
})),
|
||||||
Stream.runDrain,
|
Stream.runDrain,
|
||||||
))
|
this.runSemaphore.withPermit,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get dispose(): Effect.Effect<void> {
|
get dispose(): Effect.Effect<void> {
|
||||||
@@ -99,22 +112,6 @@ export class ScopeRegistryServiceImpl implements ScopeRegistryService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
updateEntry(
|
|
||||||
key: ScopeRegistryService.Key,
|
|
||||||
f: (entry: ScopeRegistryService.Entry) => ScopeRegistryService.Entry,
|
|
||||||
): Effect.Effect<ScopeRegistryService.Entry, Cause.NoSuchElementError> {
|
|
||||||
return SubscriptionRef.modify(this.ref, entries => {
|
|
||||||
const current = HashMap.get(entries, key)
|
|
||||||
|
|
||||||
if (current._tag === "None")
|
|
||||||
return [Option.none(), entries]
|
|
||||||
|
|
||||||
const entry = f(current.value)
|
|
||||||
return [Option.some(entry), HashMap.set(entries, key, entry)]
|
|
||||||
}).pipe(Effect.flatMap(Effect.fromOption))
|
|
||||||
}
|
|
||||||
|
|
||||||
get closeExpired(): Effect.Effect<void> {
|
get closeExpired(): Effect.Effect<void> {
|
||||||
return Effect.flatMap(DateTime.now, now => SubscriptionRef.modify(
|
return Effect.flatMap(DateTime.now, now => SubscriptionRef.modify(
|
||||||
this.ref,
|
this.ref,
|
||||||
|
|||||||
Reference in New Issue
Block a user