mirror of
https://github.com/ente-io/ente.git
synced 2025-08-09 15:59:00 +00:00
The rest
This commit is contained in:
parent
1aef9cf179
commit
1b77c899da
@ -317,8 +317,9 @@ const downloadFile = async (
|
|||||||
if (!isImageOrLivePhoto(file))
|
if (!isImageOrLivePhoto(file))
|
||||||
throw new Error("Can only cast images and live photos");
|
throw new Error("Can only cast images and live photos");
|
||||||
|
|
||||||
|
const customOrigin = await customAPIOrigin();
|
||||||
|
|
||||||
const getFile = () => {
|
const getFile = () => {
|
||||||
const customOrigin = customAPIOrigin();
|
|
||||||
if (customOrigin) {
|
if (customOrigin) {
|
||||||
// See: [Note: Passing credentials for self-hosted file fetches]
|
// See: [Note: Passing credentials for self-hosted file fetches]
|
||||||
const params = new URLSearchParams({ castToken });
|
const params = new URLSearchParams({ castToken });
|
||||||
|
@ -679,15 +679,15 @@ const ExitSection: React.FC = () => {
|
|||||||
const DebugSection: React.FC = () => {
|
const DebugSection: React.FC = () => {
|
||||||
const appContext = useContext(AppContext);
|
const appContext = useContext(AppContext);
|
||||||
const [appVersion, setAppVersion] = useState<string | undefined>();
|
const [appVersion, setAppVersion] = useState<string | undefined>();
|
||||||
|
const [host, setHost] = useState<string | undefined>();
|
||||||
|
|
||||||
const electron = globalThis.electron;
|
const electron = globalThis.electron;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
electron?.appVersion().then((v) => setAppVersion(v));
|
void electron?.appVersion().then(setAppVersion);
|
||||||
|
void customAPIHost().then(setHost);
|
||||||
});
|
});
|
||||||
|
|
||||||
const host = customAPIHost();
|
|
||||||
|
|
||||||
const confirmLogDownload = () =>
|
const confirmLogDownload = () =>
|
||||||
appContext.setDialogMessage({
|
appContext.setDialogMessage({
|
||||||
title: t("DOWNLOAD_LOGS"),
|
title: t("DOWNLOAD_LOGS"),
|
||||||
|
@ -22,7 +22,7 @@ import { t } from "i18next";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { CarouselProvider, DotGroup, Slide, Slider } from "pure-react-carousel";
|
import { CarouselProvider, DotGroup, Slide, Slider } from "pure-react-carousel";
|
||||||
import "pure-react-carousel/dist/react-carousel.es.css";
|
import "pure-react-carousel/dist/react-carousel.es.css";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState, useCallback } from "react";
|
||||||
import { Trans } from "react-i18next";
|
import { Trans } from "react-i18next";
|
||||||
import { useAppContext } from "./_app";
|
import { useAppContext } from "./_app";
|
||||||
|
|
||||||
@ -31,14 +31,17 @@ export default function LandingPage() {
|
|||||||
|
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [showLogin, setShowLogin] = useState(true);
|
const [showLogin, setShowLogin] = useState(true);
|
||||||
// This is kept as state because it can change as a result of user action
|
const [host, setHost] = useState<string | undefined>();
|
||||||
// while we're on this page (there currently isn't an event listener we can
|
|
||||||
// attach to for observing changes to local storage by the same window).
|
|
||||||
const [host, setHost] = useState(customAPIHost());
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const refreshHost = useCallback(
|
||||||
|
() => void customAPIHost().then(setHost),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
refreshHost();
|
||||||
showNavBar(false);
|
showNavBar(false);
|
||||||
const currentURL = new URL(window.location.href);
|
const currentURL = new URL(window.location.href);
|
||||||
const albumsURL = new URL(albumsAppOrigin());
|
const albumsURL = new URL(albumsAppOrigin());
|
||||||
@ -51,9 +54,7 @@ export default function LandingPage() {
|
|||||||
} else {
|
} else {
|
||||||
handleNormalRedirect();
|
handleNormalRedirect();
|
||||||
}
|
}
|
||||||
}, []);
|
}, [refreshHost]);
|
||||||
|
|
||||||
const handleMaybeChangeHost = () => setHost(customAPIHost());
|
|
||||||
|
|
||||||
const handleAlbumsRedirect = async (currentURL: URL) => {
|
const handleAlbumsRedirect = async (currentURL: URL) => {
|
||||||
const end = currentURL.hash.lastIndexOf("&");
|
const end = currentURL.hash.lastIndexOf("&");
|
||||||
@ -117,7 +118,7 @@ export default function LandingPage() {
|
|||||||
const redirectToLoginPage = () => router.push(PAGES.LOGIN);
|
const redirectToLoginPage = () => router.push(PAGES.LOGIN);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TappableContainer onMaybeChangeHost={handleMaybeChangeHost}>
|
<TappableContainer onMaybeChangeHost={refreshHost}>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<EnteSpinner />
|
<EnteSpinner />
|
||||||
) : (
|
) : (
|
||||||
|
@ -19,10 +19,11 @@ export class PhotosDownloadClient implements DownloadClient {
|
|||||||
const token = this.token;
|
const token = this.token;
|
||||||
if (!token) throw Error(CustomError.TOKEN_MISSING);
|
if (!token) throw Error(CustomError.TOKEN_MISSING);
|
||||||
|
|
||||||
|
const customOrigin = await customAPIOrigin();
|
||||||
|
|
||||||
// See: [Note: Passing credentials for self-hosted file fetches]
|
// See: [Note: Passing credentials for self-hosted file fetches]
|
||||||
const getThumbnail = () => {
|
const getThumbnail = () => {
|
||||||
const opts = { responseType: "arraybuffer", timeout: this.timeout };
|
const opts = { responseType: "arraybuffer", timeout: this.timeout };
|
||||||
const customOrigin = customAPIOrigin();
|
|
||||||
if (customOrigin) {
|
if (customOrigin) {
|
||||||
const params = new URLSearchParams({ token });
|
const params = new URLSearchParams({ token });
|
||||||
return HTTPService.get(
|
return HTTPService.get(
|
||||||
@ -53,6 +54,8 @@ export class PhotosDownloadClient implements DownloadClient {
|
|||||||
const token = this.token;
|
const token = this.token;
|
||||||
if (!token) throw Error(CustomError.TOKEN_MISSING);
|
if (!token) throw Error(CustomError.TOKEN_MISSING);
|
||||||
|
|
||||||
|
const customOrigin = await customAPIOrigin();
|
||||||
|
|
||||||
// See: [Note: Passing credentials for self-hosted file fetches]
|
// See: [Note: Passing credentials for self-hosted file fetches]
|
||||||
const getFile = () => {
|
const getFile = () => {
|
||||||
const opts = {
|
const opts = {
|
||||||
@ -61,7 +64,6 @@ export class PhotosDownloadClient implements DownloadClient {
|
|||||||
onDownloadProgress,
|
onDownloadProgress,
|
||||||
};
|
};
|
||||||
|
|
||||||
const customOrigin = customAPIOrigin();
|
|
||||||
if (customOrigin) {
|
if (customOrigin) {
|
||||||
const params = new URLSearchParams({ token });
|
const params = new URLSearchParams({ token });
|
||||||
return HTTPService.get(
|
return HTTPService.get(
|
||||||
@ -89,6 +91,8 @@ export class PhotosDownloadClient implements DownloadClient {
|
|||||||
const token = this.token;
|
const token = this.token;
|
||||||
if (!token) throw Error(CustomError.TOKEN_MISSING);
|
if (!token) throw Error(CustomError.TOKEN_MISSING);
|
||||||
|
|
||||||
|
const customOrigin = await customAPIOrigin();
|
||||||
|
|
||||||
// [Note: Passing credentials for self-hosted file fetches]
|
// [Note: Passing credentials for self-hosted file fetches]
|
||||||
//
|
//
|
||||||
// Fetching files (or thumbnails) in the default self-hosted Ente
|
// Fetching files (or thumbnails) in the default self-hosted Ente
|
||||||
@ -126,7 +130,6 @@ export class PhotosDownloadClient implements DownloadClient {
|
|||||||
// signed URL and stream back the response.
|
// signed URL and stream back the response.
|
||||||
|
|
||||||
const getFile = () => {
|
const getFile = () => {
|
||||||
const customOrigin = customAPIOrigin();
|
|
||||||
if (customOrigin) {
|
if (customOrigin) {
|
||||||
const params = new URLSearchParams({ token });
|
const params = new URLSearchParams({ token });
|
||||||
return fetch(
|
return fetch(
|
||||||
|
@ -20,6 +20,7 @@ export class PublicAlbumsDownloadClient implements DownloadClient {
|
|||||||
const accessToken = this.token;
|
const accessToken = this.token;
|
||||||
const accessTokenJWT = this.passwordToken;
|
const accessTokenJWT = this.passwordToken;
|
||||||
if (!accessToken) throw Error(CustomError.TOKEN_MISSING);
|
if (!accessToken) throw Error(CustomError.TOKEN_MISSING);
|
||||||
|
const customOrigin = await customAPIOrigin();
|
||||||
|
|
||||||
// See: [Note: Passing credentials for self-hosted file fetches]
|
// See: [Note: Passing credentials for self-hosted file fetches]
|
||||||
const getThumbnail = () => {
|
const getThumbnail = () => {
|
||||||
@ -27,7 +28,6 @@ export class PublicAlbumsDownloadClient implements DownloadClient {
|
|||||||
responseType: "arraybuffer",
|
responseType: "arraybuffer",
|
||||||
};
|
};
|
||||||
|
|
||||||
const customOrigin = customAPIOrigin();
|
|
||||||
if (customOrigin) {
|
if (customOrigin) {
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
accessToken,
|
accessToken,
|
||||||
@ -67,6 +67,8 @@ export class PublicAlbumsDownloadClient implements DownloadClient {
|
|||||||
const accessTokenJWT = this.passwordToken;
|
const accessTokenJWT = this.passwordToken;
|
||||||
if (!accessToken) throw Error(CustomError.TOKEN_MISSING);
|
if (!accessToken) throw Error(CustomError.TOKEN_MISSING);
|
||||||
|
|
||||||
|
const customOrigin = await customAPIOrigin();
|
||||||
|
|
||||||
// See: [Note: Passing credentials for self-hosted file fetches]
|
// See: [Note: Passing credentials for self-hosted file fetches]
|
||||||
const getFile = () => {
|
const getFile = () => {
|
||||||
const opts = {
|
const opts = {
|
||||||
@ -75,7 +77,6 @@ export class PublicAlbumsDownloadClient implements DownloadClient {
|
|||||||
onDownloadProgress,
|
onDownloadProgress,
|
||||||
};
|
};
|
||||||
|
|
||||||
const customOrigin = customAPIOrigin();
|
|
||||||
if (customOrigin) {
|
if (customOrigin) {
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
accessToken,
|
accessToken,
|
||||||
@ -112,9 +113,10 @@ export class PublicAlbumsDownloadClient implements DownloadClient {
|
|||||||
const accessTokenJWT = this.passwordToken;
|
const accessTokenJWT = this.passwordToken;
|
||||||
if (!accessToken) throw Error(CustomError.TOKEN_MISSING);
|
if (!accessToken) throw Error(CustomError.TOKEN_MISSING);
|
||||||
|
|
||||||
|
const customOrigin = await customAPIOrigin();
|
||||||
|
|
||||||
// See: [Note: Passing credentials for self-hosted file fetches]
|
// See: [Note: Passing credentials for self-hosted file fetches]
|
||||||
const getFile = () => {
|
const getFile = () => {
|
||||||
const customOrigin = customAPIOrigin();
|
|
||||||
if (customOrigin) {
|
if (customOrigin) {
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
accessToken,
|
accessToken,
|
||||||
|
@ -117,9 +117,10 @@ class UploadHttpClient {
|
|||||||
progressTracker,
|
progressTracker,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
try {
|
try {
|
||||||
|
const origin = await uploaderOrigin();
|
||||||
await retryHTTPCall(() =>
|
await retryHTTPCall(() =>
|
||||||
HTTPService.put(
|
HTTPService.put(
|
||||||
`${uploaderOrigin()}/file-upload`,
|
`${origin}/file-upload`,
|
||||||
file,
|
file,
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
@ -173,9 +174,10 @@ class UploadHttpClient {
|
|||||||
progressTracker,
|
progressTracker,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
const origin = await uploaderOrigin();
|
||||||
const response = await retryHTTPCall(async () => {
|
const response = await retryHTTPCall(async () => {
|
||||||
const resp = await HTTPService.put(
|
const resp = await HTTPService.put(
|
||||||
`${uploaderOrigin()}/multipart-upload`,
|
`${origin}/multipart-upload`,
|
||||||
filePart,
|
filePart,
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
@ -214,9 +216,10 @@ class UploadHttpClient {
|
|||||||
|
|
||||||
async completeMultipartUploadV2(completeURL: string, reqBody: any) {
|
async completeMultipartUploadV2(completeURL: string, reqBody: any) {
|
||||||
try {
|
try {
|
||||||
|
const origin = await uploaderOrigin();
|
||||||
await retryHTTPCall(() =>
|
await retryHTTPCall(() =>
|
||||||
HTTPService.post(
|
HTTPService.post(
|
||||||
`${uploaderOrigin()}/multipart-complete`,
|
`${origin}/multipart-complete`,
|
||||||
reqBody,
|
reqBody,
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
|
@ -13,12 +13,12 @@ const Page: React.FC<PageProps> = ({ appContext }) => {
|
|||||||
const { appName, showNavBar } = appContext;
|
const { appName, showNavBar } = appContext;
|
||||||
|
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [host, setHost] = useState<string | undefined>();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const host = customAPIHost();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
void customAPIHost().then(setHost);
|
||||||
const user = getData(LS_KEYS.USER);
|
const user = getData(LS_KEYS.USER);
|
||||||
if (user?.email) {
|
if (user?.email) {
|
||||||
router.push(PAGES.VERIFY);
|
router.push(PAGES.VERIFY);
|
||||||
|
@ -13,12 +13,12 @@ const Page: React.FC<PageProps> = ({ appContext }) => {
|
|||||||
const { appName } = appContext;
|
const { appName } = appContext;
|
||||||
|
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [host, setHost] = useState<string | undefined>();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const host = customAPIHost();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
void customAPIHost().then(setHost);
|
||||||
const user = getData(LS_KEYS.USER);
|
const user = getData(LS_KEYS.USER);
|
||||||
if (user?.email) {
|
if (user?.email) {
|
||||||
router.push(PAGES.VERIFY);
|
router.push(PAGES.VERIFY);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { nullToUndefined } from "@/utils/transform";
|
import { nullToUndefined } from "@/utils/transform";
|
||||||
|
import { get, set } from "idb-keyval";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the origin (scheme, host, port triple) that should be used for making
|
* Return the origin (scheme, host, port triple) that should be used for making
|
||||||
@ -7,7 +8,8 @@ import { nullToUndefined } from "@/utils/transform";
|
|||||||
* This defaults "https://api.ente.io", Ente's production API servers. but can
|
* This defaults "https://api.ente.io", Ente's production API servers. but can
|
||||||
* be overridden when self hosting or developing (see {@link customAPIOrigin}).
|
* be overridden when self hosting or developing (see {@link customAPIOrigin}).
|
||||||
*/
|
*/
|
||||||
export const apiOrigin = () => customAPIOrigin() ?? "https://api.ente.io";
|
export const apiOrigin = async () =>
|
||||||
|
(await customAPIOrigin()) ?? "https://api.ente.io";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the overridden API origin, if one is defined by either (in priority
|
* Return the overridden API origin, if one is defined by either (in priority
|
||||||
@ -20,10 +22,21 @@ export const apiOrigin = () => customAPIOrigin() ?? "https://api.ente.io";
|
|||||||
*
|
*
|
||||||
* Otherwise return undefined.
|
* Otherwise return undefined.
|
||||||
*/
|
*/
|
||||||
export const customAPIOrigin = () =>
|
export const customAPIOrigin = async () => {
|
||||||
nullToUndefined(localStorage.getItem("apiOrigin")) ??
|
let origin = await get<string>("apiOrigin");
|
||||||
process.env.NEXT_PUBLIC_ENTE_ENDPOINT ??
|
if (!origin) {
|
||||||
undefined;
|
// TODO: Migration of apiOrigin from local storage to indexed DB
|
||||||
|
// Remove me after a bit (27 June 2024).
|
||||||
|
const legacyOrigin = localStorage.getItem("apiOrigin");
|
||||||
|
if (legacyOrigin !== null) {
|
||||||
|
origin = nullToUndefined(legacyOrigin);
|
||||||
|
if (origin) await set("apiOrigin", origin);
|
||||||
|
localStorage.removeItem("apiOrigin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return origin ?? process.env.NEXT_PUBLIC_ENTE_ENDPOINT ?? undefined;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience wrapper over {@link customAPIOrigin} that returns the only the
|
* A convenience wrapper over {@link customAPIOrigin} that returns the only the
|
||||||
@ -31,8 +44,8 @@ export const customAPIOrigin = () =>
|
|||||||
*
|
*
|
||||||
* This is useful in places where we indicate the custom origin in the UI.
|
* This is useful in places where we indicate the custom origin in the UI.
|
||||||
*/
|
*/
|
||||||
export const customAPIHost = () => {
|
export const customAPIHost = async () => {
|
||||||
const origin = customAPIOrigin();
|
const origin = await customAPIOrigin();
|
||||||
return origin ? new URL(origin).host : undefined;
|
return origin ? new URL(origin).host : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -44,8 +57,8 @@ export const customAPIHost = () => {
|
|||||||
* this value is set to the {@link customAPIOrigin} itself, effectively
|
* this value is set to the {@link customAPIOrigin} itself, effectively
|
||||||
* bypassing the Cloudflare worker for non-Ente deployments.
|
* bypassing the Cloudflare worker for non-Ente deployments.
|
||||||
*/
|
*/
|
||||||
export const uploaderOrigin = () =>
|
export const uploaderOrigin = async () =>
|
||||||
customAPIOrigin() ?? "https://uploader.ente.io";
|
(await customAPIOrigin()) ?? "https://uploader.ente.io";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the origin that serves the accounts app.
|
* Return the origin that serves the accounts app.
|
||||||
|
@ -10,7 +10,7 @@ import EnteButton from "@ente/shared/components/EnteButton";
|
|||||||
import { CircularProgress, Stack, Typography, styled } from "@mui/material";
|
import { CircularProgress, Stack, Typography, styled } from "@mui/material";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { VerticallyCentered } from "./Container";
|
import { VerticallyCentered } from "./Container";
|
||||||
import type { DialogBoxAttributesV2 } from "./DialogBoxV2/types";
|
import type { DialogBoxAttributesV2 } from "./DialogBoxV2/types";
|
||||||
import { genericErrorAttributes } from "./ErrorComponents";
|
import { genericErrorAttributes } from "./ErrorComponents";
|
||||||
@ -48,7 +48,9 @@ const Header_ = styled("div")`
|
|||||||
export const LoginFlowFormFooter: React.FC<React.PropsWithChildren> = ({
|
export const LoginFlowFormFooter: React.FC<React.PropsWithChildren> = ({
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
const host = customAPIHost();
|
const [host, setHost] = useState<string | undefined>();
|
||||||
|
|
||||||
|
useEffect(() => void customAPIHost().then(setHost), []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormPaperFooter>
|
<FormPaperFooter>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user