aboutsummaryrefslogtreecommitdiff
path: root/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/viscosity-vpn.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/viscosity-vpn.jsx')
-rwxr-xr-xusers/ryan/modules/simple-bar/simple-bar-source/lib/components/data/viscosity-vpn.jsx144
1 files changed, 144 insertions, 0 deletions
diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/viscosity-vpn.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/viscosity-vpn.jsx
new file mode 100755
index 0000000..340c59b
--- /dev/null
+++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/viscosity-vpn.jsx
@@ -0,0 +1,144 @@
1import * as Uebersicht from "uebersicht";
2import * as DataWidget from "./data-widget.jsx";
3import * as DataWidgetLoader from "./data-widget-loader.jsx";
4import * as Icons from "../icons/icons.jsx";
5import useWidgetRefresh from "../../hooks/use-widget-refresh";
6import useServerSocket from "../../hooks/use-server-socket";
7import { useSimpleBarContext } from "../simple-bar-context.jsx";
8import * as Utils from "../../utils";
9
10export { viscosityVPNStyles as styles } from "../../styles/components/data/viscosity-vpn";
11
12const { React } = Uebersicht;
13
14const DEFAULT_REFRESH_FREQUENCY = 8000;
15
16/**
17 * Viscosity VPN Widget component.
18 * @returns {JSX.Element|null} The Viscosity VPN widget.
19 */
20export const Widget = React.memo(() => {
21 const { displayIndex, settings, pushMissive } = useSimpleBarContext();
22 const { widgets, vpnWidgetOptions } = settings;
23 const { vpnWidget } = widgets;
24 const {
25 refreshFrequency,
26 vpnConnectionName,
27 vpnShowConnectionName,
28 showOnDisplay,
29 showIcon,
30 } = vpnWidgetOptions;
31
32 // Determine the refresh frequency for the widget
33 const refresh = React.useMemo(
34 () =>
35 Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY),
36 [refreshFrequency],
37 );
38
39 // Determine if the widget should be visible
40 const visible =
41 Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && vpnWidget;
42
43 const [state, setState] = React.useState();
44 const [loading, setLoading] = React.useState(visible);
45 const [isViscosityActive, setIsViscosityActive] = React.useState(false);
46
47 /**
48 * Reset the widget state.
49 */
50 const resetWidget = () => {
51 setState(undefined);
52 setLoading(false);
53 setIsViscosityActive(false);
54 };
55
56 /**
57 * Fetch the current VPN status.
58 */
59 const getVPN = React.useCallback(async () => {
60 if (!visible) return;
61 const isRunning = await Utils.cachedRun(
62 `pgrep -xq 'Viscosity' && echo "true" || echo "false"`,
63 refresh,
64 );
65 if (Utils.cleanupOutput(isRunning) === "false") {
66 setLoading(false);
67 setIsViscosityActive(false);
68 return;
69 }
70 const status = await Utils.cachedRun(
71 `osascript -e "tell application \\"Viscosity\\" to return state of the first connection where name is equal to \\"${vpnConnectionName}\\"" 2>/dev/null`,
72 refresh,
73 );
74 if (!status.length) return;
75 setState({ status: Utils.cleanupOutput(status) });
76 setIsViscosityActive(true);
77 setLoading(false);
78 }, [visible, vpnConnectionName, refresh]);
79
80 // Use server socket to listen for VPN status updates
81 useServerSocket("viscosity-vpn", visible, getVPN, resetWidget, setLoading);
82 // Refresh the widget at the specified interval
83 useWidgetRefresh(visible, getVPN, refresh);
84
85 if (loading) return <DataWidgetLoader.Widget className="viscosity-vpn" />;
86 if (!state || !vpnConnectionName.length || !isViscosityActive) return null;
87
88 const { status } = state;
89 const isConnected = status === "Connected";
90
91 const classes = Utils.classNames("viscosity-vpn", {
92 "viscosity-vpn--disconnected": !isConnected,
93 });
94
95 const Icon = isConnected ? Icons.VPN : Icons.VPNOff;
96
97 /**
98 * Handle click event to toggle VPN connection.
99 * @param {Event} e - The click event.
100 */
101 const clicked = (e) => {
102 Utils.clickEffect(e);
103 toggleVPN(isConnected, vpnConnectionName, pushMissive);
104 setTimeout(getVPN, refreshFrequency / 2);
105 };
106
107 return (
108 <DataWidget.Widget
109 classes={classes}
110 Icon={showIcon ? Icon : null}
111 onClick={clicked}
112 >
113 {vpnShowConnectionName ? vpnConnectionName : status}
114 </DataWidget.Widget>
115 );
116});
117
118Widget.displayName = "ViscosityVPN";
119
120/**
121 * Toggle the VPN connection.
122 * @param {boolean} isConnected - Whether the VPN is currently connected.
123 * @param {string} vpnConnectionName - The name of the VPN connection.
124 * @param {function} pushMissive - Function to push notifications.
125 */
126function toggleVPN(isConnected, vpnConnectionName, pushMissive) {
127 if (isConnected) {
128 Uebersicht.run(
129 `osascript -e 'tell application "Viscosity" to disconnect "${vpnConnectionName}"'`,
130 );
131 Utils.notification(
132 `Disabling Viscosity ${vpnConnectionName} network...`,
133 pushMissive,
134 );
135 } else {
136 Uebersicht.run(
137 `osascript -e 'tell application "Viscosity" to connect "${vpnConnectionName}"'`,
138 );
139 Utils.notification(
140 `Enabling Viscosity ${vpnConnectionName} network...`,
141 pushMissive,
142 );
143 }
144}