gitscope
← marzneshin / v0.2.0 / app/dashboard/src/stores/inbounds.store.ts
https://dev.kronoz.win/r/marzneshin.git
app/dashboard/src/stores/inbounds.store.ts · TypeScript
Blame Raw
  1import { create } from 'zustand';
  2import { subscribeWithSelector } from 'zustand/middleware';
  3import { useDashboard } from './dashboard.store';
  4import { fetch } from 'service/http';
  5import { Inbounds, InboundType } from 'types/inbounds';
  6import { z } from 'zod';
  7import { HostsFilterType, InboundsFilterType } from 'types';
  8import { pageSizeManagers } from 'utils/userPreferenceStorage';
  9import { queryClient } from 'service/react-query';
 10import { queryIds } from 'constants/query-ids';
 11
 12export const hostSchema = z.object({
 13  remark: z.string().min(1, 'Remark is required'),
 14  address: z.string().min(1, 'Address is required'),
 15  port: z.coerce.number()
 16    .gte(1, 'Port must be more than 1')
 17    .lte(65535, 'Port can not be more than 65535')
 18    .or(z.string().nullable()),
 19  path: z.string(),
 20  sni: z.string(),
 21  host: z.string(),
 22  security: z.enum(['inbound_default', 'none', 'tls']),
 23  alpn: z.string().optional(),
 24  fingerprint: z.string().optional(),
 25});
 26
 27export type HostSchema = z.infer<typeof hostSchema>;
 28export type HostType = HostSchema & { id?: number };
 29export type Hosts = HostType[];
 30
 31export const fetchInbounds = async () => {
 32  useDashboard.setState({ loading: true });
 33  return fetch('/inbounds')
 34    .then((inbounds: Inbounds) => inbounds)
 35    .finally(() => {
 36      useDashboard.setState({ loading: false });
 37    });
 38};
 39
 40export const fetchInboundHosts = async (id: number | undefined): Promise<Hosts> => {
 41  if (id !== undefined) {
 42    useDashboard.setState({ loading: true });
 43    return fetch(`/inbounds/${id}/hosts`)
 44      .then((hosts: Hosts) => {
 45        return hosts
 46      })
 47      .finally(() => {
 48        useDashboard.setState({ loading: false });
 49      });
 50  } else { return [] }
 51};
 52
 53type InboundsStateType = {
 54  // Loading
 55  loading: boolean;
 56  setLoading: (value: boolean) => void;
 57  // Inbounds
 58  selectedInbound: InboundType | undefined;
 59  selectInbound: (inbound: InboundType) => void;
 60  refetchInbounds: () => void;
 61  // Hosts
 62  refetchHosts: () => void;
 63  hostsFilters: HostsFilterType;
 64  inboundsFilters: InboundsFilterType;
 65  onHostsFilterChange: (filters: Partial<HostsFilterType>) => void;
 66  onInboundsFilterChange: (filters: Partial<InboundsFilterType>) => void;
 67  selectedHost: HostType | null;
 68  selectHost: (host: HostType) => void;
 69  isEditingHost: boolean;
 70  onEditingHost: (isEditingHost: boolean, host: HostType | null) => void;
 71  editHost: (inboundId: number | undefined, host: HostType) => Promise<boolean | void>;
 72  isCreatingHost: boolean;
 73  onCreatingHost: (isCreatingHost: boolean) => void;
 74  createHost: (inboundId: number | undefined, host: HostSchema) => Promise<boolean | void>;
 75  isDeletingHost: boolean;
 76  onDeletingHost: (isDeletingHost: boolean, host: HostType) => void;
 77  deleteHost: (hostId: number) => void;
 78};
 79
 80export const useInbounds = create(
 81  subscribeWithSelector<InboundsStateType>((set, get) => ({
 82    selectedHost: null,
 83    selectedInbound: undefined,
 84    loading: false,
 85    isDeletingHost: false,
 86    isCreatingHost: false,
 87    isEditingHost: false,
 88    hostsFilters: {
 89      name: '',
 90      limit: pageSizeManagers.hosts.getPageSize(),
 91      sort: '-created_at',
 92    },
 93    inboundsFilters: {
 94      name: '',
 95      limit: pageSizeManagers.inbounds.getPageSize(),
 96      sort: '-created_at',
 97    },
 98    onHostsFilterChange: (filters) => {
 99      set({
100        hostsFilters: {
101          ...get().hostsFilters,
102          ...filters,
103        },
104      });
105    },
106    onInboundsFilterChange: (filters) => {
107      set({
108        hostsFilters: {
109          ...get().inboundsFilters,
110          ...filters,
111        },
112      });
113    },
114    setLoading: (value) => {
115      set({ loading: value })
116    },
117    refetchInbounds: () => {
118      queryClient.invalidateQueries({ queryKey: [queryIds.inbounds] });
119    },
120    refetchHosts: async () => {
121      queryClient.invalidateQueries({ queryKey: [queryIds.hosts] });
122    },
123    selectInbound: (host): void => {
124      set({ selectedInbound: host })
125    },
126    selectHost: (host: HostType): void => {
127      set({ selectedHost: host })
128    },
129    onEditingHost: (isEditingHost: boolean, host: HostType | null) => {
130      set({ isEditingHost, selectedHost: host });
131    },
132    editHost: async (hostId: number | undefined, body: HostSchema): Promise<boolean | void> => {
133      if (hostId !== undefined) {
134        useDashboard.setState({ loading: true });
135        return fetch(`/inbounds/hosts/${hostId}`, { method: 'PUT', body })
136          .then(() => true)
137          .catch(() => false)
138          .finally(() => {
139            useDashboard.setState({ loading: false });
140            get().refetchHosts();
141          });
142      }
143    },
144    onCreatingHost: (isCreatingHost: boolean) => {
145      set({ isCreatingHost });
146    },
147    createHost: async (inboundId: number | undefined, body: HostSchema): Promise<boolean | void> => {
148      if (inboundId !== undefined) {
149        useDashboard.setState({ loading: true });
150        return fetch(`/inbounds/${inboundId}/hosts`, { method: 'POST', body })
151          .then(() => true)
152          .catch(() => false)
153          .finally(() => {
154            useDashboard.setState({ loading: false });
155            get().refetchHosts();
156          });
157      }
158    },
159    onDeletingHost: (isDeletingHost: boolean, host: HostType | null) => {
160      set({ isDeletingHost, selectedHost: host });
161    },
162    deleteHost: async (hostId: number): Promise<boolean> => {
163      useDashboard.setState({ loading: true });
164      return fetch(`/inbounds/hosts/${hostId}`, { method: 'DELETE' })
165        .then(() => {
166          get().refetchHosts();
167          return true;
168        })
169        .catch(() => false)
170        .finally(() => {
171          useDashboard.setState({ loading: false });
172        });
173    },
174  }))
175);