api.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import axios, { AxiosInstance } from "axios";
  2. import { getClashInfo } from "./cmds";
  3. let axiosIns: AxiosInstance = null!;
  4. let server = "";
  5. let secret = "";
  6. /// initialize some information
  7. /// enable force update axiosIns
  8. export async function getAxios(force: boolean = false) {
  9. if (axiosIns && !force) return axiosIns;
  10. try {
  11. const info = await getClashInfo();
  12. if (info?.server) {
  13. server = info.server;
  14. // compatible width `external-controller`
  15. if (server.startsWith(":")) server = `127.0.0.1${server}`;
  16. else if (/^\d+$/.test(server)) server = `127.0.0.1:${server}`;
  17. }
  18. if (info?.secret) secret = info?.secret;
  19. } catch {}
  20. axiosIns = axios.create({
  21. baseURL: `http://${server}`,
  22. headers: secret ? { Authorization: `Bearer ${secret}` } : {},
  23. });
  24. axiosIns.interceptors.response.use((r) => r.data);
  25. return axiosIns;
  26. }
  27. /// get information
  28. export async function getInformation() {
  29. if (server) return { server, secret };
  30. const info = await getClashInfo();
  31. return info!;
  32. }
  33. /// Get Version
  34. export async function getVersion() {
  35. const instance = await getAxios();
  36. return instance.get("/version") as Promise<{
  37. premium: boolean;
  38. meta?: boolean;
  39. version: string;
  40. }>;
  41. }
  42. /// Get current base configs
  43. export async function getClashConfig() {
  44. const instance = await getAxios();
  45. return instance.get("/configs") as Promise<IConfigData>;
  46. }
  47. /// Update current configs
  48. export async function updateConfigs(config: Partial<IConfigData>) {
  49. const instance = await getAxios();
  50. return instance.patch("/configs", config);
  51. }
  52. /// Get current rules
  53. export async function getRules() {
  54. const instance = await getAxios();
  55. const response = await instance.get<any, any>("/rules");
  56. return response?.rules as IRuleItem[];
  57. }
  58. /// Get Proxy delay
  59. export async function getProxyDelay(
  60. name: string,
  61. url?: string
  62. ): Promise<{ delay: number }> {
  63. const params = {
  64. timeout: 3000,
  65. url: url || "http://www.gstatic.com/generate_204",
  66. };
  67. const instance = await getAxios();
  68. return instance.get(`/proxies/${encodeURIComponent(name)}/delay`, { params });
  69. }
  70. /// Update the Proxy Choose
  71. export async function updateProxy(group: string, proxy: string) {
  72. const instance = await getAxios();
  73. return instance.put(`/proxies/${encodeURIComponent(group)}`, { name: proxy });
  74. }
  75. // get proxy
  76. async function getProxiesInner() {
  77. const instance = await getAxios();
  78. const response = await instance.get<any, any>("/proxies");
  79. return (response?.proxies || {}) as Record<string, IProxyItem>;
  80. }
  81. /// Get the Proxy information
  82. export async function getProxies() {
  83. const [proxyRecord, providerRecord] = await Promise.all([
  84. getProxiesInner(),
  85. getProviders(),
  86. ]);
  87. // provider name map
  88. const providerMap = Object.fromEntries(
  89. Object.entries(providerRecord).flatMap(([provider, item]) =>
  90. item.proxies.map((p) => [p.name, { ...p, provider }])
  91. )
  92. );
  93. // compatible with proxy-providers
  94. const generateItem = (name: string) => {
  95. if (proxyRecord[name]) return proxyRecord[name];
  96. if (providerMap[name]) return providerMap[name];
  97. return { name, type: "unknown", udp: false, history: [] };
  98. };
  99. const { GLOBAL: global, DIRECT: direct, REJECT: reject } = proxyRecord;
  100. let groups: IProxyGroupItem[] = [];
  101. if (global?.all) {
  102. groups = global.all
  103. .filter((name) => proxyRecord[name]?.all)
  104. .map((name) => proxyRecord[name])
  105. .map((each) => ({
  106. ...each,
  107. all: each.all!.map((item) => generateItem(item)),
  108. }));
  109. } else {
  110. groups = Object.values(proxyRecord)
  111. .filter((each) => each.name !== "GLOBAL" && each.all)
  112. .map((each) => ({
  113. ...each,
  114. all: each.all!.map((item) => generateItem(item)),
  115. }))
  116. .sort((a, b) => b.name.localeCompare(a.name));
  117. }
  118. const proxies = [direct, reject].concat(
  119. Object.values(proxyRecord).filter(
  120. (p) => !p.all?.length && p.name !== "DIRECT" && p.name !== "REJECT"
  121. )
  122. );
  123. const _global: IProxyGroupItem = {
  124. ...global,
  125. all: global?.all?.map((item) => generateItem(item)) || [],
  126. };
  127. return { global: _global, direct, groups, records: proxyRecord, proxies };
  128. }
  129. // get proxy providers
  130. export async function getProviders() {
  131. const instance = await getAxios();
  132. const response = await instance.get<any, any>("/providers/proxies");
  133. const providers = (response.providers || {}) as Record<string, IProviderItem>;
  134. return Object.fromEntries(
  135. Object.entries(providers).filter(([key, item]) => {
  136. const type = item.vehicleType.toLowerCase();
  137. return type === "http" || type === "file";
  138. })
  139. );
  140. }
  141. // proxy providers health check
  142. export async function providerHealthCheck(name: string) {
  143. const instance = await getAxios();
  144. return instance.get(
  145. `/providers/proxies/${encodeURIComponent(name)}/healthcheck`
  146. );
  147. }
  148. export async function getConnections() {
  149. const instance = await getAxios();
  150. const result = await instance.get("/connections");
  151. return result as any as IConnections;
  152. }
  153. // Close specific connection
  154. export async function deleteConnection(id: string) {
  155. const instance = await getAxios();
  156. await instance.delete<any, any>(`/connections/${encodeURIComponent(id)}`);
  157. }
  158. // Close all connections
  159. export async function closeAllConnections() {
  160. const instance = await getAxios();
  161. await instance.delete<any, any>(`/connections`);
  162. }