mirror of
https://github.com/Jellify-Music/App.git
synced 2025-12-21 10:39:59 -06:00
Can I switch to a singleton for the api client?
This commit is contained in:
144
api/client.ts
144
api/client.ts
@@ -1,36 +1,118 @@
|
||||
import { Api, Jellyfin } from "@jellyfin/sdk";
|
||||
import { getDeviceNameSync, getUniqueIdSync } from "react-native-device-info";
|
||||
import { name, version } from "../package.json"
|
||||
import { capitalize } from "lodash";
|
||||
import { Api } from "@jellyfin/sdk/lib/api";
|
||||
import { JellyfinInfo } from "./info";
|
||||
import { JellifyServer } from "@/types/JellifyServer";
|
||||
import { JellifyUser } from "@/types/JellifyUser";
|
||||
import { storage } from '../constants/storage';
|
||||
import { MMKVStorageKeys } from "@/enums/mmkv-storage-keys";
|
||||
import uuid from 'react-native-uuid';
|
||||
import { JellifyLibrary } from "@/types/JellifyLibrary";
|
||||
|
||||
/**
|
||||
* Client object that represents Jellify on the Jellyfin server.
|
||||
*/
|
||||
export const jellifyClient: Jellyfin = new Jellyfin({
|
||||
clientInfo: {
|
||||
name: capitalize(name),
|
||||
version: version
|
||||
},
|
||||
deviceInfo: {
|
||||
name: getDeviceNameSync(),
|
||||
id: getUniqueIdSync()
|
||||
|
||||
export default class Client {
|
||||
static #instance: Client;
|
||||
|
||||
public api : Api | undefined;
|
||||
public user : JellifyUser | undefined;
|
||||
public server : JellifyServer | undefined;
|
||||
public library : JellifyLibrary | undefined;
|
||||
public sessionId : string = uuid.v4();
|
||||
|
||||
private constructor(
|
||||
api?: Api | undefined,
|
||||
user?: JellifyUser | undefined,
|
||||
server?: JellifyServer | undefined,
|
||||
library?: JellifyLibrary | undefined
|
||||
) {
|
||||
|
||||
const userJson = storage.getString(MMKVStorageKeys.User)
|
||||
const serverJson = storage.getString(MMKVStorageKeys.Server);
|
||||
const libraryJson = storage.getString(MMKVStorageKeys.Library);
|
||||
|
||||
|
||||
if (api)
|
||||
this.api = api
|
||||
|
||||
if (user)
|
||||
this.setAndPersistUser
|
||||
else if (userJson)
|
||||
this.user = JSON.parse(userJson)
|
||||
|
||||
if (server)
|
||||
this.setAndPersistServer(server)
|
||||
else if (serverJson)
|
||||
this.server = JSON.parse(serverJson);
|
||||
|
||||
if (library)
|
||||
this.setAndPersistLibrary(library)
|
||||
else if (libraryJson)
|
||||
this.library = JSON.parse(libraryJson)
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Uses the jellifyClient to create a public Jellyfin API instance.
|
||||
* @param serverUrl The URL of the Jellyfin server
|
||||
* @returns
|
||||
*/
|
||||
export function buildPublicApiClient(serverUrl : string) : Api {
|
||||
return jellifyClient.createApi(serverUrl);
|
||||
}
|
||||
public static get instance(): Client {
|
||||
if (!Client.#instance) {
|
||||
Client.#instance = new Client();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param serverUrl The URL of the Jellyfin server
|
||||
* @param accessToken The assigned accessToken for the Jellyfin user
|
||||
*/
|
||||
export function buildAuthenticatedApiClient(serverUrl: string, accessToken: string) : Api {
|
||||
return jellifyClient.createApi(serverUrl, accessToken);
|
||||
return Client.#instance;
|
||||
}
|
||||
|
||||
public static signOut(): void {
|
||||
if (!Client.#instance) {
|
||||
Client.instance;
|
||||
}
|
||||
|
||||
Client.instance.removeCredentials()
|
||||
}
|
||||
|
||||
private setAndPersistUser(user: JellifyUser) {
|
||||
this.user = user;
|
||||
|
||||
// persist user details
|
||||
storage.set(MMKVStorageKeys.User, JSON.stringify(user));
|
||||
}
|
||||
|
||||
private setAndPersistServer(server : JellifyServer) {
|
||||
this.server = server;
|
||||
|
||||
storage.set(MMKVStorageKeys.Server, JSON.stringify(server));
|
||||
}
|
||||
|
||||
private setAndPersistLibrary(library : JellifyLibrary) {
|
||||
this.library = library;
|
||||
|
||||
storage.set(MMKVStorageKeys.Library, JSON.stringify(library))
|
||||
}
|
||||
|
||||
private removeCredentials() {
|
||||
this.library = undefined;
|
||||
this.library = undefined;
|
||||
this.server = undefined;
|
||||
this.user = undefined;
|
||||
|
||||
storage.delete(MMKVStorageKeys.Server)
|
||||
storage.delete(MMKVStorageKeys.Library)
|
||||
storage.delete(MMKVStorageKeys.User)
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the jellifyClient to create a public Jellyfin API instance.
|
||||
* @param serverUrl The URL of the Jellyfin server
|
||||
* @returns
|
||||
*/
|
||||
public static setPublicApiClient(server : JellifyServer) : void {
|
||||
const api = JellyfinInfo.createApi(server.url);
|
||||
|
||||
Client.#instance = new Client(api, undefined, server, undefined)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param serverUrl The URL of the Jellyfin server
|
||||
* @param accessToken The assigned accessToken for the Jellyfin user
|
||||
*/
|
||||
public static setPrivateApiClient(server : JellifyServer, user : JellifyUser) : void {
|
||||
const api = JellyfinInfo.createApi(server.url, user.accessToken);
|
||||
|
||||
Client.#instance = new Client(api, user, server, undefined)
|
||||
}
|
||||
}
|
||||
18
api/info.ts
Normal file
18
api/info.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Api, Jellyfin } from "@jellyfin/sdk";
|
||||
import { getDeviceNameSync, getUniqueIdSync } from "react-native-device-info";
|
||||
import { name, version } from "../package.json"
|
||||
import { capitalize } from "lodash";
|
||||
|
||||
/**
|
||||
* Client object that represents Jellify on the Jellyfin server.
|
||||
*/
|
||||
export const JellyfinInfo: Jellyfin = new Jellyfin({
|
||||
clientInfo: {
|
||||
name: capitalize(name),
|
||||
version: version
|
||||
},
|
||||
deviceInfo: {
|
||||
name: getDeviceNameSync(),
|
||||
id: getUniqueIdSync()
|
||||
}
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Api } from "@jellyfin/sdk";
|
||||
import { jellifyClient } from "../../client";
|
||||
import { JellyfinInfo } from "../../info";
|
||||
import _ from "lodash";
|
||||
|
||||
export function createApi(serverUrl?: string, username?: string, password?: string, accessToken?: string): Promise<Api> {
|
||||
@@ -12,22 +12,22 @@ export function createApi(serverUrl?: string, username?: string, password?: stri
|
||||
|
||||
if (!_.isUndefined(accessToken)) {
|
||||
console.info("Creating API with accessToken")
|
||||
return resolve(jellifyClient.createApi(serverUrl, accessToken));
|
||||
return resolve(JellyfinInfo.createApi(serverUrl, accessToken));
|
||||
}
|
||||
|
||||
|
||||
if (_.isUndefined(username) && _.isUndefined(password)) {
|
||||
|
||||
console.info("Creating public API for server url")
|
||||
return resolve(jellifyClient.createApi(serverUrl));
|
||||
return resolve(JellyfinInfo.createApi(serverUrl));
|
||||
}
|
||||
|
||||
console.log("Signing into Jellyfin")
|
||||
let authResult = await jellifyClient.createApi(serverUrl).authenticateUserByName(username!, password);
|
||||
let authResult = await JellyfinInfo.createApi(serverUrl).authenticateUserByName(username!, password);
|
||||
|
||||
if (authResult.data.AccessToken) {
|
||||
console.info("Signed into Jellyfin successfully")
|
||||
return resolve(jellifyClient.createApi(serverUrl, authResult.data.AccessToken));
|
||||
return resolve(JellyfinInfo.createApi(serverUrl, authResult.data.AccessToken));
|
||||
}
|
||||
|
||||
return reject("Unable to sign in");
|
||||
|
||||
@@ -11,7 +11,7 @@ import Input from "../../Global/helpers/input";
|
||||
import Button from "../../Global/helpers/button";
|
||||
import { http, https } from "../utils/constants";
|
||||
import { storage } from "../../../constants/storage";
|
||||
import { jellifyClient } from "../../../api/client";
|
||||
import { JellyfinInfo } from "../../../api/info";
|
||||
import { Jellyfin } from "@jellyfin/sdk/lib/jellyfin";
|
||||
import { getSystemApi } from "@jellyfin/sdk/lib/utils/api/system-api";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
@@ -25,7 +25,7 @@ export default function ServerAddress(): React.JSX.Element {
|
||||
|
||||
const useServerMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
let jellyfin = new Jellyfin(jellifyClient);
|
||||
let jellyfin = new JellyfinInfo(JellyfinInfo);
|
||||
|
||||
if (!!!serverAddress)
|
||||
throw new Error("Server address was empty");
|
||||
|
||||
@@ -8,7 +8,7 @@ import { JellifyServer } from '../types/JellifyServer';
|
||||
import { JellifyLibrary } from '../types/JellifyLibrary';
|
||||
import { JellifyUser } from '../types/JellifyUser';
|
||||
import uuid from 'react-native-uuid';
|
||||
import { buildAuthenticatedApiClient, buildPublicApiClient } from '@/api/client';
|
||||
import Client from '@/api/client';
|
||||
|
||||
interface JellyfinApiClientContext {
|
||||
apiClient: Api | undefined;
|
||||
@@ -24,19 +24,17 @@ interface JellyfinApiClientContext {
|
||||
|
||||
const JellyfinApiClientContextInitializer = () => {
|
||||
|
||||
const userJson = storage.getString(MMKVStorageKeys.User)
|
||||
const serverJson = storage.getString(MMKVStorageKeys.Server);
|
||||
const libraryJson = storage.getString(MMKVStorageKeys.Library);
|
||||
|
||||
const [sessionId, setSessionId] = useState<string>(uuid.v4())
|
||||
const [user, setUser] = useState<JellifyUser | undefined>(userJson ? (JSON.parse(userJson) as JellifyUser) : undefined);
|
||||
const [server, setServer] = useState<JellifyServer | undefined>(serverJson ? (JSON.parse(serverJson) as JellifyServer) : undefined);
|
||||
const [library, setLibrary] = useState<JellifyLibrary | undefined>(libraryJson ? (JSON.parse(libraryJson) as JellifyLibrary) : undefined);
|
||||
|
||||
const [apiClient, setApiClient] = useState<Api | undefined>(!isUndefined(server) && !isUndefined(user) ? buildAuthenticatedApiClient(server!.url, user!.accessToken) : undefined);
|
||||
const [apiClient, setApiClient] = useState<Api | undefined>(Client.instance.api);
|
||||
const [sessionId, setSessionId] = useState<string>(Client.instance.sessionId);
|
||||
const [user, setUser] = useState<JellifyUser | undefined>(Client.instance.user);
|
||||
const [server, setServer] = useState<JellifyServer | undefined>(Client.instance.server);
|
||||
const [library, setLibrary] = useState<JellifyLibrary | undefined>(Client.instance.library);
|
||||
|
||||
const signOut = () => {
|
||||
console.debug("Signing out of Jellify");
|
||||
|
||||
Client.signOut();
|
||||
|
||||
setUser(undefined);
|
||||
setServer(undefined);
|
||||
setLibrary(undefined);
|
||||
@@ -44,11 +42,11 @@ const JellyfinApiClientContextInitializer = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (server && user)
|
||||
setApiClient(buildAuthenticatedApiClient(server.url, user.accessToken));
|
||||
Client.setPrivateApiClient(server, user)
|
||||
else if (server)
|
||||
setApiClient(buildPublicApiClient(server.url));
|
||||
Client.setPublicApiClient(server)
|
||||
else
|
||||
setApiClient(undefined);
|
||||
Client.signOut();
|
||||
}, [
|
||||
server,
|
||||
user
|
||||
|
||||
2
index.js
2
index.js
@@ -4,6 +4,8 @@ import App from './App';
|
||||
import {name as appName} from './app.json';
|
||||
import { PlaybackService } from './player/service'
|
||||
import TrackPlayer from 'react-native-track-player';
|
||||
import { Client } from './api/client';
|
||||
|
||||
Client.instance;
|
||||
AppRegistry.registerComponent(appName, () => App);
|
||||
TrackPlayer.registerPlaybackService(() => PlaybackService);
|
||||
Reference in New Issue
Block a user