diff --git a/package.json b/package.json
index 88e404f..3bfad80 100644
--- a/package.json
+++ b/package.json
@@ -15,8 +15,8 @@
"prepare": "husky"
},
"dependencies": {
- "@effect/schema": "^0.67.18",
- "effect": "^3.5.8",
+ "@effect/schema": "^0.71.1",
+ "effect": "^3.6.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
diff --git a/packages/components/add-provider/package.json b/packages/components/add-provider/package.json
index 7abc669..0002e2c 100644
--- a/packages/components/add-provider/package.json
+++ b/packages/components/add-provider/package.json
@@ -10,9 +10,10 @@
"@echo/core-types": "^1.0.0",
"@echo/services-bootstrap": "^1.0.0",
"@echo/services-bootstrap-services": "^1.0.0",
+ "@echo/services-add-provider-workflow": "^1.0.0",
"@effect-rx/rx": "^0.33.8",
"@effect-rx/rx-react": "^0.30.11",
- "effect": "^3.2.8"
+ "effect": "^3.6.5"
},
"devDependencies": {
"@types/react": "^18.2.66",
diff --git a/packages/components/add-provider/src/AddProvider.tsx b/packages/components/add-provider/src/AddProvider.tsx
index f1874a9..dc9dfdc 100644
--- a/packages/components/add-provider/src/AddProvider.tsx
+++ b/packages/components/add-provider/src/AddProvider.tsx
@@ -1,37 +1,22 @@
import {
- ActiveMediaProviderCache,
+ AddProviderWorkflow,
AvailableProviders,
- MediaProviderMainThreadBroadcastChannel,
- type Authentication,
- type AuthenticationInfo,
type FolderMetadata,
- type MediaPlayer,
- type MediaProvider,
type ProviderMetadata,
} from "@echo/core-types";
-import { LazyLoadedProvider } from "@echo/services-bootstrap";
+import { AddProviderWorkflowLive } from "@echo/services-add-provider-workflow";
import { AppLive } from "@echo/services-bootstrap-services";
-import { LazyLoadedMediaPlayer } from "@echo/services-bootstrap/src/loaders";
import { Rx } from "@effect-rx/rx";
import { useRx } from "@effect-rx/rx-react";
-import { Effect, Match } from "effect";
-import { useCallback, useEffect, useMemo } from "react";
+import { Layer, Match } from "effect";
+import { useCallback } from "react";
-const runtime = Rx.runtime(AppLive);
-const loadProviderFn = runtime.fn(LazyLoadedProvider.load);
-const loadMediaPlayerFn = runtime.fn(
- ({
- metadata,
- authInfo,
- }: {
- metadata: ProviderMetadata;
- authInfo: AuthenticationInfo;
- }) =>
- Effect.gen(function* () {
- const { createMediaPlayer } = yield* LazyLoadedMediaPlayer.load(metadata);
- return yield* createMediaPlayer(authInfo);
- }),
+const runtime = Rx.runtime(
+ AddProviderWorkflowLive.pipe(Layer.provide(AppLive)),
);
+const loadProviderFn = runtime.fn(AddProviderWorkflow.loadProvider);
+const connectToProviderFn = runtime.fn(AddProviderWorkflow.connectToProvider);
+const selectRootFn = runtime.fn(AddProviderWorkflow.selectRoot);
export const AddProvider = () => {
const [loadStatus, loadProvider] = useRx(loadProviderFn);
@@ -47,16 +32,7 @@ export const AddProvider = () => {
Match.tag("Initial", () => (
)),
- Match.tag(
- "Success",
- ({ value: { metadata, authentication, createMediaProvider } }) => (
-
- ),
- ),
+ Match.tag("Success", () => ),
Match.tag("Failure", () => (
Failed to load provider.
)),
@@ -77,35 +53,18 @@ const ProviderSelector = ({
));
-const authenticateFn = runtime.fn(
- (authentication: Authentication) => authentication.connect,
-);
-
-const ProviderAuthenticator = ({
- metadata,
- authentication,
- createMediaProvider,
-}: {
- metadata: ProviderMetadata;
- authentication: Authentication;
- createMediaProvider: (authInfo: AuthenticationInfo) => MediaProvider;
-}) => {
- const [connectionStatus, connectToProvider] = useRx(authenticateFn);
- const _connectToProvider = () => connectToProvider(authentication);
+const ProviderAuthenticator = () => {
+ const [connectionStatus, connectToProvider] = useRx(connectToProviderFn);
+ const _connectToProvider = () => connectToProvider();
return (
- {metadata.id}
{Match.value(connectionStatus).pipe(
Match.tag("Initial", () => (
)),
- Match.tag("Success", ({ value: authInfo }) => (
-
+ Match.tag("Success", ({ value: rootFolderContent }) => (
+
)),
Match.tag("Failure", (error) => (
Error: {JSON.stringify(error)}
@@ -116,128 +75,17 @@ const ProviderAuthenticator = ({
);
};
-const listRootFn = runtime.fn(
- (mediaProvider: MediaProvider) => mediaProvider.listRoot,
-);
-
-const addMediaProviderToCacheFn = runtime.fn(
- ({
- metadata,
- provider,
- player,
- }: {
- metadata: ProviderMetadata;
- provider: MediaProvider;
- player: MediaPlayer;
- }) => ActiveMediaProviderCache.add(metadata, provider, player),
-);
-
const SelectRoot = ({
- authInfo,
- metadata,
- createMediaProvider,
-}: {
- authInfo: AuthenticationInfo;
- metadata: ProviderMetadata;
- createMediaProvider: (authInfo: AuthenticationInfo) => MediaProvider;
-}) => {
- const [mediaPlayerStatus, createMediaPlayer] = useRx(loadMediaPlayerFn);
-
- const mediaProvider = useMemo(
- () => createMediaProvider(authInfo),
- [createMediaProvider, authInfo],
- );
-
- const [listStatus, listRoot] = useRx(listRootFn);
- const [, addMediaProviderToCache] = useRx(addMediaProviderToCacheFn);
-
- useEffect(() => {
- listRoot(mediaProvider);
- createMediaPlayer({ metadata, authInfo });
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
-
- // TODO: Refactor this mess somehow?
- useEffect(() => {
- Match.value(mediaPlayerStatus).pipe(
- Match.tag("Success", ({ value: player }) => {
- addMediaProviderToCache({
- metadata,
- provider: mediaProvider,
- player,
- });
- }),
- );
- }, [mediaPlayerStatus, mediaProvider, metadata, addMediaProviderToCache]);
-
- return (
-
- {Match.value(listStatus).pipe(
- Match.tag("Initial", () => (
-
Loading root of media provider...
- )),
- Match.tag("Success", ({ value: folders }) => (
-
- )),
- Match.tag("Failure", (error) => (
-
Error: {JSON.stringify(error)}
- )),
- Match.exhaustive,
- )}
-
- );
-};
-
-const startMediaProviderEffect = (
- authInfo: AuthenticationInfo,
- metadata: ProviderMetadata,
- rootFolder: FolderMetadata,
-) =>
- Effect.gen(function* () {
- const broadcastChannel = yield* MediaProviderMainThreadBroadcastChannel;
-
- yield* broadcastChannel.send("start", {
- _tag: "file-based",
- metadata,
- authInfo,
- rootFolder,
- });
- });
-
-const startMediaProviderFn = runtime.fn(
- ({
- authInfo,
- metadata,
- rootFolder,
- }: {
- authInfo: AuthenticationInfo;
- metadata: ProviderMetadata;
- rootFolder: FolderMetadata;
- }) => startMediaProviderEffect(authInfo, metadata, rootFolder),
-);
-
-const FolderSelector = ({
- authInfo,
- folders,
- metadata,
+ rootFolderContent: folders,
}: {
- authInfo: AuthenticationInfo;
- folders: FolderMetadata[];
- metadata: ProviderMetadata;
+ rootFolderContent: FolderMetadata[];
}) => {
- const [selectRootStatus, selectRoot] = useRx(startMediaProviderFn);
+ const [selectRootStatus, selectRoot] = useRx(selectRootFn);
return Match.value(selectRootStatus).pipe(
Match.tag("Initial", () =>
folders.map((folder) => (
-