From 7e97c325f1e591f54cdb58eb9aaf3f3d0437b6e3 Mon Sep 17 00:00:00 2001 From: Reckless_Satoshi Date: Sat, 2 Dec 2023 11:31:21 +0000 Subject: [PATCH 1/4] Add robo-identity-wasm --- frontend/package-lock.json | 6 ++ frontend/package.json | 1 + .../RobotAvatar/RobohashGenerator.ts | 73 +++++++++++++++++++ frontend/src/components/RobotAvatar/index.tsx | 41 ++++++++--- .../components/RobotAvatar/robohash.worker.ts | 15 ++++ frontend/src/contexts/FederationContext.ts | 8 ++ frontend/src/models/Book.model.ts | 1 + frontend/src/models/Coordinator.model.ts | 8 ++ frontend/src/models/Robot.model.ts | 12 +++ frontend/webpack.config.ts | 1 + 10 files changed, 154 insertions(+), 12 deletions(-) create mode 100644 frontend/src/components/RobotAvatar/RobohashGenerator.ts create mode 100644 frontend/src/components/RobotAvatar/robohash.worker.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 26d7a606..95503e67 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -47,6 +47,7 @@ "react-smooth-image": "^1.1.0", "react-world-flags": "^1.6.0", "reconnecting-websocket": "^4.4.0", + "robo-identities-wasm": "^0.1.0", "simple-plist": "^1.3.1", "webln": "^0.3.2", "websocket": "^1.0.34" @@ -14282,6 +14283,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robo-identities-wasm": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/robo-identities-wasm/-/robo-identities-wasm-0.1.0.tgz", + "integrity": "sha512-q6+1Vgq+8d2F5k8Nqm39qwQJYe9uTC7TlR3NbBQ6k2ImBNccdAEoZgb0ikKjN59cK4MvqejlgBV1ybaLXoHbhA==" + }, "node_modules/run-applescript": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 1fd49164..4e145048 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -86,6 +86,7 @@ "react-smooth-image": "^1.1.0", "react-world-flags": "^1.6.0", "reconnecting-websocket": "^4.4.0", + "robo-identities-wasm": "^0.1.0", "simple-plist": "^1.3.1", "webln": "^0.3.2", "websocket": "^1.0.34" diff --git a/frontend/src/components/RobotAvatar/RobohashGenerator.ts b/frontend/src/components/RobotAvatar/RobohashGenerator.ts new file mode 100644 index 00000000..2d25a89f --- /dev/null +++ b/frontend/src/components/RobotAvatar/RobohashGenerator.ts @@ -0,0 +1,73 @@ +class RoboGenerator { + private assetsCache: Record = {}; + private assetsPromises: Record> = {}; + private readonly workers: Worker[] = []; + + constructor() { + // limit to 8 workers + const numCores = Math.min(navigator.hardwareConcurrency || 1, 8); + + for (let i = 0; i < numCores; i++) { + const worker = new Worker(new URL('./robohash.worker.ts', import.meta.url)); + this.workers.push(worker); + } + } + + public generate: (hash: string, size: 'small' | 'large') => Promise = async ( + hash, + size, + ) => { + const cacheKey = `${size}px;${hash}`; + if (this.assetsCache[cacheKey]) { + return this.assetsCache[cacheKey]; + } else if (cacheKey in this.assetsPromises) { + return await this.assetsPromises[cacheKey]; + } + + const workerIndex = Object.keys(this.assetsPromises).length % this.workers.length; + const worker = this.workers[workerIndex]; + + this.assetsPromises[cacheKey] = new Promise((resolve, reject) => { + // const avatarB64 = async_generate_robohash(hash, size == 'small' ? 80 : 256).then((avatarB64)=> resolve(`data:image/png;base64,${avatarB64}`)); + // Create a message object with the necessary data + const message = { hash, size, cacheKey, workerIndex }; + + // Listen for messages from the worker + const handleMessage = (event: MessageEvent) => { + const { cacheKey, imageUrl } = event.data; + + // Update the cache and resolve the promise + this.assetsCache[cacheKey] = imageUrl; + delete this.assetsPromises[cacheKey]; + resolve(imageUrl); + }; + + // Add the event listener for messages + worker.addEventListener('message', handleMessage); + + // Send the message to the worker + worker.postMessage(message); + + // Clean up the event listener after receiving the result + const cleanup = () => { + worker.removeEventListener('message', handleMessage); + }; + + // Reject the promise if an error occurs + worker.addEventListener('error', (error) => { + cleanup(); + reject(error); + }); + + // Reject the promise if the worker times out + setTimeout(() => { + cleanup(); + reject(new Error('Generation timed out')); + }, 5000); // Adjust the timeout duration as needed + }); + + return await this.assetsPromises[cacheKey]; + }; +} + +export const robohash = new RoboGenerator(); diff --git a/frontend/src/components/RobotAvatar/index.tsx b/frontend/src/components/RobotAvatar/index.tsx index 7d4b89ae..98b74b7a 100644 --- a/frontend/src/components/RobotAvatar/index.tsx +++ b/frontend/src/components/RobotAvatar/index.tsx @@ -1,11 +1,10 @@ -import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import SmoothImage from 'react-smooth-image'; import { Avatar, Badge, Tooltip } from '@mui/material'; import { SendReceiveIcon } from '../Icons'; import { apiClient } from '../../services/api'; import placeholder from './placeholder.json'; -import { type UseAppStoreType, AppContext } from '../../contexts/AppContext'; -import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext'; +import { robohash } from './RobohashGenerator'; interface Props { nickname: string | undefined; @@ -59,21 +58,39 @@ const RobotAvatar: React.FC = ({ const className = placeholderType === 'loading' ? 'loadingAvatar' : 'generatingAvatar'; useEffect(() => { - if (nickname !== undefined) { + // TODO: HANDLE ANDROID AVATARS TOO (when window.NativeRobosats !== undefined) + if (nickname !== undefined && !coordinator) { + robohash + .generate(nickname, small ? 'small' : 'large') // TODO: should hash_id + .then((avatar) => { + setAvatarSrc(avatar); + }) + .catch(() => { + setAvatarSrc(''); + }); + setNicknameReady(true); + setActiveBackground(false); + } + + if (coordinator) { if (window.NativeRobosats === undefined) { - setAvatarSrc(`${baseUrl}${path}${nickname}${small ? '.small' : ''}.webp`); - setNicknameReady(true); - } else if (baseUrl != null && apiClient.fileImageUrl !== undefined) { - setNicknameReady(true); - void apiClient - .fileImageUrl(baseUrl, `${path}${nickname}${small ? '.small' : ''}.webp`) - .then(setAvatarSrc); + setAvatarSrc( + `${baseUrl}/static/federation/avatars/${nickname}${small ? '.small' : ''}.webp`, + ); + } else { + setAvatarSrc( + `file:///android_asset/Web.bundle/assets/federation/avatars/${nickname}${ + small ? ' .small' : '' + }.webp`, + ); } + setNicknameReady(true); + setActiveBackground(false); } else { setNicknameReady(false); setActiveBackground(true); } - }, [nickname]); + }, [nickname]); // TODO: should hash_id const statusBadge = (
diff --git a/frontend/src/components/RobotAvatar/robohash.worker.ts b/frontend/src/components/RobotAvatar/robohash.worker.ts new file mode 100644 index 00000000..a7549235 --- /dev/null +++ b/frontend/src/components/RobotAvatar/robohash.worker.ts @@ -0,0 +1,15 @@ +import { async_generate_robohash } from 'robo-identities-wasm'; + +// Listen for messages from the main thread +self.addEventListener('message', async (event) => { + const { hash, size, cacheKey, workerIndex } = event.data; + + // Generate the image using async_image_base + const t0 = performance.now(); + const avatarB64 = await async_generate_robohash(hash, size == 'small' ? 80 : 256); + const imageUrl = `data:image/png;base64,${avatarB64}`; + const t1 = performance.now(); + console.log(`Worker ${workerIndex} :: Time to generate avatar: ${t1 - t0} ms`); + // Send the result back to the main thread + self.postMessage({ cacheKey, imageUrl }); +}); diff --git a/frontend/src/contexts/FederationContext.ts b/frontend/src/contexts/FederationContext.ts index 7ce19769..d22e606a 100644 --- a/frontend/src/contexts/FederationContext.ts +++ b/frontend/src/contexts/FederationContext.ts @@ -151,11 +151,19 @@ export const useFederationStore = (): UseFederationStoreType => { const slot = garage.getSlot(); const robot = slot?.getRobot(); +<<<<<<< HEAD if (robot != null && garage.currentSlot != null) { if (open.profile && slot?.avatarLoaded === true && slot.token != null) { void federation.fetchRobot(garage, slot.token); // refresh/update existing robot } else if ( !(slot?.avatarLoaded === true) && +======= + if (robot != null && garage.currentSlot) { + if (open.profile && slot?.avatarLoaded && slot.token) { + void federation.fetchRobot(garage, slot.token); // refresh/update existing robot + } else if ( + !slot?.avatarLoaded && +>>>>>>> f861207a (Add robo-identity-wasm) robot.token !== undefined && robot.encPrivKey !== undefined && robot.pubKey !== undefined diff --git a/frontend/src/models/Book.model.ts b/frontend/src/models/Book.model.ts index 9f515962..8c4e8850 100644 --- a/frontend/src/models/Book.model.ts +++ b/frontend/src/models/Book.model.ts @@ -20,6 +20,7 @@ export interface PublicOrder { maker: number; escrow_duration: number; maker_nick: string; + maker_hash_id: string; price: number; maker_status: 'Active' | 'Seen recently' | 'Inactive'; coordinatorShortAlias?: string; diff --git a/frontend/src/models/Coordinator.model.ts b/frontend/src/models/Coordinator.model.ts index 8eab5521..8b3548fd 100644 --- a/frontend/src/models/Coordinator.model.ts +++ b/frontend/src/models/Coordinator.model.ts @@ -10,6 +10,7 @@ import { apiClient } from '../services/api'; import { validateTokenEntropy } from '../utils'; import { compareUpdateLimit } from './Limit.model'; import { defaultOrder } from './Order.model'; +import { robohash } from '../components/RobotAvatar/RobohashGenerator'; export interface Contact { nostr?: string | undefined; @@ -156,6 +157,12 @@ export class Coordinator { this.loadInfo(onDataLoad); }; + generateAllMakerAvatars = (data: [PublicOrder]) => { + for (const order of data) { + robohash.generate(order.maker_hash_id, 'small'); + } + }; + loadBook = (onDataLoad: () => void = () => {}): void => { if (this.enabled === false) return; if (this.loadingBook) return; @@ -170,6 +177,7 @@ export class Coordinator { order.coordinatorShortAlias = this.shortAlias; return order; }); + this.generateAllMakerAvatars(data); onDataLoad(); } }) diff --git a/frontend/src/models/Robot.model.ts b/frontend/src/models/Robot.model.ts index 86cb07e3..6f525f7e 100644 --- a/frontend/src/models/Robot.model.ts +++ b/frontend/src/models/Robot.model.ts @@ -1,5 +1,7 @@ import { sha256 } from 'js-sha256'; import { hexToBase91 } from '../utils'; +import { robohash } from '../components/RobotAvatar/RobohashGenerator'; +import { generate_roboname } from 'robo-identities-wasm'; interface AuthHeaders { tokenSHA256: string; @@ -13,6 +15,7 @@ class Robot { constructor(garageRobot?: Robot) { if (garageRobot != null) { this.token = garageRobot?.token ?? undefined; + this.hash_id = garageRobot?.hash_id ?? undefined; this.tokenSHA256 = garageRobot?.tokenSHA256 ?? (this.token != null ? hexToBase91(sha256(this.token)) : ''); this.pubKey = garageRobot?.pubKey ?? undefined; @@ -22,6 +25,7 @@ class Robot { public nickname?: string; public token?: string; + public hash_id?: string; public bitsEntropy?: number; public shannonEntropy?: number; public tokenSHA256: string = ''; @@ -41,6 +45,14 @@ class Robot { update = (attributes: Record): void => { Object.assign(this, attributes); + if (attributes.token != null) { + const hash_id = sha256(sha256(attributes.token)); + this.hash_id = hash_id; + this.nickname = generate_roboname(hash_id); + // trigger RoboHash avatar generation in webworker and store in RoboHash class cache. + robohash.generate(hash_id, 'small'); + robohash.generate(hash_id, 'large'); + } }; getAuthHeaders = (): AuthHeaders | null => { diff --git a/frontend/webpack.config.ts b/frontend/webpack.config.ts index 76950736..51594f86 100644 --- a/frontend/webpack.config.ts +++ b/frontend/webpack.config.ts @@ -18,6 +18,7 @@ const config: Configuration = { }, ], }, + experiments: { asyncWebAssembly: true }, resolve: { extensions: ['.tsx', '.ts', '.jsx', '.js'], }, From 4fda9370fd4ed2813787d3c1effb724f35cd0282 Mon Sep 17 00:00:00 2001 From: Reckless_Satoshi Date: Sat, 2 Dec 2023 12:12:52 +0000 Subject: [PATCH 2/4] Small fixes --- frontend/src/basic/Main.tsx | 12 +--- frontend/src/basic/NavBar/NavBar.tsx | 3 +- frontend/src/basic/RobotPage/Onboarding.tsx | 3 +- frontend/src/basic/RobotPage/RobotProfile.tsx | 8 +-- frontend/src/basic/RobotPage/index.tsx | 8 +-- frontend/src/components/BookTable/index.tsx | 10 +-- .../src/components/Dialogs/Coordinator.tsx | 4 +- frontend/src/components/Dialogs/Profile.tsx | 3 +- .../src/components/FederationTable/index.tsx | 4 +- .../src/components/OrderDetails/index.tsx | 15 ++--- frontend/src/components/RobotAvatar/index.tsx | 61 ++++++++++--------- frontend/src/contexts/FederationContext.ts | 8 --- frontend/src/models/Order.model.ts | 4 ++ frontend/src/models/Robot.model.ts | 16 ++--- 14 files changed, 64 insertions(+), 95 deletions(-) diff --git a/frontend/src/basic/Main.tsx b/frontend/src/basic/Main.tsx index 1ec99a23..989c997b 100644 --- a/frontend/src/basic/Main.tsx +++ b/frontend/src/basic/Main.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useState } from 'react'; +import React, { useContext, useEffect } from 'react'; import { MemoryRouter, BrowserRouter, Routes, Route } from 'react-router-dom'; import { Box, Slide, Typography, styled } from '@mui/material'; import { type UseAppStoreType, AppContext, closeAll } from '../contexts/AppContext'; @@ -34,11 +34,6 @@ const Main: React.FC = () => { useContext(AppContext); const { federation, sortedCoordinators } = useContext(FederationContext); const { garage } = useContext(GarageContext); - const [avatarBaseUrl, setAvatarBaseUrl] = useState(hostUrl); - - useEffect(() => { - setAvatarBaseUrl(federation.getCoordinator(sortedCoordinators[0]).getBaseUrl()); - }, [settings.network, settings.selfhostedClient, federation, sortedCoordinators]); const onLoad = (): void => { garage.updateSlot({ avatarLoaded: true }); @@ -48,8 +43,7 @@ const Main: React.FC = () => { { appear={slideDirection.in !== undefined} >
- +
} diff --git a/frontend/src/basic/NavBar/NavBar.tsx b/frontend/src/basic/NavBar/NavBar.tsx index 5f7148ac..3ca0f286 100644 --- a/frontend/src/basic/NavBar/NavBar.tsx +++ b/frontend/src/basic/NavBar/NavBar.tsx @@ -130,8 +130,7 @@ const NavBar = (): JSX.Element => { ) : ( <> diff --git a/frontend/src/basic/RobotPage/Onboarding.tsx b/frontend/src/basic/RobotPage/Onboarding.tsx index 2b666f53..389723aa 100644 --- a/frontend/src/basic/RobotPage/Onboarding.tsx +++ b/frontend/src/basic/RobotPage/Onboarding.tsx @@ -164,7 +164,7 @@ const Onboarding = ({ diff --git a/frontend/src/basic/RobotPage/RobotProfile.tsx b/frontend/src/basic/RobotPage/RobotProfile.tsx index 1cb9d066..f0835db6 100644 --- a/frontend/src/basic/RobotPage/RobotProfile.tsx +++ b/frontend/src/basic/RobotPage/RobotProfile.tsx @@ -44,7 +44,7 @@ const RobotProfile = ({ setView, width, }: RobotProfileProps): JSX.Element => { - const { windowSize, hostUrl } = useContext(AppContext); + const { windowSize } = useContext(AppContext); const { garage, robotUpdatedAt, orderUpdatedAt } = useContext(GarageContext); const { sortedCoordinators } = useContext(FederationContext); @@ -127,7 +127,7 @@ const RobotProfile = ({ {robot?.found === true && slot?.lastShortAlias != null ? ( @@ -275,11 +274,10 @@ const RobotProfile = ({ > diff --git a/frontend/src/basic/RobotPage/index.tsx b/frontend/src/basic/RobotPage/index.tsx index 793a4abd..3b747dc2 100644 --- a/frontend/src/basic/RobotPage/index.tsx +++ b/frontend/src/basic/RobotPage/index.tsx @@ -23,11 +23,7 @@ import { validateTokenEntropy } from '../../utils'; import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext'; import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext'; -interface RobotPageProps { - avatarBaseUrl: string; -} - -const RobotPage = ({ avatarBaseUrl }: RobotPageProps): JSX.Element => { +const RobotPage = (): JSX.Element => { const { torStatus, windowSize, settings, page } = useContext(AppContext); const { garage } = useContext(GarageContext); const { federation, sortedCoordinators } = useContext(FederationContext); @@ -158,7 +154,6 @@ const RobotPage = ({ avatarBaseUrl }: RobotPageProps): JSX.Element => { inputToken={inputToken} setInputToken={setInputToken} getGenerateRobot={getGenerateRobot} - avatarBaseUrl={avatarBaseUrl} /> ) : null} @@ -170,7 +165,6 @@ const RobotPage = ({ avatarBaseUrl }: RobotPageProps): JSX.Element => { inputToken={inputToken} setInputToken={setInputToken} getGenerateRobot={getGenerateRobot} - avatarBaseUrl={avatarBaseUrl} /> ) : null} diff --git a/frontend/src/components/BookTable/index.tsx b/frontend/src/components/BookTable/index.tsx index aa0fddb2..54c21067 100644 --- a/frontend/src/components/BookTable/index.tsx +++ b/frontend/src/components/BookTable/index.tsx @@ -220,14 +220,13 @@ const BookTable = ({ > @@ -257,14 +256,13 @@ const BookTable = ({ }} >
); @@ -293,12 +291,10 @@ const BookTable = ({ > diff --git a/frontend/src/components/Dialogs/Coordinator.tsx b/frontend/src/components/Dialogs/Coordinator.tsx index bddb67ae..288094b4 100644 --- a/frontend/src/components/Dialogs/Coordinator.tsx +++ b/frontend/src/components/Dialogs/Coordinator.tsx @@ -362,12 +362,10 @@ const CoordinatorDialog = ({ open = false, onClose, network, shortAlias }: Props diff --git a/frontend/src/components/Dialogs/Profile.tsx b/frontend/src/components/Dialogs/Profile.tsx index 3a48b2f9..248ebdb1 100644 --- a/frontend/src/components/Dialogs/Profile.tsx +++ b/frontend/src/components/Dialogs/Profile.tsx @@ -83,8 +83,7 @@ const ProfileDialog = ({ open = false, baseUrl, onClose }: Props): JSX.Element = diff --git a/frontend/src/components/FederationTable/index.tsx b/frontend/src/components/FederationTable/index.tsx index 8958afc9..8c7cf816 100644 --- a/frontend/src/components/FederationTable/index.tsx +++ b/frontend/src/components/FederationTable/index.tsx @@ -75,12 +75,10 @@ const FederationTable = ({ > diff --git a/frontend/src/components/OrderDetails/index.tsx b/frontend/src/components/OrderDetails/index.tsx index 48cc52e8..d913801d 100644 --- a/frontend/src/components/OrderDetails/index.tsx +++ b/frontend/src/components/OrderDetails/index.tsx @@ -264,12 +264,7 @@ const OrderDetails = ({ {' '} - + @@ -283,10 +278,9 @@ const OrderDetails = ({ @@ -315,12 +309,11 @@ const OrderDetails = ({ diff --git a/frontend/src/components/RobotAvatar/index.tsx b/frontend/src/components/RobotAvatar/index.tsx index 98b74b7a..5266ffbd 100644 --- a/frontend/src/components/RobotAvatar/index.tsx +++ b/frontend/src/components/RobotAvatar/index.tsx @@ -1,15 +1,15 @@ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import SmoothImage from 'react-smooth-image'; import { Avatar, Badge, Tooltip } from '@mui/material'; import { SendReceiveIcon } from '../Icons'; -import { apiClient } from '../../services/api'; import placeholder from './placeholder.json'; import { robohash } from './RobohashGenerator'; +import { AppContext, UseAppStoreType } from '../../contexts/AppContext'; interface Props { - nickname: string | undefined; + shortAlias?: string | undefined; + hashId?: string | undefined; smooth?: boolean; - coordinator?: boolean; small?: boolean; flipHorizontally?: boolean; style?: object; @@ -21,7 +21,6 @@ interface Props { tooltipPosition?: string; avatarClass?: string; onLoad?: () => void; - baseUrl: string; } interface BackgroundData { @@ -30,7 +29,8 @@ interface BackgroundData { } const RobotAvatar: React.FC = ({ - nickname, + shortAlias, + hashId, orderType, statusColor, tooltip, @@ -43,14 +43,13 @@ const RobotAvatar: React.FC = ({ avatarClass = 'flippedSmallAvatar', imageStyle = {}, onLoad = () => {}, - coordinator = false, - baseUrl, }) => { - const [avatarSrc, setAvatarSrc] = useState(); - const [nicknameReady, setNicknameReady] = useState(false); + const [avatarSrc, setAvatarSrc] = useState(''); + const [avatarReady, setAvatarReady] = useState(false); const [activeBackground, setActiveBackground] = useState(true); + const { hostUrl } = useContext(AppContext); + const backgroundFadeTime = 3000; - const path = coordinator ? '/static/federation/avatars/' : '/static/assets/avatars/'; const [backgroundData] = useState( placeholderType === 'generating' ? placeholder.generating : placeholder.loading, ); @@ -59,38 +58,44 @@ const RobotAvatar: React.FC = ({ useEffect(() => { // TODO: HANDLE ANDROID AVATARS TOO (when window.NativeRobosats !== undefined) - if (nickname !== undefined && !coordinator) { + if (hashId !== undefined) { robohash - .generate(nickname, small ? 'small' : 'large') // TODO: should hash_id + .generate(hashId, small ? 'small' : 'large') .then((avatar) => { setAvatarSrc(avatar); }) .catch(() => { setAvatarSrc(''); }); - setNicknameReady(true); - setActiveBackground(false); + setAvatarReady(true); + setTimeout(() => { + setActiveBackground(false); + }, backgroundFadeTime); } + }, [hashId]); - if (coordinator) { + useEffect(() => { + if (shortAlias !== undefined) { if (window.NativeRobosats === undefined) { setAvatarSrc( - `${baseUrl}/static/federation/avatars/${nickname}${small ? '.small' : ''}.webp`, + `${hostUrl}/static/federation/avatars/${shortAlias}${small ? '.small' : ''}.webp`, ); } else { setAvatarSrc( - `file:///android_asset/Web.bundle/assets/federation/avatars/${nickname}${ + `file:///android_asset/Web.bundle/assets/federation/avatars/${shortAlias}${ small ? ' .small' : '' }.webp`, ); } - setNicknameReady(true); - setActiveBackground(false); + setAvatarReady(true); + setTimeout(() => { + setActiveBackground(false); + }, backgroundFadeTime); } else { - setNicknameReady(false); + setAvatarReady(false); setActiveBackground(true); } - }, [nickname]); // TODO: should hash_id + }, [shortAlias]); // TODO: should hashId const statusBadge = (
@@ -106,6 +111,7 @@ const RobotAvatar: React.FC = ({ ); const avatar = useMemo(() => { + console.log(avatarSrc, avatarReady); if (smooth) { return (
= ({ >
{ - setActiveBackground(false); - }, 5000), }} />
@@ -140,8 +143,8 @@ const RobotAvatar: React.FC = ({ = ({ /> ); } - }, [nickname, nicknameReady, avatarSrc, statusColor, tooltip, avatarClass]); + }, [hashId, shortAlias, avatarReady, avatarSrc, statusColor, tooltip, avatarClass]); const getAvatarWithBadges = useCallback(() => { let component = avatar; diff --git a/frontend/src/contexts/FederationContext.ts b/frontend/src/contexts/FederationContext.ts index d22e606a..7ce19769 100644 --- a/frontend/src/contexts/FederationContext.ts +++ b/frontend/src/contexts/FederationContext.ts @@ -151,19 +151,11 @@ export const useFederationStore = (): UseFederationStoreType => { const slot = garage.getSlot(); const robot = slot?.getRobot(); -<<<<<<< HEAD if (robot != null && garage.currentSlot != null) { if (open.profile && slot?.avatarLoaded === true && slot.token != null) { void federation.fetchRobot(garage, slot.token); // refresh/update existing robot } else if ( !(slot?.avatarLoaded === true) && -======= - if (robot != null && garage.currentSlot) { - if (open.profile && slot?.avatarLoaded && slot.token) { - void federation.fetchRobot(garage, slot.token); // refresh/update existing robot - } else if ( - !slot?.avatarLoaded && ->>>>>>> f861207a (Add robo-identity-wasm) robot.token !== undefined && robot.encPrivKey !== undefined && robot.pubKey !== undefined diff --git a/frontend/src/models/Order.model.ts b/frontend/src/models/Order.model.ts index 78b9e927..62a82b96 100644 --- a/frontend/src/models/Order.model.ts +++ b/frontend/src/models/Order.model.ts @@ -62,7 +62,9 @@ export interface Order { is_buyer: boolean; is_seller: boolean; maker_nick: string; + maker_hash_id: string; taker_nick: string; + taker_hash_id: string; status_message: string; is_fiat_sent: boolean; is_disputed: boolean; @@ -150,7 +152,9 @@ export const defaultOrder: Order = { is_buyer: false, is_seller: false, maker_nick: '', + maker_hash_id: '', taker_nick: '', + taker_hash_id: '', status_message: '', is_fiat_sent: false, is_disputed: false, diff --git a/frontend/src/models/Robot.model.ts b/frontend/src/models/Robot.model.ts index 6f525f7e..ea5cfb8e 100644 --- a/frontend/src/models/Robot.model.ts +++ b/frontend/src/models/Robot.model.ts @@ -15,7 +15,7 @@ class Robot { constructor(garageRobot?: Robot) { if (garageRobot != null) { this.token = garageRobot?.token ?? undefined; - this.hash_id = garageRobot?.hash_id ?? undefined; + this.hashId = garageRobot?.hashId ?? undefined; this.tokenSHA256 = garageRobot?.tokenSHA256 ?? (this.token != null ? hexToBase91(sha256(this.token)) : ''); this.pubKey = garageRobot?.pubKey ?? undefined; @@ -25,7 +25,7 @@ class Robot { public nickname?: string; public token?: string; - public hash_id?: string; + public hashId?: string; public bitsEntropy?: number; public shannonEntropy?: number; public tokenSHA256: string = ''; @@ -45,13 +45,15 @@ class Robot { update = (attributes: Record): void => { Object.assign(this, attributes); + + // generate robo identity if (attributes.token != null) { - const hash_id = sha256(sha256(attributes.token)); - this.hash_id = hash_id; - this.nickname = generate_roboname(hash_id); + const hashId = sha256(sha256(attributes.token)); + this.hashId = hashId; + this.nickname = generate_roboname(hashId); // trigger RoboHash avatar generation in webworker and store in RoboHash class cache. - robohash.generate(hash_id, 'small'); - robohash.generate(hash_id, 'large'); + robohash.generate(hashId, 'small'); + robohash.generate(hashId, 'large'); } }; From 25e6e82a9f0509733e368e79c31eabfebcabfe8f Mon Sep 17 00:00:00 2001 From: Reckless_Satoshi Date: Sat, 2 Dec 2023 20:19:23 +0000 Subject: [PATCH 3/4] Small fixes --- frontend/src/basic/Main.tsx | 6 ++---- frontend/src/basic/RobotPage/RobotProfile.tsx | 5 +++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/src/basic/Main.tsx b/frontend/src/basic/Main.tsx index 989c997b..0ba4318e 100644 --- a/frontend/src/basic/Main.tsx +++ b/frontend/src/basic/Main.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect } from 'react'; +import React, { useContext } from 'react'; import { MemoryRouter, BrowserRouter, Routes, Route } from 'react-router-dom'; import { Box, Slide, Typography, styled } from '@mui/material'; import { type UseAppStoreType, AppContext, closeAll } from '../contexts/AppContext'; @@ -8,7 +8,6 @@ import RobotAvatar from '../components/RobotAvatar'; import Notifications from '../components/Notifications'; import { useTranslation } from 'react-i18next'; -import { FederationContext, type UseFederationStoreType } from '../contexts/FederationContext'; import { GarageContext, type UseGarageStoreType } from '../contexts/GarageContext'; const Router = window.NativeRobosats === undefined ? BrowserRouter : MemoryRouter; @@ -30,9 +29,8 @@ const MainBox = styled(Box)((props) => ({ const Main: React.FC = () => { const { t } = useTranslation(); - const { settings, page, slideDirection, setOpen, windowSize, navbarHeight, hostUrl } = + const { settings, page, slideDirection, setOpen, windowSize, navbarHeight } = useContext(AppContext); - const { federation, sortedCoordinators } = useContext(FederationContext); const { garage } = useContext(GarageContext); const onLoad = (): void => { diff --git a/frontend/src/basic/RobotPage/RobotProfile.tsx b/frontend/src/basic/RobotPage/RobotProfile.tsx index f0835db6..383f27f2 100644 --- a/frontend/src/basic/RobotPage/RobotProfile.tsx +++ b/frontend/src/basic/RobotPage/RobotProfile.tsx @@ -262,6 +262,11 @@ const RobotProfile = ({ ) : ( Object.values(garage.slots).map((slot: Slot, index: number) => { + console.log('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'); + console.log(slot); + console.log(slot.getRobot()); + console.log(slot?.getRobot()?.hashId); + console.log('BBBBBBBBBBBBBBBBBBBBBBBBBBBB'); return ( Date: Fri, 15 Dec 2023 15:17:46 +0000 Subject: [PATCH 4/4] Avatar hashid in Garage (#983) --- frontend/src/basic/BookPage/index.tsx | 2 +- frontend/src/basic/Main.tsx | 10 +------- frontend/src/basic/MakerPage/index.tsx | 2 +- frontend/src/basic/NavBar/NavBar.tsx | 14 +++++------ frontend/src/basic/RobotPage/Onboarding.tsx | 10 ++++---- frontend/src/basic/RobotPage/RobotProfile.tsx | 23 +++++++------------ frontend/src/components/Dialogs/Profile.tsx | 10 ++++---- .../src/components/MakerForm/MakerForm.tsx | 2 +- .../components/OrderDetails/TakeButton.tsx | 2 +- frontend/src/components/RobotAvatar/index.tsx | 11 +++------ .../EncryptedSocketChat/index.tsx | 2 +- frontend/src/contexts/FederationContext.ts | 5 ++-- frontend/src/models/Garage.model.ts | 9 ++++---- frontend/src/models/Robot.model.ts | 15 ------------ frontend/src/models/Slot.model.ts | 19 ++++++++++----- 15 files changed, 53 insertions(+), 83 deletions(-) diff --git a/frontend/src/basic/BookPage/index.tsx b/frontend/src/basic/BookPage/index.tsx index 85aa695d..30b28ba9 100644 --- a/frontend/src/basic/BookPage/index.tsx +++ b/frontend/src/basic/BookPage/index.tsx @@ -31,7 +31,7 @@ const BookPage = (): JSX.Element => { const chartWidthEm = width - maxBookTableWidth; const onOrderClicked = function (id: number, shortAlias: string): void { - if (garage.getSlot()?.avatarLoaded === true) { + if (Boolean(garage.getSlot()?.hashId)) { setDelay(10000); navigate(`/order/${shortAlias}/${id}`); } else { diff --git a/frontend/src/basic/Main.tsx b/frontend/src/basic/Main.tsx index 0ba4318e..b87d564a 100644 --- a/frontend/src/basic/Main.tsx +++ b/frontend/src/basic/Main.tsx @@ -33,17 +33,9 @@ const Main: React.FC = () => { useContext(AppContext); const { garage } = useContext(GarageContext); - const onLoad = (): void => { - garage.updateSlot({ avatarLoaded: true }); - }; - return ( - + { diff --git a/frontend/src/basic/MakerPage/index.tsx b/frontend/src/basic/MakerPage/index.tsx index 8fee6249..c4f4d585 100644 --- a/frontend/src/basic/MakerPage/index.tsx +++ b/frontend/src/basic/MakerPage/index.tsx @@ -51,7 +51,7 @@ const MakerPage = (): JSX.Element => { ]); const onOrderClicked = function (id: number): void { - if (garage.getSlot()?.avatarLoaded === true) { + if (Boolean(garage.getSlot()?.hashId)) { navigate(`/order/${id}`); } else { setOpenNoRobot(true); diff --git a/frontend/src/basic/NavBar/NavBar.tsx b/frontend/src/basic/NavBar/NavBar.tsx index 3ca0f286..34cbbfaf 100644 --- a/frontend/src/basic/NavBar/NavBar.tsx +++ b/frontend/src/basic/NavBar/NavBar.tsx @@ -32,7 +32,7 @@ const NavBar = (): JSX.Element => { navbarHeight, hostUrl, } = useContext(AppContext); - const { garage, orderUpdatedAt } = useContext(GarageContext); + const { garage, orderUpdatedAt, robotUpdatedAt } = useContext(GarageContext); const navigate = useNavigate(); const location = useLocation(); @@ -42,7 +42,7 @@ const NavBar = (): JSX.Element => { const tabSx = smallBar ? { position: 'relative', - bottom: garage.getSlot()?.avatarLoaded === true ? '0.9em' : '0.13em', + bottom: Boolean(garage.getSlot()?.hashId) ? '0.9em' : '0.13em', minWidth: '1em', } : { position: 'relative', bottom: '1em', minWidth: '2em' }; @@ -65,7 +65,7 @@ const NavBar = (): JSX.Element => { if (isPage(pathPage)) { setPage(pathPage); } - }, [location, navigate, setPage, orderUpdatedAt]); + }, [location, navigate, setPage, orderUpdatedAt, robotUpdatedAt]); const handleSlideDirection = function (oldPage: Page, newPage: Page): void { const oldPos: number = pagesPosition[oldPage]; @@ -121,16 +121,16 @@ const NavBar = (): JSX.Element => { { setOpen({ ...closeAll, profile: !open.profile }); }} icon={ - slot?.getRobot()?.nickname != null && slot?.avatarLoaded ? ( + slot?.hashId ? ( ) : ( <> @@ -165,7 +165,7 @@ const NavBar = (): JSX.Element => { label={smallBar ? undefined : t('Order')} value='order' disabled={ - slot?.avatarLoaded === false || + !Boolean(slot?.hashId) || !(slot?.getRobot(slot?.activeShortAlias ?? '')?.activeOrderId != null) } icon={} diff --git a/frontend/src/basic/RobotPage/Onboarding.tsx b/frontend/src/basic/RobotPage/Onboarding.tsx index 389723aa..323dc4c5 100644 --- a/frontend/src/basic/RobotPage/Onboarding.tsx +++ b/frontend/src/basic/RobotPage/Onboarding.tsx @@ -151,7 +151,7 @@ const Onboarding = ({ - {slot?.avatarLoaded === true && Boolean(robot?.nickname) ? ( + {Boolean(slot?.hashId) ? ( t('This is your trading avatar') ) : ( <> @@ -164,7 +164,7 @@ const Onboarding = ({ - {slot?.avatarLoaded === true && Boolean(robot?.nickname) ? ( + {Boolean(slot?.hashId) ? ( {t('Hi! My name is')} @@ -198,7 +198,7 @@ const Onboarding = ({ width: '1.5em', }} /> - {robot.nickname} + {slot?.nickname} ) : null} - +