Feat: may setup proxy (#238)
* add https proxy * remove proxy in renderer * proxy work for openai request * use proxyAgent to enable system proxy * add proxy setting * tweak proxy setting
This commit is contained in:
@@ -15,3 +15,5 @@ export * from "./balance-settings";
|
||||
|
||||
export * from "./reset-settings";
|
||||
export * from "./reset-all-settings";
|
||||
|
||||
export * from "./proxy-settings";
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
WhisperSettings,
|
||||
FfmpegSettings,
|
||||
OpenaiSettings,
|
||||
ProxySettings,
|
||||
GoogleGenerativeAiSettings,
|
||||
ResetSettings,
|
||||
ResetAllSettings,
|
||||
@@ -58,6 +59,8 @@ export const Preferences = () => {
|
||||
<div className="font-semibold mb-4 capitilized">
|
||||
{t("advancedSettings")}
|
||||
</div>
|
||||
<ProxySettings />
|
||||
<Separator />
|
||||
<ResetSettings />
|
||||
<Separator />
|
||||
<ResetAllSettings />
|
||||
|
||||
164
enjoy/src/renderer/components/preferences/proxy-settings.tsx
Normal file
164
enjoy/src/renderer/components/preferences/proxy-settings.tsx
Normal file
@@ -0,0 +1,164 @@
|
||||
import * as z from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "i18next";
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormControl,
|
||||
Switch,
|
||||
Input,
|
||||
toast,
|
||||
} from "@renderer/components/ui";
|
||||
import { InfoIcon } from "lucide-react";
|
||||
import { AppSettingsProviderContext } from "@renderer/context";
|
||||
import { useContext, useState, useEffect } from "react";
|
||||
|
||||
export const ProxySettings = () => {
|
||||
const { proxy, setProxy } = useContext(AppSettingsProviderContext);
|
||||
const [ipData, setIpData] = useState(null);
|
||||
const [editing, setEditing] = useState(false);
|
||||
|
||||
const proxyConfigSchema = z.object({
|
||||
enabled: z.boolean(),
|
||||
url: z.string().url(),
|
||||
});
|
||||
const form = useForm({
|
||||
mode: "onBlur",
|
||||
resolver: zodResolver(proxyConfigSchema),
|
||||
values: {
|
||||
enabled: proxy?.enabled,
|
||||
url: proxy?.url,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof proxyConfigSchema>) => {
|
||||
if (!data.url) {
|
||||
data.enabled = false;
|
||||
}
|
||||
|
||||
setProxy({
|
||||
enabled: data.enabled,
|
||||
url: data.url,
|
||||
})
|
||||
.then(() => {
|
||||
toast.success(t("proxyConfigUpdated"));
|
||||
})
|
||||
.finally(() => {
|
||||
setEditing(false);
|
||||
});
|
||||
};
|
||||
|
||||
const checkIp = async () => {
|
||||
fetch("https://ipapi.co/json")
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
setIpData(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
toast.error(error.message);
|
||||
setIpData(null);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
checkIp();
|
||||
}, [proxy]);
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div className="flex items-start justify-between py-4">
|
||||
<div className="">
|
||||
<div className="mb-2">{t("proxySettings")}</div>
|
||||
<div className="text-sm text-muted-foreground mb-2 ml-1">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="url"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="http://proxy:port"
|
||||
disabled={!editing}
|
||||
value={field.value || ""}
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{form.getValues("enabled") && ipData && (
|
||||
<div className="text-sm text-muted-foreground mb-2 ml-1">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div>
|
||||
IP: {ipData.ip} ({ipData.city}, {ipData.country_name})
|
||||
</div>
|
||||
<div>
|
||||
<InfoIcon size={16} className="cursor-pointer" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2 justify-end">
|
||||
{editing ? (
|
||||
<>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={(e) => {
|
||||
setEditing(!editing);
|
||||
e.preventDefault();
|
||||
}}
|
||||
size="sm"
|
||||
>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={() => setEditing(!editing)}
|
||||
size="sm"
|
||||
>
|
||||
{t("save")}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={(e) => {
|
||||
setEditing(!editing);
|
||||
e.preventDefault();
|
||||
}}
|
||||
size="sm"
|
||||
>
|
||||
{t("edit")}
|
||||
</Button>
|
||||
)}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="enabled"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Switch
|
||||
disabled={!form.getValues("url")}
|
||||
checked={field.value}
|
||||
onCheckedChange={(e) => {
|
||||
field.onChange(e);
|
||||
onSubmit(form.getValues());
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -22,6 +22,8 @@ type AppSettingsProviderState = {
|
||||
EnjoyApp?: EnjoyAppType;
|
||||
language?: "en" | "zh-CN";
|
||||
switchLanguage?: (language: "en" | "zh-CN") => void;
|
||||
proxy?: ProxyConfigType;
|
||||
setProxy?: (config: ProxyConfigType) => Promise<void>;
|
||||
};
|
||||
|
||||
const initialState: AppSettingsProviderState = {
|
||||
@@ -47,6 +49,7 @@ export const AppSettingsProvider = ({
|
||||
const [ffmpegConfig, setFfmegConfig] = useState<FfmpegConfigType>(null);
|
||||
const [ffmpeg, setFfmpeg] = useState<FFmpeg>(null);
|
||||
const [language, setLanguage] = useState<"en" | "zh-CN">();
|
||||
const [proxy, setProxy] = useState<ProxyConfigType>();
|
||||
const EnjoyApp = window.__ENJOY_APP__;
|
||||
|
||||
const ffmpegRef = useRef(new FFmpeg());
|
||||
@@ -58,6 +61,7 @@ export const AppSettingsProvider = ({
|
||||
fetchFfmpegConfig();
|
||||
fetchLanguage();
|
||||
loadFfmpegWASM();
|
||||
fetchProxyConfig();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -171,6 +175,17 @@ export const AppSettingsProvider = ({
|
||||
setLibraryPath(dir);
|
||||
};
|
||||
|
||||
const fetchProxyConfig = async () => {
|
||||
const config = await EnjoyApp.system.proxy.get();
|
||||
setProxy(config);
|
||||
};
|
||||
|
||||
const setProxyConfigHandler = async (config: ProxyConfigType) => {
|
||||
EnjoyApp.system.proxy.set(config).then(() => {
|
||||
setProxy(config);
|
||||
});
|
||||
};
|
||||
|
||||
const validate = async () => {
|
||||
setInitialized(Boolean(user && libraryPath));
|
||||
};
|
||||
@@ -192,6 +207,8 @@ export const AppSettingsProvider = ({
|
||||
ffmpegConfig,
|
||||
ffmpeg,
|
||||
setFfmegConfig,
|
||||
proxy,
|
||||
setProxy: setProxyConfigHandler,
|
||||
initialized,
|
||||
}}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user