Data.tsx 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. import {
  2. createContext,
  3. useCallback,
  4. useContext,
  5. useEffect,
  6. useState,
  7. useRef,
  8. } from 'react';
  9. import { io, Socket } from 'socket.io-client';
  10. import { authContext } from '@/context';
  11. import { url, CollectionService, MilvusService, DatabaseService } from '@/http';
  12. import { IndexCreateParam, IndexManageParam } from '@/pages/schema/Types';
  13. import { getDbValueFromUrl } from '@/utils';
  14. import { DataContextType } from './Types';
  15. import { LAST_TIME_DATABASE } from '@/consts';
  16. import { CollectionObject, CollectionFullObject } from '@server/types';
  17. import { WS_EVENTS, WS_EVENTS_TYPE } from '@server/utils/Const';
  18. import { checkIndexing, checkLoading } from '@server/utils/Shared';
  19. export const dataContext = createContext<DataContextType>({
  20. loading: false,
  21. collections: [],
  22. setCollections: () => {},
  23. database: 'default',
  24. setDatabase: () => {},
  25. databases: [],
  26. setDatabaseList: () => {},
  27. fetchDatabases: async () => {},
  28. fetchCollections: async () => {},
  29. fetchCollection: async () => {
  30. return {} as CollectionFullObject;
  31. },
  32. createCollection: async () => {
  33. return {} as CollectionFullObject;
  34. },
  35. loadCollection: async () => {
  36. return {} as CollectionFullObject;
  37. },
  38. releaseCollection: async () => {
  39. return {} as CollectionFullObject;
  40. },
  41. renameCollection: async () => {
  42. return {} as CollectionFullObject;
  43. },
  44. duplicateCollection: async () => {
  45. return {} as CollectionFullObject;
  46. },
  47. dropCollection: async () => {},
  48. createIndex: async () => {
  49. return {} as CollectionFullObject;
  50. },
  51. dropIndex: async () => {
  52. return {} as CollectionFullObject;
  53. },
  54. createAlias: async () => {
  55. return {} as CollectionFullObject;
  56. },
  57. dropAlias: async () => {
  58. return {} as CollectionFullObject;
  59. },
  60. });
  61. const { Provider } = dataContext;
  62. export const DataProvider = (props: { children: React.ReactNode }) => {
  63. // get database name from url
  64. const currentUrl = window.location.href;
  65. const initialDatabase = getDbValueFromUrl(currentUrl);
  66. // local data state
  67. const [collections, setCollections] = useState<CollectionObject[]>([]);
  68. const [connected, setConnected] = useState(false);
  69. const [loading, setLoading] = useState(false);
  70. const [database, setDatabase] = useState<string>(
  71. initialDatabase ||
  72. window.localStorage.getItem(LAST_TIME_DATABASE) ||
  73. 'default'
  74. );
  75. const [databases, setDatabases] = useState<string[]>([database]);
  76. // auth context
  77. const { isAuth, clientId } = useContext(authContext);
  78. // socket ref
  79. const socket = useRef<Socket | null>(null);
  80. // collection state test
  81. const detectLoadingIndexing = useCallback(
  82. (collections: CollectionObject[]) => {
  83. const LoadingOrBuildingCollections = collections.filter(v => {
  84. const isLoading = checkLoading(v);
  85. const isBuildingIndex = checkIndexing(v);
  86. return isLoading || isBuildingIndex;
  87. });
  88. // trigger cron if it has
  89. if (LoadingOrBuildingCollections.length > 0) {
  90. MilvusService.triggerCron({
  91. name: WS_EVENTS.COLLECTION_UPDATE,
  92. type: WS_EVENTS_TYPE.START,
  93. payload: {
  94. database,
  95. collections: LoadingOrBuildingCollections.map(
  96. c => c.collection_name
  97. ),
  98. },
  99. });
  100. }
  101. },
  102. [database]
  103. );
  104. // Websocket Callback: update single collection
  105. const updateCollections = useCallback(
  106. (updateCollections: CollectionFullObject[]) => {
  107. // check state to see if it is loading or building index, if so, start server cron job
  108. detectLoadingIndexing(updateCollections);
  109. // update single collection
  110. setCollections(prev => {
  111. // update exsit collection
  112. const newCollections = prev.map(v => {
  113. const collectionToUpdate = updateCollections.find(c => c.id === v.id);
  114. if (collectionToUpdate) {
  115. return collectionToUpdate;
  116. }
  117. return v;
  118. });
  119. return newCollections;
  120. });
  121. },
  122. [database]
  123. );
  124. // API: fetch databases
  125. const fetchDatabases = async () => {
  126. const res = await DatabaseService.getDatabases();
  127. setDatabases(res.db_names);
  128. };
  129. // API:fetch collections
  130. const fetchCollections = async () => {
  131. try {
  132. // set loading true
  133. setLoading(true);
  134. // fetch collections
  135. const res = await CollectionService.getCollections();
  136. // check state
  137. detectLoadingIndexing(res);
  138. // set collections
  139. setCollections(res);
  140. // set loading false
  141. setLoading(false);
  142. } finally {
  143. setLoading(false);
  144. }
  145. };
  146. // API: fetch single collection
  147. const fetchCollection = async (name: string) => {
  148. // fetch collections
  149. const res = await CollectionService.getCollection(name);
  150. // update collection
  151. updateCollections([res]);
  152. return res;
  153. };
  154. // API: create collection
  155. const createCollection = async (data: any) => {
  156. // create collection
  157. const newCollection = await CollectionService.createCollection(data);
  158. // inset collection to state
  159. setCollections(prev => [...prev, newCollection]);
  160. return newCollection;
  161. };
  162. // API: load collection
  163. const loadCollection = async (name: string, param?: any) => {
  164. // load collection
  165. const newCollection = await CollectionService.loadCollection(name, param);
  166. // update collection
  167. updateCollections([newCollection]);
  168. return newCollection;
  169. };
  170. // API: release collection
  171. const releaseCollection = async (name: string) => {
  172. // release collection
  173. const newCollection = await CollectionService.releaseCollection(name);
  174. // update collection
  175. updateCollections([newCollection]);
  176. return newCollection;
  177. };
  178. // API: rename collection
  179. const renameCollection = async (name: string, newName: string) => {
  180. // rename collection
  181. const newCollection = await CollectionService.renameCollection(name, {
  182. new_collection_name: newName,
  183. });
  184. updateCollections([newCollection]);
  185. return newCollection;
  186. };
  187. // API: duplicate collection
  188. const duplicateCollection = async (name: string, newName: string) => {
  189. // duplicate collection
  190. const newCollection = await CollectionService.duplicateCollection(name, {
  191. new_collection_name: newName,
  192. });
  193. // inset collection to state
  194. setCollections(prev => [...prev, newCollection]);
  195. return newCollection;
  196. };
  197. // API: drop collection
  198. const dropCollection = async (name: string) => {
  199. // drop collection
  200. const dropped = await CollectionService.dropCollection(name);
  201. if (dropped.data.error_code === 'Success') {
  202. // remove collection from state
  203. setCollections(prev => prev.filter(v => v.collection_name !== name));
  204. }
  205. };
  206. // API: create index
  207. const createIndex = async (param: IndexCreateParam) => {
  208. // create index
  209. const newCollection = await CollectionService.createIndex(param);
  210. // update collection
  211. updateCollections([newCollection]);
  212. return newCollection;
  213. };
  214. // API: drop index
  215. const dropIndex = async (params: IndexManageParam) => {
  216. // drop index
  217. const { data } = await CollectionService.dropIndex(params);
  218. // update collection
  219. updateCollections([data]);
  220. return data;
  221. };
  222. // API: create alias
  223. const createAlias = async (collectionName: string, alias: string) => {
  224. // create alias
  225. const newCollection = await CollectionService.createAlias(collectionName, {
  226. alias,
  227. });
  228. // update collection
  229. updateCollections([newCollection]);
  230. return newCollection;
  231. };
  232. // API: drop alias
  233. const dropAlias = async (collectionName: string, alias: string) => {
  234. // drop alias
  235. const { data } = await CollectionService.dropAlias(collectionName, {
  236. alias,
  237. });
  238. // update collection
  239. updateCollections([data]);
  240. return data;
  241. };
  242. useEffect(() => {
  243. if (isAuth) {
  244. // fetch db
  245. fetchDatabases();
  246. // connect to socket server
  247. socket.current = io(url as string);
  248. // register client
  249. socket.current.emit(WS_EVENTS.REGISTER, clientId);
  250. socket.current.on('connect', function () {
  251. console.log('--- ws connected ---', clientId);
  252. setConnected(true);
  253. });
  254. } else {
  255. socket.current?.disconnect();
  256. // clear collections
  257. setCollections([]);
  258. // clear database
  259. setDatabases(['default']);
  260. // set connected to false
  261. setConnected(false);
  262. }
  263. }, [isAuth]);
  264. useEffect(() => {
  265. if (connected) {
  266. // clear data
  267. setCollections([]);
  268. // remove all listeners
  269. socket.current?.offAny();
  270. // listen to backend collection event
  271. socket.current?.on(WS_EVENTS.COLLECTION_UPDATE, updateCollections);
  272. // fetch db
  273. fetchCollections();
  274. }
  275. return () => {
  276. // remove all listeners when component unmount
  277. socket.current?.offAny();
  278. };
  279. }, [updateCollections, connected]);
  280. return (
  281. <Provider
  282. value={{
  283. loading,
  284. collections,
  285. setCollections,
  286. database,
  287. databases,
  288. setDatabase,
  289. setDatabaseList: setDatabases,
  290. fetchDatabases,
  291. fetchCollections,
  292. fetchCollection,
  293. createCollection,
  294. loadCollection,
  295. releaseCollection,
  296. renameCollection,
  297. duplicateCollection,
  298. dropCollection,
  299. createIndex,
  300. dropIndex,
  301. createAlias,
  302. dropAlias,
  303. }}
  304. >
  305. {props.children}
  306. </Provider>
  307. );
  308. };