api.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. import { getClashInfo } from "./cmds";
  2. import {
  3. fetch as tauriFetch,
  4. HttpVerb,
  5. Body,
  6. Response,
  7. } from "@tauri-apps/api/http";
  8. let clashInfo: IClashInfo | null;
  9. export const refreshClashInfo = async () => {
  10. clashInfo = await getClashInfo();
  11. return clashInfo;
  12. };
  13. export const fetch = async (
  14. path: string,
  15. method: HttpVerb,
  16. body?: any
  17. ): Promise<Response<any>> => {
  18. let server = "";
  19. let secret = "";
  20. try {
  21. const info = clashInfo ?? (await refreshClashInfo());
  22. if (info?.server) {
  23. server = info.server;
  24. // compatible width `external-controller`
  25. if (server.startsWith(":")) server = `127.0.0.1${server}`;
  26. else if (/^\d+$/.test(server)) server = `127.0.0.1:${server}`;
  27. }
  28. if (info?.secret) secret = info?.secret;
  29. } catch {}
  30. return tauriFetch(`http://${server}${path}`, {
  31. method,
  32. headers: secret ? { Authorization: `Bearer ${secret}` } : {},
  33. timeout: 15000,
  34. body: body ? Body.json(body) : undefined,
  35. });
  36. };
  37. /// Get Version
  38. export const getVersion = async () => {
  39. const res = await fetch("/version", "GET");
  40. return res.data as Promise<{
  41. premium: boolean;
  42. meta?: boolean;
  43. version: string;
  44. }>;
  45. };
  46. /// Get current base configs
  47. export const getClashConfig = async () => {
  48. const res = await fetch("/configs", "GET");
  49. return res.data as Promise<IConfigData>;
  50. };
  51. /// Update current configs
  52. export const updateConfigs = async (config: Partial<IConfigData>) => {
  53. const res = await fetch("/configs", "PATCH", config);
  54. return res;
  55. };
  56. /// Update geo data
  57. export const updateGeoData = async () => {
  58. const res = await fetch("/configs/geo", "POST");
  59. return res;
  60. };
  61. /// Upgrade clash core
  62. export const upgradeCore = async () => {
  63. const res = await fetch("/upgrade", "POST");
  64. return res;
  65. };
  66. /// Get current rules
  67. export const getRules = async () => {
  68. const res = await fetch("/rules", "GET");
  69. return res?.data?.rules as IRuleItem[];
  70. };
  71. /// Get Proxy delay
  72. export const getProxyDelay = async (name: string, url?: string) => {
  73. const params = {
  74. timeout: 10000,
  75. url: url || "http://1.1.1.1",
  76. };
  77. const result = await fetch(
  78. `/proxies/${encodeURIComponent(name)}/delay`,
  79. "GET",
  80. { params }
  81. );
  82. return result.data as any as { delay: number };
  83. };
  84. /// Update the Proxy Choose
  85. export const updateProxy = async (group: string, proxy: string) => {
  86. const res = await fetch(`/proxies/${encodeURIComponent(group)}`, "PUT", {
  87. name: proxy,
  88. });
  89. return res;
  90. };
  91. // get proxy
  92. export const getProxiesInner = async () => {
  93. const res = await fetch("/proxies", "GET");
  94. return (res?.data?.proxies || {}) as Record<string, IProxyItem>;
  95. };
  96. /// Get the Proxy information
  97. export const getProxies = async () => {
  98. const [proxyRecord, providerRecord] = await Promise.all([
  99. getProxiesInner(),
  100. getProviders(),
  101. ]);
  102. // provider name map
  103. const providerMap = Object.fromEntries(
  104. Object.entries(providerRecord).flatMap(([provider, item]) =>
  105. item.proxies.map((p) => [p.name, { ...p, provider }])
  106. )
  107. );
  108. // compatible with proxy-providers
  109. const generateItem = (name: string) => {
  110. if (proxyRecord[name]) return proxyRecord[name];
  111. if (providerMap[name]) return providerMap[name];
  112. return {
  113. name,
  114. type: "unknown",
  115. udp: false,
  116. xudp: false,
  117. tfo: false,
  118. history: [],
  119. };
  120. };
  121. const { GLOBAL: global, DIRECT: direct, REJECT: reject } = proxyRecord;
  122. let groups: IProxyGroupItem[] = [];
  123. if (global?.all) {
  124. groups = global.all
  125. .filter((name) => proxyRecord[name]?.all)
  126. .map((name) => proxyRecord[name])
  127. .map((each) => ({
  128. ...each,
  129. all: each.all!.map((item) => generateItem(item)),
  130. }));
  131. } else {
  132. groups = Object.values(proxyRecord)
  133. .filter((each) => each.name !== "GLOBAL" && each.all)
  134. .map((each) => ({
  135. ...each,
  136. all: each.all!.map((item) => generateItem(item)),
  137. }))
  138. .sort((a, b) => b.name.localeCompare(a.name));
  139. }
  140. const proxies = [direct, reject].concat(
  141. Object.values(proxyRecord).filter(
  142. (p) => !p.all?.length && p.name !== "DIRECT" && p.name !== "REJECT"
  143. )
  144. );
  145. const _global: IProxyGroupItem = {
  146. ...global,
  147. all: global?.all?.map((item) => generateItem(item)) || [],
  148. };
  149. return { global: _global, direct, groups, records: proxyRecord, proxies };
  150. };
  151. // get proxy providers
  152. export const getProviders = async () => {
  153. const res = await fetch("/providers/proxies", "GET");
  154. const providers = (res.data.providers || {}) as Record<string, IProviderItem>;
  155. return Object.fromEntries(
  156. Object.entries(providers).filter(([key, item]) => {
  157. const type = item.vehicleType.toLowerCase();
  158. return type === "http" || type === "file";
  159. })
  160. );
  161. };
  162. // proxy providers health check
  163. export const providerHealthCheck = async (name: string) => {
  164. const res = await fetch(
  165. `/providers/proxies/${encodeURIComponent(name)}/healthcheck`,
  166. "GET"
  167. );
  168. return res;
  169. };
  170. export const providerUpdate = async (name: string) => {
  171. const res = await fetch(
  172. `/providers/proxies/${encodeURIComponent(name)}`,
  173. "PUT"
  174. );
  175. return res;
  176. };
  177. export const getConnections = async () => {
  178. const res = await fetch("/connections", "GET");
  179. return res.data as any as IConnections;
  180. };
  181. // Close specific connection
  182. export const deleteConnection = async (id: string) => {
  183. const res = await fetch(`/connections/${encodeURIComponent(id)}`, "DELETE");
  184. return res;
  185. };
  186. // Close all connections
  187. export const closeAllConnections = async () => {
  188. const res = await fetch("/connections", "DELETE");
  189. return res;
  190. };