Skip to content

Commit

Permalink
refactor: layer structure
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart committed Dec 1, 2023
1 parent ea9623e commit 7aeb5ec
Show file tree
Hide file tree
Showing 17 changed files with 132 additions and 183 deletions.
12 changes: 7 additions & 5 deletions examples/interactions.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Discord, Ix } from "dfx"
import { gatewayLayer, runIx } from "dfx/gateway"
import { Discord, DiscordConfig, Ix } from "dfx"
import { DiscordLive, runIx } from "dfx/gateway"
import Dotenv from "dotenv"
import { Cause, Config, Effect, Option, pipe } from "effect"
import { Cause, Config, Effect, Layer, Option, pipe } from "effect"

Dotenv.config()

// Create the dependencies layer
const DiscordLive = gatewayLayer({
const DiscordConfigLive = DiscordConfig.layerConfig({
token: Config.secret("DISCORD_BOT_TOKEN"),
})

Expand Down Expand Up @@ -78,9 +78,11 @@ const program = Effect.gen(function* (_) {
yield* _(interactions)
})

const EnvLive = DiscordLive.pipe(Layer.provide(DiscordConfigLive))

// Run it
program.pipe(
Effect.provide(DiscordLive),
Effect.provide(EnvLive),
Effect.tapErrorCause(_ =>
Effect.sync(() => {
console.error(Cause.squash(_))
Expand Down
9 changes: 5 additions & 4 deletions examples/registry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Discord, Ix } from "dfx"
import { Discord, DiscordConfig, Ix } from "dfx"
import {
gatewayLayer,
DiscordLive,
InteractionsRegistry,
InteractionsRegistryLive,
} from "dfx/gateway"
Expand Down Expand Up @@ -53,9 +53,10 @@ const GreetLive = Layer.effectDiscard(makeGreetService)

// Main layer
const MainLive = GreetLive.pipe(
Layer.provide(InteractionsRegistryLive()),
Layer.provide(InteractionsRegistryLive),
Layer.provide(DiscordLive),
Layer.provide(
gatewayLayer({
DiscordConfig.layerConfig({
token: Config.secret("DISCORD_BOT_TOKEN"),
debug: Config.withDefault(Config.boolean("DEBUG"), false),
}),
Expand Down
4 changes: 2 additions & 2 deletions src/DiscordConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ export const make = ({
},
})

export const makeLayer = (
export const layer = (
opts: MakeOpts,
): Layer.Layer<never, never, DiscordConfig> =>
Layer.succeed(DiscordConfig, make(opts))

export const makeFromConfig = (
export const layerConfig = (
_: Config.Config.Wrap<MakeOpts>,
): Layer.Layer<never, ConfigError.ConfigError, DiscordConfig> =>
Layer.effect(DiscordConfig, Effect.map(Effect.config(Config.unwrap(_)), make))
6 changes: 3 additions & 3 deletions src/DiscordGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as Layer from "effect/Layer"
import * as Queue from "effect/Queue"
import * as Stream from "effect/Stream"
import type { RunningShard } from "dfx/DiscordGateway/Shard"
import { LiveSharder, Sharder } from "dfx/DiscordGateway/Sharder"
import { SharedLive, Sharder } from "dfx/DiscordGateway/Sharder"
import type * as Discord from "dfx/types"
import * as EffectUtils from "dfx/utils/Effect"
import * as Schedule from "effect/Schedule"
Expand Down Expand Up @@ -97,7 +97,7 @@ export const make = Effect.gen(function* (_) {
}),
)

export const LiveDiscordGateway = Layer.provide(
export const DiscordGatewayLive = Layer.provide(
Layer.scoped(DiscordGateway, make),
LiveSharder,
SharedLive,
)
6 changes: 3 additions & 3 deletions src/DiscordGateway/DiscordWS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Tag } from "effect/Context"
import * as Effect from "effect/Effect"
import * as Layer from "effect/Layer"
import * as Ref from "effect/Ref"
import { LiveWS, Reconnect, WS } from "dfx/DiscordGateway/WS"
import { WSLive, Reconnect, WS } from "dfx/DiscordGateway/WS"
import type * as Discord from "dfx/types"
import type WebSocket from "isomorphic-ws"

Expand Down Expand Up @@ -69,7 +69,7 @@ const make = Effect.gen(function* (_) {

export interface DiscordWS extends Effect.Effect.Success<typeof make> {}
export const DiscordWS = Tag<DiscordWS>()
export const LiveDiscordWS = Layer.provide(
export const DiscordWSLive = Layer.provide(
Layer.effect(DiscordWS, make),
LiveWS,
WSLive,
)
8 changes: 4 additions & 4 deletions src/DiscordGateway/Shard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import * as Queue from "effect/Queue"
import * as Ref from "effect/Ref"
import { DiscordConfig } from "dfx/DiscordConfig"
import type { Message } from "dfx/DiscordGateway/DiscordWS"
import { DiscordWS, LiveDiscordWS } from "dfx/DiscordGateway/DiscordWS"
import { DiscordWS, DiscordWSLive } from "dfx/DiscordGateway/DiscordWS"
import * as Heartbeats from "dfx/DiscordGateway/Shard/heartbeats"
import * as Identify from "dfx/DiscordGateway/Shard/identify"
import * as InvalidSession from "dfx/DiscordGateway/Shard/invalidSession"
import * as Utils from "dfx/DiscordGateway/Shard/utils"
import { Reconnect } from "dfx/DiscordGateway/WS"
import { Log } from "dfx/Log"
import { LiveRateLimiter, RateLimiter } from "dfx/RateLimit"
import { RateLimiterLive, RateLimiter } from "dfx/RateLimit"
import * as Discord from "dfx/types"

const enum Phase {
Expand Down Expand Up @@ -191,9 +191,9 @@ export const make = Effect.gen(function* (_) {

export interface Shard extends Effect.Effect.Success<typeof make> {}
export const Shard = Tag<Shard>()
export const LiveShard = Layer.provide(
export const ShardLive = Layer.provide(
Layer.effect(Shard, make),
Layer.merge(LiveDiscordWS, LiveRateLimiter),
Layer.merge(DiscordWSLive, RateLimiterLive),
)

export interface RunningShard
Expand Down
2 changes: 1 addition & 1 deletion src/DiscordGateway/ShardStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ const memoryStore = (): ShardStore => {
}
}

export const LiveMemoryShardStore = Layer.sync(ShardStore, memoryStore)
export const MemoryShardStoreLive = Layer.sync(ShardStore, memoryStore)
8 changes: 4 additions & 4 deletions src/DiscordGateway/Sharder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import * as Ref from "effect/Ref"
import * as Schedule from "effect/Schedule"
import { DiscordConfig } from "dfx/DiscordConfig"
import type { RunningShard } from "dfx/DiscordGateway/Shard"
import { LiveShard, Shard } from "dfx/DiscordGateway/Shard"
import { ShardLive, Shard } from "dfx/DiscordGateway/Shard"
import { ShardStore } from "dfx/DiscordGateway/ShardStore"
import type { WebSocketCloseError, WebSocketError } from "dfx/DiscordGateway/WS"
import { DiscordREST } from "dfx/DiscordREST"
import { LiveRateLimiter, RateLimiter } from "dfx/RateLimit"
import { RateLimiterLive, RateLimiter } from "dfx/RateLimit"
import type * as Discord from "dfx/types"

const claimRepeatPolicy = Schedule.spaced("3 minutes").pipe(
Expand Down Expand Up @@ -134,7 +134,7 @@ const make = Effect.gen(function* (_) {

export interface Sharder extends Effect.Effect.Success<typeof make> {}
export const Sharder = Tag<Sharder>()
export const LiveSharder = Layer.provide(
export const SharedLive = Layer.provide(
Layer.effect(Sharder, make),
Layer.merge(LiveRateLimiter, LiveShard),
Layer.merge(RateLimiterLive, ShardLive),
)
2 changes: 1 addition & 1 deletion src/DiscordGateway/WS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,4 @@ const make = Effect.gen(function* (_) {

export interface WS extends Effect.Effect.Success<typeof make> {}
export const WS = Tag<WS>()
export const LiveWS = Layer.effect(WS, make)
export const WSLive = Layer.effect(WS, make)
6 changes: 3 additions & 3 deletions src/DiscordREST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
routeFromConfig,
} from "dfx/DiscordREST/utils"
import { Log } from "dfx/Log"
import { LiveRateLimiter, RateLimiter, RateLimitStore } from "dfx/RateLimit"
import { RateLimiterLive, RateLimiter, RateLimitStore } from "dfx/RateLimit"
import * as Discord from "dfx/types"
import { LIB_VERSION } from "dfx/version"

Expand Down Expand Up @@ -254,7 +254,7 @@ export interface DiscordREST
}

export const DiscordREST = Tag<DiscordREST>()
export const LiveDiscordREST = Layer.effect(DiscordREST, make).pipe(
Layer.provide(LiveRateLimiter),
export const DiscordRESTLive = Layer.effect(DiscordREST, make).pipe(
Layer.provide(RateLimiterLive),
Layer.provide(Http.client.layer),
)
94 changes: 48 additions & 46 deletions src/Interactions/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ import { builder, Interaction } from "dfx/Interactions/index"
import type * as Discord from "dfx/types"
import * as EffectUtils from "dfx/utils/Effect"
import * as Schedule from "effect/Schedule"
import { globalValue } from "effect/GlobalValue"
import * as FiberRef from "effect/FiberRef"

export interface RunOpts {
sync?: boolean
}
export const interactionsSync: FiberRef.FiberRef<boolean> = globalValue(
"dfx/Interactions/sync",
() => FiberRef.unsafeMake(true),
)

export const setInteractionsSync = (enabled: boolean) =>
Layer.locally(interactionsSync, enabled)

/**
* @tsplus pipeable dfx/InteractionBuilder runGateway
*/
export const run =
<R, R2, E, TE, E2>(
postHandler: (
Expand All @@ -38,7 +41,6 @@ export const run =
void
>,
) => Effect.Effect<R2, E2, void>,
{ sync = true }: RunOpts = {},
) =>
(
ix: InteractionBuilder<R, E, TE>,
Expand Down Expand Up @@ -100,6 +102,8 @@ export const run =
Effect.provideService(postHandler(handle[i.type](i)), Interaction, i),
)

const sync = yield* _(FiberRef.get(interactionsSync))

return yield* _(
sync
? Effect.forever(
Expand All @@ -112,55 +116,53 @@ export const run =
)
})

const makeRegistry = (options?: RunOpts) =>
Effect.gen(function* (_) {
const ref = yield* _(
Ref.make(builder as InteractionBuilder<never, never, never>),
)
const queue = yield* _(
Queue.sliding<InteractionBuilder<never, never, never>>(1),
)
const makeRegistry = Effect.gen(function* (_) {
const ref = yield* _(
Ref.make(builder as InteractionBuilder<never, never, never>),
)
const queue = yield* _(
Queue.sliding<InteractionBuilder<never, never, never>>(1),
)

const register = <E>(ix: InteractionBuilder<never, E, never>) =>
Effect.flatMap(
Ref.updateAndGet(ref, _ => _.concat(ix as any)),
_ => Queue.offer(queue, _),
)
const register = <E>(ix: InteractionBuilder<never, E, never>) =>
Effect.flatMap(
Ref.updateAndGet(ref, _ => _.concat(ix as any)),
_ => Queue.offer(queue, _),
)

yield* _(
EffectUtils.foreverSwitch(Queue.take(queue), ix =>
pipe(
ix,
run(
Effect.catchAllCause(_ => Effect.logError("unhandled error", _)),
options,
),
Effect.delay(Duration.seconds(0.1)),
),
yield* _(
EffectUtils.foreverSwitch(Queue.take(queue), ix =>
pipe(
ix,
run(Effect.catchAllCause(_ => Effect.logError("unhandled error", _))),
Effect.delay(Duration.seconds(0.1)),
),
Effect.tapErrorCause(_ => Effect.logError("registry error", _)),
Effect.retry(
Schedule.exponential("1 seconds").pipe(
Schedule.union(Schedule.spaced("20 seconds")),
),
),
Effect.tapErrorCause(_ => Effect.logError("registry error", _)),
Effect.retry(
Schedule.exponential("1 seconds").pipe(
Schedule.union(Schedule.spaced("20 seconds")),
),
Effect.forkScoped,
)

return { register } as const
}).pipe(
Effect.annotateLogs({
package: "dfx",
service: "InteractionsRegistry",
}),
),
Effect.forkScoped,
)

return { register } as const
}).pipe(
Effect.annotateLogs({
package: "dfx",
service: "InteractionsRegistry",
}),
)

export interface InteractionsRegistry {
readonly register: <E>(
ix: InteractionBuilder<never, E, never>,
) => Effect.Effect<never, never, void>
}

export const InteractionsRegistry = Tag<InteractionsRegistry>()
export const InteractionsRegistryLive = (options?: RunOpts) =>
Layer.scoped(InteractionsRegistry, makeRegistry(options))
export const InteractionsRegistryLive = Layer.scoped(
InteractionsRegistry,
makeRegistry,
)
4 changes: 2 additions & 2 deletions src/Interactions/webhook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ const makeConfig = ({
export interface WebhookConfig extends ReturnType<typeof makeConfig> {}
export const WebhookConfig = Tag<WebhookConfig>()

export const makeConfigLayer = (opts: MakeConfigOpts) =>
export const layer = (opts: MakeConfigOpts) =>
Layer.succeed(WebhookConfig, makeConfig(opts))

export const makeFromConfig: (
export const layerConfig: (
a: Config.Config<MakeConfigOpts>,
) => Layer.Layer<never, ConfigError.ConfigError, WebhookConfig> = (
a: Config.Config<MakeConfigOpts>,
Expand Down
7 changes: 5 additions & 2 deletions src/Log.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DiscordConfig } from "dfx/DiscordConfig"
import { Tag } from "effect/Context"
import * as Effect from "effect/Effect"
import * as Layer from "effect/Layer"
Expand All @@ -17,5 +18,7 @@ const make = (debug = false) => ({

export interface Log extends ReturnType<typeof make> {}
export const Log = Tag<Log>()
export const LiveLog = Layer.succeed(Log, make(false))
export const LiveLogDebug = Layer.succeed(Log, make(true))
export const LogLive = Layer.effect(
Log,
Effect.map(DiscordConfig, config => make(config.debug)),
)
2 changes: 1 addition & 1 deletion src/RateLimit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@ const makeLimiter = Effect.gen(function* (_) {
export interface RateLimiter
extends Effect.Effect.Success<typeof makeLimiter> {}
export const RateLimiter = Tag<RateLimiter>()
export const LiveRateLimiter = Layer.effect(RateLimiter, makeLimiter)
export const RateLimiterLive = Layer.effect(RateLimiter, makeLimiter)
Loading

0 comments on commit 7aeb5ec

Please sign in to comment.