|
@@ -25,7 +25,13 @@ import {
|
|
|
MASK_ADDRESS,
|
|
MASK_ADDRESS,
|
|
|
ROUTING_DOMAIN_STRATEGIES,
|
|
ROUTING_DOMAIN_STRATEGIES,
|
|
|
} from './constants';
|
|
} from './constants';
|
|
|
-import { directFreedomStrategy, setDirectFreedomStrategy } from './helpers';
|
|
|
|
|
|
|
+import {
|
|
|
|
|
+ directFreedomStrategy,
|
|
|
|
|
+ ensureDirectFreedomOutbound,
|
|
|
|
|
+ isDirectFreedomOutbound,
|
|
|
|
|
+ isDirectTagTaken,
|
|
|
|
|
+ setDirectFreedomStrategy,
|
|
|
|
|
+} from './helpers';
|
|
|
|
|
|
|
|
interface BasicsTabProps {
|
|
interface BasicsTabProps {
|
|
|
templateSettings: XraySettingsValue | null;
|
|
templateSettings: XraySettingsValue | null;
|
|
@@ -112,9 +118,10 @@ export default function BasicsTab({
|
|
|
|
|
|
|
|
const freedomStrategy = directFreedomStrategy(templateSettings);
|
|
const freedomStrategy = directFreedomStrategy(templateSettings);
|
|
|
|
|
|
|
|
- const directFreedomOutbound = templateSettings?.outbounds?.find(
|
|
|
|
|
- (o) => o?.protocol === 'freedom' && o?.tag === 'direct',
|
|
|
|
|
|
|
+ const directFreedomOutbound = templateSettings?.outbounds?.find((o) =>
|
|
|
|
|
+ isDirectFreedomOutbound(o),
|
|
|
);
|
|
);
|
|
|
|
|
+ const directTagTaken = isDirectTagTaken(templateSettings);
|
|
|
const directHappyEyeballs = (() => {
|
|
const directHappyEyeballs = (() => {
|
|
|
const sockopt = (
|
|
const sockopt = (
|
|
|
directFreedomOutbound?.streamSettings as { sockopt?: { happyEyeballs?: unknown } } | undefined
|
|
directFreedomOutbound?.streamSettings as { sockopt?: { happyEyeballs?: unknown } } | undefined
|
|
@@ -128,13 +135,8 @@ export default function BasicsTab({
|
|
|
const setDirectHappyEyeballs = useCallback(
|
|
const setDirectHappyEyeballs = useCallback(
|
|
|
(next: ReturnType<typeof HappyEyeballsSchema.parse> | null) => {
|
|
(next: ReturnType<typeof HappyEyeballsSchema.parse> | null) => {
|
|
|
mutate((tt) => {
|
|
mutate((tt) => {
|
|
|
- if (!tt.outbounds) tt.outbounds = [];
|
|
|
|
|
- let idx = tt.outbounds.findIndex((o) => o?.protocol === 'freedom' && o?.tag === 'direct');
|
|
|
|
|
- if (idx < 0) {
|
|
|
|
|
- tt.outbounds.push({ protocol: 'freedom', tag: 'direct', settings: {} });
|
|
|
|
|
- idx = tt.outbounds.length - 1;
|
|
|
|
|
- }
|
|
|
|
|
- const ob = tt.outbounds[idx];
|
|
|
|
|
|
|
+ const ob = ensureDirectFreedomOutbound(tt);
|
|
|
|
|
+ if (!ob) return;
|
|
|
const stream = (ob.streamSettings ?? {}) as Record<string, unknown>;
|
|
const stream = (ob.streamSettings ?? {}) as Record<string, unknown>;
|
|
|
const sockopt = (stream.sockopt ?? {}) as Record<string, unknown>;
|
|
const sockopt = (stream.sockopt ?? {}) as Record<string, unknown>;
|
|
|
if (next == null) {
|
|
if (next == null) {
|
|
@@ -181,6 +183,7 @@ export default function BasicsTab({
|
|
|
control={
|
|
control={
|
|
|
<Select
|
|
<Select
|
|
|
value={freedomStrategy}
|
|
value={freedomStrategy}
|
|
|
|
|
+ disabled={directTagTaken}
|
|
|
style={{ width: '100%' }}
|
|
style={{ width: '100%' }}
|
|
|
options={OutboundDomainStrategies.map((s) => ({ value: s, label: s }))}
|
|
options={OutboundDomainStrategies.map((s) => ({ value: s, label: s }))}
|
|
|
onChange={(next) => mutate((tt) => setDirectFreedomStrategy(tt, next))}
|
|
onChange={(next) => mutate((tt) => setDirectFreedomStrategy(tt, next))}
|
|
@@ -194,6 +197,7 @@ export default function BasicsTab({
|
|
|
control={
|
|
control={
|
|
|
<Switch
|
|
<Switch
|
|
|
checked={directHappyEyeballs != null}
|
|
checked={directHappyEyeballs != null}
|
|
|
|
|
+ disabled={directTagTaken}
|
|
|
onChange={(checked) => {
|
|
onChange={(checked) => {
|
|
|
setDirectHappyEyeballs(checked ? HappyEyeballsSchema.parse({}) : null);
|
|
setDirectHappyEyeballs(checked ? HappyEyeballsSchema.parse({}) : null);
|
|
|
}}
|
|
}}
|