Feat: support action cable (#665)
* upgrade deps * may connect server via cable
This commit is contained in:
@@ -20,6 +20,7 @@ export const STORAGE_WORKER_ENDPOINTS = [
|
||||
export const AI_WORKER_ENDPOINT = "https://ai-worker.enjoy.bot";
|
||||
|
||||
export const WEB_API_URL = "https://enjoy.bot";
|
||||
export const WS_URL = "wss://enjoy.bot";
|
||||
|
||||
export const REPO_URL = "https://github.com/xiaolai/everyone-can-use-english";
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import whisper from "@main/whisper";
|
||||
import fs from "fs-extra";
|
||||
import "@main/i18n";
|
||||
import log from "@main/logger";
|
||||
import { WEB_API_URL, REPO_URL } from "@/constants";
|
||||
import { WEB_API_URL, REPO_URL, WS_URL } from "@/constants";
|
||||
import { AudibleProvider, TedProvider, YoutubeProvider } from "@main/providers";
|
||||
import Ffmpeg from "@main/ffmpeg";
|
||||
import { Waveform } from "./waveform";
|
||||
@@ -318,6 +318,10 @@ main.init = () => {
|
||||
return process.env.WEB_API_URL || WEB_API_URL;
|
||||
});
|
||||
|
||||
ipcMain.handle("app-ws-url", () => {
|
||||
return process.env.WS_URL || WS_URL;
|
||||
});
|
||||
|
||||
ipcMain.handle("app-quit", () => {
|
||||
app.quit();
|
||||
});
|
||||
|
||||
@@ -23,6 +23,9 @@ contextBridge.exposeInMainWorld("__ENJOY_APP__", {
|
||||
apiUrl: () => {
|
||||
return ipcRenderer.invoke("app-api-url");
|
||||
},
|
||||
wsUrl: () => {
|
||||
return ipcRenderer.invoke("app-ws-url");
|
||||
},
|
||||
quit: () => {
|
||||
ipcRenderer.invoke("app-quit");
|
||||
},
|
||||
|
||||
1
enjoy/src/renderer/cables/channels/index.ts
Normal file
1
enjoy/src/renderer/cables/channels/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./notifications_channel";
|
||||
49
enjoy/src/renderer/cables/channels/notifications_channel.ts
Normal file
49
enjoy/src/renderer/cables/channels/notifications_channel.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { toast } from "@/renderer/components/ui";
|
||||
import { type Consumer } from "@rails/actioncable";
|
||||
|
||||
export class NoticiationsChannel {
|
||||
private consumer: Consumer;
|
||||
|
||||
constructor(consumer: Consumer) {
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
subscribe() {
|
||||
this.consumer.subscriptions.create(
|
||||
{ channel: "NotificationsChannel" },
|
||||
{
|
||||
received(data) {
|
||||
if (typeof data === "string") {
|
||||
toast.info(data);
|
||||
} else {
|
||||
switch (data?.type) {
|
||||
case "success":
|
||||
toast.success(data.message);
|
||||
break;
|
||||
case "error":
|
||||
toast.error(data.message);
|
||||
break;
|
||||
case "info":
|
||||
toast.info(data.message);
|
||||
break;
|
||||
case "warning":
|
||||
toast.warning(data.message);
|
||||
break;
|
||||
default:
|
||||
toast.message(data.message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.id) {
|
||||
this.markAsSeen([data.id]);
|
||||
}
|
||||
},
|
||||
|
||||
markAsSeen(ids: number[]) {
|
||||
this.consumer.perform("mark_as_seen", { ids });
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
1
enjoy/src/renderer/cables/index.ts
Normal file
1
enjoy/src/renderer/cables/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './channels';
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuItem,
|
||||
Separator,
|
||||
toast,
|
||||
} from "@renderer/components/ui";
|
||||
import {
|
||||
SettingsIcon,
|
||||
@@ -34,12 +35,19 @@ import { useLocation, Link } from "react-router-dom";
|
||||
import { t } from "i18next";
|
||||
import { Preferences } from "@renderer/components";
|
||||
import { AppSettingsProviderContext } from "@renderer/context";
|
||||
import { useContext } from "react";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { NoticiationsChannel } from "@/renderer/cables";
|
||||
|
||||
export const Sidebar = () => {
|
||||
const location = useLocation();
|
||||
const activeTab = location.pathname;
|
||||
const { EnjoyApp } = useContext(AppSettingsProviderContext);
|
||||
const { EnjoyApp, cable } = useContext(AppSettingsProviderContext);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Subscrbing ->");
|
||||
const channel = new NoticiationsChannel(cable);
|
||||
channel.subscribe();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -170,7 +178,9 @@ export const Sidebar = () => {
|
||||
className="w-full xl:justify-start px-2 xl:px-4"
|
||||
>
|
||||
<HelpCircleIcon className="h-5 w-5" />
|
||||
<span className="ml-2 hidden xl:block">{t("sidebar.help")}</span>
|
||||
<span className="ml-2 hidden xl:block">
|
||||
{t("sidebar.help")}
|
||||
</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { WEB_API_URL, LANGUAGES } from "@/constants";
|
||||
import { Client } from "@/api";
|
||||
import i18n from "@renderer/i18n";
|
||||
import ahoy from "ahoy.js";
|
||||
import { type Consumer, createConsumer } from "@rails/actioncable";
|
||||
|
||||
type AppSettingsProviderState = {
|
||||
webApi: Client;
|
||||
@@ -23,6 +24,7 @@ type AppSettingsProviderState = {
|
||||
switchLearningLanguage?: (lang: string) => void;
|
||||
proxy?: ProxyConfigType;
|
||||
setProxy?: (config: ProxyConfigType) => Promise<void>;
|
||||
cable?: Consumer;
|
||||
ahoy?: typeof ahoy;
|
||||
};
|
||||
|
||||
@@ -43,6 +45,7 @@ export const AppSettingsProvider = ({
|
||||
const [version, setVersion] = useState<string>("");
|
||||
const [apiUrl, setApiUrl] = useState<string>(WEB_API_URL);
|
||||
const [webApi, setWebApi] = useState<Client>(null);
|
||||
const [cable, setCable] = useState<Consumer>();
|
||||
const [user, setUser] = useState<UserType | null>(null);
|
||||
const [libraryPath, setLibraryPath] = useState("");
|
||||
const [language, setLanguage] = useState<"en" | "zh-CN">();
|
||||
@@ -145,6 +148,7 @@ export const AppSettingsProvider = ({
|
||||
const login = (user: UserType) => {
|
||||
setUser(user);
|
||||
EnjoyApp.settings.setUser(user);
|
||||
createCable(user.accessToken);
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
@@ -173,6 +177,12 @@ export const AppSettingsProvider = ({
|
||||
});
|
||||
};
|
||||
|
||||
const createCable = async (token: string) => {
|
||||
const wsUrl = await EnjoyApp.app.wsUrl();
|
||||
const consumer = createConsumer(wsUrl + "/cable?token=" + token);
|
||||
setCable(consumer);
|
||||
};
|
||||
|
||||
return (
|
||||
<AppSettingsProviderContext.Provider
|
||||
value={{
|
||||
@@ -195,6 +205,7 @@ export const AppSettingsProvider = ({
|
||||
setProxy: setProxyConfigHandler,
|
||||
initialized: Boolean(user && libraryPath),
|
||||
ahoy,
|
||||
cable,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
1
enjoy/src/types/enjoy-app.d.ts
vendored
1
enjoy/src/types/enjoy-app.d.ts
vendored
@@ -6,6 +6,7 @@ type EnjoyAppType = {
|
||||
reload: () => Promise<void>;
|
||||
isPackaged: () => Promise<boolean>;
|
||||
apiUrl: () => Promise<string>;
|
||||
wsUrl: () => Promise<string>;
|
||||
quit: () => Promise<void>;
|
||||
openDevTools: () => Promise<void>;
|
||||
createIssue: (title: string, body: string) => Promise<void>;
|
||||
|
||||
Reference in New Issue
Block a user