diff --git a/package.json b/package.json index be6f25b18..2364bfb8b 100644 --- a/package.json +++ b/package.json @@ -117,8 +117,8 @@ "rehype-stringify": "^9.0.2", "remark-gfm": "^3.0.1", "resolve-url-loader": "^5.0.0", - "sass": "^1.60.0", - "sass-loader": "^13.2.0", + "sass": "1.60.0", + "sass-loader": "13.2.0", "serve": "^14.2.0", "storybook": "^7.2.3", "stream-browserify": "^3.0.0", @@ -144,8 +144,9 @@ }, "dependencies": { "@apollo/client": "^3.9.4", - "@chainsafe/libp2p-noise": "^13.0.1", - "@chainsafe/libp2p-yamux": "^5.0.0", + "@chainsafe/libp2p-gossipsub": "^13.1.0", + "@chainsafe/libp2p-noise": "^15.1.0", + "@chainsafe/libp2p-yamux": "^6.0.2", "@confio/relayer": "0.4.0", "@cosmjs/cosmwasm-stargate": "^0.30.0", "@cosmjs/crypto": "0.29.0", @@ -159,12 +160,15 @@ "@cybercongress/cyber-js": "^0.3.92", "@cybercongress/gravity": "0.0.15", "@ethersproject/providers": "^5.7.2", - "@helia/unixfs": "^1.4.2", + "@helia/unixfs": "3.0.0", "@jest/transform": "^29.5.0", "@ledgerhq/hw-transport-webusb": "5.53.0", - "@libp2p/bootstrap": "^9.0.7", - "@libp2p/webrtc": "^3.2.1", - "@libp2p/websockets": "^7.0.8", + "@libp2p/bootstrap": "^10.1.2", + "@libp2p/kad-dht": "^12.1.2", + "@libp2p/peer-id": "^4.2.1", + "@libp2p/peer-id-factory": "^4.2.1", + "@libp2p/webrtc": "^4.1.2", + "@libp2p/websockets": "^8.1.2", "@multiformats/multiaddr": "^11.4.0", "@nftstorage/ipfs-cluster": "^5.0.1", "@reduxjs/toolkit": "^1.9.3", @@ -198,6 +202,7 @@ "datastore-core": "^9.2.3", "datastore-idb": "^2.1.4", "dateformat": "^3.0.3", + "debug": "^4.3.5", "detectrtc": "^1.4.0", "dexie": "^3.0.2", "dotenv": "^16.0.3", @@ -211,8 +216,7 @@ "graphql": "^16.5.0", "graphql-request": "^5.1.0", "graphql-ws": "^5.15.0", - "helia": "^2.0.3", - "ipfs-core": "^0.18.0", + "helia": "^4.2.4", "ipfs-core-types": "^0.14.0", "ipfs-http-client": "^60.0.0", "ipfs-unixfs": "^0.2.0", @@ -222,7 +226,7 @@ "jest-text-transformer": "^1.0.4", "kubo-rpc-client": "^3.0.1", "ledger-cosmos-js": "2.1.7", - "libp2p": "^0.46.12", + "libp2p": "^1.8.1", "lodash": "^4.17.21", "long": "^5.2.0", "node-polyfill-webpack-plugin": "^2.0.1", @@ -254,7 +258,7 @@ "rxjs": "^7.8.0", "secp256k1": "^3.7.1", "sinon": "^16.0.0", - "tone": "^14.7.77", + "tone": "14.7.77", "ts-jest": "^29.1.1", "ts-jest-resolver": "^2.0.1", "videostream": "^3.2.2", diff --git a/src/containers/ipfs/components/SoulCompanion/soulCompanion.module.scss b/src/containers/ipfs/components/SoulCompanion/soulCompanion.module.scss index ba4d32dab..785b513af 100644 --- a/src/containers/ipfs/components/SoulCompanion/soulCompanion.module.scss +++ b/src/containers/ipfs/components/SoulCompanion/soulCompanion.module.scss @@ -6,7 +6,7 @@ } .soulCompanion { - margin: -10px 0; + margin: -20px 0; } .itemText { @@ -20,7 +20,7 @@ // white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - max-width: 158px; + display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; diff --git a/src/containers/ipfsSettings/ipfsComponents/infoIpfsNode.tsx b/src/containers/ipfsSettings/ipfsComponents/infoIpfsNode.tsx deleted file mode 100644 index 5a4944161..000000000 --- a/src/containers/ipfsSettings/ipfsComponents/infoIpfsNode.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { useEffect, useState } from 'react'; -import { Dots } from '../../../../components'; -import { formatCurrency, trimString } from '../../../../utils/utils'; -import { ContainerKeyValue } from './utilsComponents'; -import { useIpfs } from 'src/contexts/ipfs'; - -const PREFIXES = [ - { - prefix: 'T', - power: 1024 * 10 ** 9, - }, - { - prefix: 'G', - power: 1024 * 10 ** 6, - }, - { - prefix: 'M', - power: 1024 * 10 ** 3, - }, - { - prefix: 'K', - power: 1024, - }, -]; - -export function useGetIpfsInfo() { - const { node: ipfs } = useIpfs(); - const [repoSizeValue, setRepoSizeValue] = useState(0); - const [idIpfs, setIdIpfs] = useState({ id: '', agentVersion: '' }); - const [loading, setLoading] = useState(true); - - useEffect(() => { - const getIpfsStat = async () => { - setLoading(true); - if (ipfs !== null) { - const response = await ipfs.stats.repo(); - const repoSize = formatCurrency( - Number(response.repoSize), - 'B', - 2, - PREFIXES - ); - setRepoSizeValue(repoSize); - - const responseId = await ipfs.id(); - const { agentVersion, id } = responseId; - const idString = id.toString(); - setIdIpfs({ - id: idString, - agentVersion: agentVersion.replace(/\//g, ' '), - }); - } - setLoading(false); - }; - getIpfsStat(); - }, [ipfs]); - - return { idIpfs, repoSizeValue, loading }; -} - -function InfoIpfsNode() { - const { idIpfs, repoSizeValue, loading } = useGetIpfsInfo(); - - return ( - <> - -
id
- {loading ? ( - - ) : ( -
{idIpfs.id.length > 0 ? trimString(idIpfs.id, 8, 8) : ''}
- )} -
- -
agent version
- {loading ? :
{idIpfs.agentVersion}
} -
- -
repo size
- {loading ? :
{repoSizeValue}
} -
- - ); -} - -export default InfoIpfsNode; diff --git a/src/containers/sigma/hooks/useGetPassportByAddress.ts b/src/containers/sigma/hooks/useGetPassportByAddress.ts index a8bc4d1a6..e653ab85b 100644 --- a/src/containers/sigma/hooks/useGetPassportByAddress.ts +++ b/src/containers/sigma/hooks/useGetPassportByAddress.ts @@ -1,6 +1,7 @@ import { Citizenship } from 'src/types/citizenship'; import usePassportContract from 'src/features/passport/usePassportContract'; import { PATTERN_CYBER } from 'src/constants/patterns'; +import { parseToCitizenshipWithData } from 'src/utils/citizenship'; function useGetPassportByAddress(accounts: any) { let address = @@ -25,7 +26,7 @@ function useGetPassportByAddress(accounts: any) { }); return { - passport: data, + passport: data ? parseToCitizenshipWithData(data) : null, loading, error, }; diff --git a/src/contexts/backend/backend.tsx b/src/contexts/backend/backend.tsx index 80de1217a..4b62da504 100644 --- a/src/contexts/backend/backend.tsx +++ b/src/contexts/backend/backend.tsx @@ -1,11 +1,4 @@ -import React, { - useCallback, - useContext, - useEffect, - useMemo, - useRef, - useState, -} from 'react'; +import React, { useContext, useEffect, useMemo, useState } from 'react'; import { useAppDispatch, useAppSelector } from 'src/redux/hooks'; import { proxy, Remote } from 'comlink'; import { backgroundWorkerInstance } from 'src/services/backend/workers/background/service'; @@ -17,18 +10,24 @@ import { getIpfsOpts } from 'src/services/ipfs/config'; import { selectCurrentAddress } from 'src/redux/features/pocket'; import DbApiWrapper from 'src/services/backend/services/DbApi/DbApi'; import { CozoDbWorker } from 'src/services/backend/workers/db/worker'; -import { BackgroundWorker } from 'src/services/backend/workers/background/worker'; import { DB_NAME } from 'src/services/CozoDb/cozoDb'; import { RESET_SYNC_STATE_ACTION_NAME } from 'src/redux/reducers/backend'; import BroadcastChannelSender from 'src/services/backend/channels/BroadcastChannelSender'; // import BroadcastChannelListener from 'src/services/backend/channels/BroadcastChannelListener'; -import { Observable } from 'rxjs'; import { EmbeddingApi } from 'src/services/backend/workers/background/api/mlApi'; -import { SenseApi, createSenseApi } from './services/senseApi'; import { RuneEngine } from 'src/services/scripting/engine'; -import { Option } from 'src/types'; +import { + createP2PApi, + P2PApi, +} from 'src/services/backend/workers/background/api/p2p/p2pApi'; +import createIpfsApi, { + IpfsApi, +} from 'src/services/backend/workers/background/api/ipfsApi'; +import SyncIpfsService from 'src/services/backend/services/sync/services/p2p/SyncIpfsService'; +import { SenseApi, createSenseApi } from './services/senseApi'; +import { useBackendServiceLoaded, useFollowings } from './hooks'; const setupStoragePersistence = async () => { let isPersistedStorage = await navigator.storage.persisted(); @@ -48,26 +47,32 @@ const setupStoragePersistence = async () => { type BackendProviderContextType = { cozoDbRemote: Remote | null; senseApi: SenseApi; - ipfsApi: Remote | null; + ipfsApi: IpfsApi | null; + p2pApi: P2PApi | null; dbApi: DbApiWrapper | null; ipfsError?: string | null; isIpfsInitialized: boolean; isDbInitialized: boolean; isSyncInitialized: boolean; isReady: boolean; - embeddingApi$: Promise>; + getEmbeddingApi: Remote<() => Promise>; rune: Remote; + p2pSyncService: SyncIpfsService; }; const valueContext = { - cozoDbRemote: null, - senseApi: null, + cozoDbRemote: {} as Remote, + senseApi: {} as SenseApi, isIpfsInitialized: false, isDbInitialized: false, isSyncInitialized: false, isReady: false, - dbApi: null, - ipfsApi: null, + dbApi: {} as DbApiWrapper, + ipfsApi: {} as IpfsApi, + p2pApi: {} as P2PApi, + rune: {} as RuneEngine, + p2pSyncService: {} as SyncIpfsService, + getEmbeddingApi: null, }; const BackendContext = @@ -87,31 +92,42 @@ function BackendProvider({ children }: { children: React.ReactNode }) { const [ipfsError, setIpfsError] = useState(null); - const isDbInitialized = useAppSelector( - (state) => state.backend.services.db.status === 'started' - ); - const isIpfsInitialized = useAppSelector( - (state) => state.backend.services.ipfs.status === 'started' - ); - const isSyncInitialized = useAppSelector( - (state) => state.backend.services.sync.status === 'started' - ); + const isDbInitialized = useBackendServiceLoaded('db'); + const isIpfsInitialized = useBackendServiceLoaded('ipfs'); + const isSyncInitialized = useBackendServiceLoaded('sync'); + const isReady = isDbInitialized && isIpfsInitialized && isSyncInitialized; const myAddress = useAppSelector(selectCurrentAddress); - const { friends, following } = useAppSelector( - (state) => state.backend.community + const followings = useFollowings(); + + const broadcastApi = useMemo(() => new BroadcastChannelSender(), []); + + const { api: p2pApi } = useMemo( + () => createP2PApi(broadcastApi), + [broadcastApi] + ); + + const { ipfsInstance$, api: ipfsApi } = useMemo( + () => createIpfsApi(p2pApi, broadcastApi), + [p2pApi, broadcastApi] ); - // // TODO: preload from DB - const followings = useMemo(() => { - return Array.from(new Set([...friends, ...following])); - }, [friends, following]); + const p2pSyncService = useMemo( + () => new SyncIpfsService(ipfsApi, p2pApi), + [ipfsApi, p2pApi] + ); + + useEffect(() => { + backgroundWorkerInstance.injectIpfsApi(proxy(ipfsApi)); + + ipfsInstance$.subscribe((node: CybIpfsNode | undefined) => { + if (node) { + backgroundWorkerInstance.injectIpfsNode(proxy(node)); + } + }); + }, [ipfsApi, ipfsInstance$]); - const isReady = isDbInitialized && isIpfsInitialized && isSyncInitialized; - const [embeddingApi$, setEmbeddingApi] = - useState>>(undefined); - // const embeddingApiRef = useRef>(); useEffect(() => { console.log( process.env.IS_DEV @@ -119,32 +135,24 @@ function BackendProvider({ children }: { children: React.ReactNode }) { : '🧬 Starting backend in PROD mode...' ); - (async () => { - // embeddingApiRef.current = await backgroundWorkerInstance.embeddingApi$; - const embeddingApiInstance$ = - await backgroundWorkerInstance.embeddingApi$; - setEmbeddingApi(embeddingApiInstance$); - })(); - - setupStoragePersistence(); - + // eslint-disable-next-line @typescript-eslint/no-unused-vars const channel = new RxBroadcastChannelListener(dispatch); - backgroundWorkerInstance.ipfsApi - .start(getIpfsOpts()) - .then(() => { - setIpfsError(null); - }) - .catch((err) => { - setIpfsError(err); - console.log(`☠️ Ipfs error: ${err}`); - }); + getIpfsOpts().then((ipfsOpts) => { + ipfsApi + .start(ipfsOpts) + .then(() => { + setIpfsError(null); + }) + .catch((err) => { + setIpfsError(err); + console.log(`☠️ Ipfs error: ${err}`); + }); + }); cozoDbWorkerInstance.init().then(() => { // const dbApi = createDbApi(); - const dbApi = new DbApiWrapper(); - - dbApi.init(proxy(cozoDbWorkerInstance)); + const dbApi = new DbApiWrapper(proxy(cozoDbWorkerInstance)); setDbApi(dbApi); // pass dbApi into background worker return backgroundWorkerInstance.injectDb(proxy(dbApi)); @@ -153,6 +161,9 @@ function BackendProvider({ children }: { children: React.ReactNode }) { useEffect(() => { backgroundWorkerInstance.setParams({ myAddress }); + backgroundWorkerInstance.setRuneDeps({ + address: myAddress, + }); dispatch({ type: RESET_SYNC_STATE_ACTION_NAME }); }, [myAddress, dispatch]); @@ -169,29 +180,22 @@ function BackendProvider({ children }: { children: React.ReactNode }) { return null; }, [isDbInitialized, dbApi, myAddress, followings]); - useEffect(() => { - (async () => { - backgroundWorkerInstance.setRuneDeps({ - address: myAddress, - // TODO: proxify particular methods - // senseApi: senseApi ? proxy(senseApi) : undefined, - // signingClient: signingClient ? proxy(signingClient) : undefined, - }); - })(); - }, [myAddress]); - - const ipfsApi = useMemo( - () => (isIpfsInitialized ? backgroundWorkerInstance.ipfsApi : null), - [isIpfsInitialized] - ); + // useEffect(() => { + // (async () => { + // backgroundWorkerInstance.setRuneDeps({ + // address: myAddress, + // }); + // })(); + // }, [myAddress]); const valueMemo = useMemo( () => ({ rune: backgroundWorkerInstance.rune, - embeddingApi$: backgroundWorkerInstance.embeddingApi$, + getEmbeddingApi: backgroundWorkerInstance.getEmbeddingApi, cozoDbRemote: cozoDbWorkerInstance, ipfsApi, + p2pApi, dbApi, senseApi, ipfsError, @@ -199,6 +203,7 @@ function BackendProvider({ children }: { children: React.ReactNode }) { isDbInitialized, isSyncInitialized, isReady, + p2pSyncService, } as BackendProviderContextType), [ isReady, @@ -209,6 +214,8 @@ function BackendProvider({ children }: { children: React.ReactNode }) { senseApi, dbApi, ipfsApi, + p2pApi, + p2pSyncService, ] ); diff --git a/src/contexts/backend/hooks.ts b/src/contexts/backend/hooks.ts new file mode 100644 index 000000000..b085dc206 --- /dev/null +++ b/src/contexts/backend/hooks.ts @@ -0,0 +1,23 @@ +import { useMemo } from 'react'; +import { useAppSelector } from 'src/redux/hooks'; +import { ServiceName } from 'src/services/backend/types/services'; + +export const useBackendServiceLoaded = (serviceName: ServiceName) => + useAppSelector( + (state) => state.backend.services[serviceName].status === 'started' + ); + +export const useFollowings = () => { + // TODO: preload from DB + + const { friends, following } = useAppSelector( + (state) => state.backend.community + ); + + // // TODO: preload from DB + const followings = useMemo(() => { + return Array.from(new Set([...friends, ...following])); + }, [friends, following]); + + return followings; +}; diff --git a/src/contexts/scripting/scripting.tsx b/src/contexts/scripting/scripting.tsx index fae0a08d4..4437f3051 100644 --- a/src/contexts/scripting/scripting.tsx +++ b/src/contexts/scripting/scripting.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; import { UserContext } from 'src/services/scripting/types'; -import { Remote, proxy } from 'comlink'; +import { Remote } from 'comlink'; import { useAppDispatch, useAppSelector } from 'src/redux/hooks'; import { selectRuneEntypoints, @@ -18,12 +18,14 @@ type ScriptingContextType = { isSoulInitialized: boolean; rune: Option>; embeddingApi: Option; + isEmbeddingApiInitialized: boolean; }; const ScriptingContext = React.createContext({ isSoulInitialized: false, rune: undefined, embeddingApi: undefined, + isEmbeddingApiInitialized: false, }); export function useScripting() { @@ -35,12 +37,14 @@ function ScriptingProvider({ children }: { children: React.ReactNode }) { rune: runeBackend, ipfsApi, isIpfsInitialized, - embeddingApi$, + getEmbeddingApi, } = useBackend(); const [isSoulInitialized, setIsSoulInitialized] = useState(false); const runeRef = useRef>>(); - const embeddingApiRef = useRef>>(); + const embeddingApiRef = useRef(); + const [isEmbeddingApiInitialized, setIsEmbeddingApiInitialized] = + useState(false); const dispatch = useAppDispatch(); @@ -57,19 +61,15 @@ function ScriptingProvider({ children }: { children: React.ReactNode }) { } setIsSoulInitialized(!!v); }); - - const embeddingApiSubscription = (await embeddingApi$).subscribe( - proxy((embeddingApi) => { - if (embeddingApi) { - embeddingApiRef.current = embeddingApi; - console.log('+ embedding api initalized', embeddingApi); - } + getEmbeddingApi() + .then(async (api) => { + embeddingApiRef.current = api; + setIsEmbeddingApiInitialized(true); }) - ); + .catch(console.error); return () => { soulSubscription.unsubscribe(); - embeddingApiSubscription.unsubscribe(); }; }; @@ -133,9 +133,10 @@ function ScriptingProvider({ children }: { children: React.ReactNode }) { return { rune: runeRef.current, embeddingApi: embeddingApiRef.current, + isEmbeddingApiInitialized, isSoulInitialized, }; - }, [isSoulInitialized]); + }, [isSoulInitialized, isEmbeddingApiInitialized]); return ( diff --git a/src/features/ipfs/Drive/BackendStatus.tsx b/src/features/ipfs/Drive/BackendStatus.tsx index d810f8cce..e14117484 100644 --- a/src/features/ipfs/Drive/BackendStatus.tsx +++ b/src/features/ipfs/Drive/BackendStatus.tsx @@ -6,7 +6,7 @@ import Display from 'src/components/containerGradient/Display/Display'; // import { ServiceStatus, SyncEntryStatus } from 'src/services/backend/types'; import { ProgressTracking, - ServiceStatus as ServiceStatusInfo, + ServiceStatus, SyncEntryName, SyncProgress, } from 'src/services/backend/types/services'; @@ -16,10 +16,7 @@ import styles from './drive.scss'; import { syncEntryNameToReadable } from 'src/services/backend/services/sync/utils'; import { Button } from 'src/components'; import { downloadJson } from 'src/utils/json'; -import { useBackend } from 'src/contexts/backend/backend'; -import { EmbeddinsDbEntity } from 'src/services/CozoDb/types/entities'; import { isObject } from 'lodash'; -import { openAICompletion } from 'src/services/scripting/services/llmRequests/openai'; const getProgressTrackingInfo = (progress?: ProgressTracking) => { if (!progress) { @@ -39,7 +36,7 @@ function ServiceStatusInfo({ message, }: { name: string; - status: ServiceStatusInfo; + status: ServiceStatus; message?: string; }) { const icon = status === 'error' ? '❌' : status === 'starting' ? '⏳' : ''; @@ -67,7 +64,7 @@ function EntrySatus({ } function BackendStatus() { - const { syncState, dbPendingWrites, services, mlState } = useAppSelector( + const { syncState, dbPendingWrites, services, mlState, p2p } = useAppSelector( (store) => store.backend ); @@ -85,6 +82,25 @@ function BackendStatus() { status={services.db.status} message={services.db.error || `(queries: ${dbPendingWrites})`} /> + + {['addresses', 'peers'].map((key) => ( +
+
{key}
+ {(p2p[key] || []).length === 0 ? ( +
none
+ ) : ( + p2p[key].map((addr, index) => ( +
+ {addr} +
+ )) + )} +
+ ))} store.backend); + const { p2pApi, ipfsApi, p2pSyncService } = useBackend(); + const [msg, setMsg] = React.useState(''); + const [peerAddress, setPeerAddress] = React.useState(''); + const [isPeerAddressSet, setIsPeerAddressSet] = React.useState(false); + const { setAdviser } = useAdviser(); + + const onChange = (event: React.ChangeEvent) => { + const { value } = event.target; + setMsg(value); + }; + + const onSubmit = (event) => { + if (event.key === 'Enter') { + setMsg(''); + p2pApi?.sendPubSubMessage(DEFAUL_P2P_SERVICE_TOPIC, { + message: msg, + peerId: p2pApi.getMyPeerId(), + type: PUBSUB_CHAT_MESSAGE, + }); + } + }; + + const onChangePeerAddress = (event: React.ChangeEvent) => { + const { value } = event.target; + setPeerAddress(value); + }; + + const onSubmitPeerAddress = (event) => { + if (event.key === 'Enter') { + setIsPeerAddressSet(true); + p2pApi?.connectPeer(peerAddress); + } + }; + const reAdvertise = async () => { + const prefix = 'Re-advertising IPFS content'; + setAdviser(`${prefix}...`); + const pins = await ipfsApi!.pins(); + const total = pins.length; + let i = 0; + setAdviser(`${prefix}...${pins.length} pins found`); + // eslint-disable-next-line no-restricted-syntax + for (const pin of pins) { + const cid = pin.cid.toString(); + // eslint-disable-next-line no-await-in-loop + await p2pApi!.provideContent(cid); + i++; + setAdviser(`${prefix}: ${cid} (${Math.round((i / total) * 100)}%)`); + } + setAdviser(`${prefix}: done`); + }; + const syncPins = async () => { + setAdviser('Syncing remote node pins...'); + + const pins = await p2pSyncService.requestNodePins(peerAddress); + console.log(`-> recieved pins from ${peerAddress}`, pins); + const prefix = 'Fetching pins'; + const total = pins.length; + let i = 0; + const getPercents = () => Math.round((i / total) * 100); + setAdviser(`${prefix} (${getPercents()}%)... `); + + // eslint-disable-next-line no-restricted-syntax + for (const pin of pins) { + setAdviser(`${prefix} (${getPercents()}%): ${pin}`); + // eslint-disable-next-line no-await-in-loop + await ipfsApi!.enqueueAndWait(pin, { priority: 1 }); + i++; + } + setAdviser(`${prefix}: done`); + }; + const testConnect = async () => { + console.log('----peerid', p2pApi?.getMyPeerId()); + const peerAddress = + p2pApi.getMyPeerId() === + '12D3KooWB4KPaswRhqhuxaKiAtjezFsMKi1tDRe8tLszAvoE4huk' + ? '/dns4/acidpictures.ink/tcp/4444/wss/p2p/12D3KooWE3yj6jibgZcxMb6hrpQGKRE9xaqAazFkYaJZDZengzHq/p2p-circuit/webrtc/p2p/12D3KooWGR5S8tyeo8Q4b88YnmTwFMbj1dAvnZSoJr4TZa4zWWYk' + : '/dns4/acidpictures.ink/tcp/4444/wss/p2p/12D3KooWE3yj6jibgZcxMb6hrpQGKRE9xaqAazFkYaJZDZengzHq/p2p-circuit/webrtc/p2p/12D3KooWB4KPaswRhqhuxaKiAtjezFsMKi1tDRe8tLszAvoE4huk'; + setPeerAddress(peerAddress); + p2pApi?.connectPeer(peerAddress); + }; + return ( + } + > +
IPFS tools
+ {ipfsApi && ( + + )} + +
direct node-to-node connect
+ {/* */} + + + {isPeerAddressSet && ( + + )} +
p2p messaging
+
+ {(messages[DEFAUL_P2P_SERVICE_TOPIC] || []).map((msg, index) => ( +
+ {msg} +
+ ))} +
+ {isPeerAddressSet && ( + + )} +
+ ); +} + +export default P2PChat; diff --git a/src/features/ipfs/Drive/drive.scss b/src/features/ipfs/Drive/drive.scss index a61415683..2fbabb79d 100644 --- a/src/features/ipfs/Drive/drive.scss +++ b/src/features/ipfs/Drive/drive.scss @@ -29,6 +29,11 @@ font-size: 1.2em; } +.subTitle { + font-size: 1.2em; + margin: 20px 0 20px; +} + .commandPanel { display: flex; justify-content: space-between; @@ -73,6 +78,11 @@ padding-left: 20px; font-size: 0.85em; } +.doubleTabbed { + padding-left: 40px; + font-size: 0.85em; + text-transform: none !important; +} .buttonPanel { padding-top: 16px; @@ -87,3 +97,15 @@ display: flex; flex-direction: column; } + +.messages { + padding: 12px 0; + font-family: monospace; +} + +.green1 { + color: #00ff7f; +} +.green2 { + color: #00ff00; +} diff --git a/src/features/ipfs/Drive/index.tsx b/src/features/ipfs/Drive/index.tsx index 10e9fa69a..d2bcbc6a0 100644 --- a/src/features/ipfs/Drive/index.tsx +++ b/src/features/ipfs/Drive/index.tsx @@ -5,31 +5,26 @@ import Table from 'src/components/Table/Table'; import { toListOfObjects } from 'src/services/CozoDb/utils'; import { saveAs } from 'file-saver'; -import { Pane, Text } from '@cybercongress/gravity'; -import { - Button, - Button as CybButton, - Dots, - Input, - Loading, - Select, -} from 'src/components'; -import FileInputButton from './FileInputButton'; -import { useAppSelector } from 'src/redux/hooks'; +import { Pane } from '@cybercongress/gravity'; +import { Button, Button as CybButton, Input, Select } from 'src/components'; import Display from 'src/components/containerGradient/Display/Display'; +import { updatePassportData } from 'src/services/neuron/neuronApi'; import { useBackend } from 'src/contexts/backend/backend'; import { Link } from 'react-router-dom'; import { Colors } from 'src/components/containerGradient/types'; import classNames from 'classnames'; +import { useScripting } from 'src/contexts/scripting/scripting'; +import { useSigningClient } from 'src/contexts/signerClient'; +import { useGetPassportByAddress } from 'src/containers/sigma/hooks'; +import { RootState } from 'src/redux/store'; +import { useAppSelector } from 'src/redux/hooks'; import BackendStatus from './BackendStatus'; import cozoPresets from './cozo_presets.json'; import styles from './drive.scss'; -import { EmbeddinsDbEntity } from 'src/services/CozoDb/types/entities'; -import useEmbeddingApi from 'src/hooks/useEmbeddingApi'; -import { useScripting } from 'src/contexts/scripting/scripting'; +import FileInputButton from './FileInputButton'; const DEFAULT_PRESET_NAME = '💡 defaul commands...'; @@ -45,6 +40,12 @@ const diffMs = (t0: number, t1: number) => `${(t1 - t0).toFixed(1)}ms`; function Drive() { const [queryText, setQueryText] = useState(''); + const { signer, signingClient } = useSigningClient(); + const { defaultAccount } = useAppSelector((store: RootState) => store.pocket); + + const { passport } = useGetPassportByAddress(defaultAccount); + const [description, setDescription] = useState(''); + const [isLoaded, setIsLoaded] = useState(true); const [inProgress, setInProgress] = useState(false); const [statusMessage, setStatusMessage] = useState(''); @@ -52,16 +53,34 @@ function Drive() { // const [summarizeCid, setSummarizeCid] = useState(''); const [outputText, setOutputText] = useState(''); // const [questionText, setQuestionText] = useState(''); - const [embeddingsProcessStatus, setEmbeddingsProcessStatus] = useState(''); + // const [embeddingsProcessStatus, setEmbeddingsProcessStatus] = useState(''); const [errorMessage, setErrorMessage] = useState(); const [queryResults, setQueryResults] = useState<{ rows: []; cols: [] }>(); - const { cozoDbRemote, isReady, ipfsApi } = useBackend(); - const { embeddingApi } = useScripting(); - // const embeddingApi = useEmbeddingApi(); - - // console.log('-----syncStatus', syncState, dbPendingWrites); + const { cozoDbRemote, isReady, p2pApi } = useBackend(); + const { embeddingApi, isEmbeddingApiInitialized } = useScripting(); + useEffect(() => { + if (passport?.extension?.data?.description) { + setDescription(passport.extension.data.description); + } + }, [passport]); + function syncCitizenshipData() { + const nickname = passport?.extension.nickname; + if (nickname) { + updatePassportData( + nickname, + { + description, + peerId: p2pApi?.getMyPeerId(), + }, + { + signer, + signingClient, + } + ); + } + } function runQuery(queryArg?: string) { const query = queryArg || queryText.trim(); if (query) { @@ -202,7 +221,7 @@ function Drive() { // }; const searchByEmbeddingsClick = async () => { - const vec = await embeddingApi?.createEmbedding(searchEmbedding); + const vec = await embeddingApi!.createEmbedding(searchEmbedding); const queryText = ` e[dist, cid] := ~embeddings:semantic{cid | query: vec([${vec}]), bind_distance: dist, k: 20, ef: 50} ?[dist, cid, text] := e[dist, cid], *particle{cid, text} @@ -262,7 +281,7 @@ function Drive() {
- query using ai oriented{' '} - + datalog
@@ -272,6 +291,20 @@ function Drive() {

+ +