diff --git a/scripts/build-webhapp.sh b/scripts/build-webhapp.sh index 1289a8f0..cdcca985 100644 --- a/scripts/build-webhapp.sh +++ b/scripts/build-webhapp.sh @@ -4,6 +4,6 @@ set -e yarn workspace acorn-ui build -yarn run zip-we-applet +npx bestzip web/dist.zip web/dist/* cd we-applet -hc web-app pack workdir --recursive \ No newline at end of file +hc web-app pack . --recursive \ No newline at end of file diff --git a/we-applet/acorn-applet.webhapp b/we-applet/acorn-applet.webhapp new file mode 100644 index 00000000..01f6112c Binary files /dev/null and b/we-applet/acorn-applet.webhapp differ diff --git a/we-applet/web-happ.yaml b/we-applet/web-happ.yaml index 33a5f5ba..e517ce82 100644 --- a/we-applet/web-happ.yaml +++ b/we-applet/web-happ.yaml @@ -2,6 +2,6 @@ manifest_version: "1" name: acorn-applet ui: - bundled: "../ui/dist.zip" + bundled: "../web/dist.zip" happ_manifest: bundled: "./talking-stickies.happ" \ No newline at end of file diff --git a/web/src/api/callZome.ts b/web/src/api/callZome.ts index 78d595d8..d12ae53a 100644 --- a/web/src/api/callZome.ts +++ b/web/src/api/callZome.ts @@ -1,7 +1,7 @@ -import { AppWebsocket, CellId } from '@holochain/client' +import { AppAgentClient, CellId } from '@holochain/client' export default async function callZome( - appWebsocket: AppWebsocket, + appWebsocket: AppAgentClient, cellId: CellId, zomeName: string, fnName: string, diff --git a/web/src/api/hdkCrud.ts b/web/src/api/hdkCrud.ts index e3831a7f..0e99c386 100644 --- a/web/src/api/hdkCrud.ts +++ b/web/src/api/hdkCrud.ts @@ -4,7 +4,7 @@ import { ActionHashB64, UpdateInput, } from '../types/shared' -import { AppWebsocket, CellId } from '@holochain/client' +import { AppAgentClient, CellId } from '@holochain/client' import callZome from './callZome' export interface WireRecord { @@ -42,7 +42,7 @@ export function deleteEntryName(entryType: string) { } export function createCrudFunctions( - appWebsocket: AppWebsocket, + appWebsocket: AppAgentClient, zomeName: string, entryType: string ): EntryTypeApi> { diff --git a/web/src/api/profilesApi.ts b/web/src/api/profilesApi.ts index ac72c598..b32852cf 100644 --- a/web/src/api/profilesApi.ts +++ b/web/src/api/profilesApi.ts @@ -1,4 +1,4 @@ -import { AppWebsocket, CellId } from '@holochain/client' +import { AppAgentClient, CellId } from '@holochain/client' import { PROFILES_ZOME_NAME } from '../holochainConfig' import { Profile, WhoAmIOutput } from '../types' import { AgentPubKeyB64, UpdateInput } from '../types/shared' @@ -14,7 +14,7 @@ const ZOME_FN_NAMES = { FETCH_AGENT_ADDRESS: 'fetch_agent_address', } -const ProfilesApi = (appWebsocket: AppWebsocket) => { +const ProfilesApi = (appWebsocket: AppAgentClient) => { return { createWhoami: async ( cellId: CellId, @@ -83,9 +83,9 @@ const ProfilesApi = (appWebsocket: AppWebsocket) => { } export default class ProfilesZomeApi { - appWebsocket: AppWebsocket + appWebsocket: AppAgentClient profile: ReturnType - constructor(appWebsocket: AppWebsocket) { + constructor(appWebsocket: AppAgentClient) { this.appWebsocket = appWebsocket this.profile = ProfilesApi(appWebsocket) } diff --git a/web/src/api/projectsApi.ts b/web/src/api/projectsApi.ts index d13dc19a..18272a82 100644 --- a/web/src/api/projectsApi.ts +++ b/web/src/api/projectsApi.ts @@ -14,7 +14,7 @@ import { Tag, } from '../types' import { createCrudFunctions, WireRecord } from './hdkCrud' -import { AppWebsocket, CellId } from '@holochain/client' +import { AppAgentClient, CellId } from '@holochain/client' import { PROJECTS_ZOME_NAME } from '../holochainConfig' import callZome from './callZome' import { ActionHashB64 } from '../types/shared' @@ -42,7 +42,7 @@ const ZOME_FN_NAMES = { FETCH_MEMBERS: 'fetch_members', } -const OutcomeApi = (appWebsocket: AppWebsocket) => { +const OutcomeApi = (appWebsocket: AppAgentClient) => { const outcomeCrud = createCrudFunctions( appWebsocket, PROJECTS_ZOME_NAME, @@ -76,28 +76,28 @@ const OutcomeApi = (appWebsocket: AppWebsocket) => { }, } } -const ConnectionApi = (appWebsocket: AppWebsocket) => { +const ConnectionApi = (appWebsocket: AppAgentClient) => { return createCrudFunctions( appWebsocket, PROJECTS_ZOME_NAME, ENTRY_TYPE_NAMES.CONNECTION ) } -const OutcomeCommentApi = (appWebsocket: AppWebsocket) => { +const OutcomeCommentApi = (appWebsocket: AppAgentClient) => { return createCrudFunctions( appWebsocket, PROJECTS_ZOME_NAME, ENTRY_TYPE_NAMES.OUTCOME_COMMENT ) } -const OutcomeMemberApi = (appWebsocket: AppWebsocket) => { +const OutcomeMemberApi = (appWebsocket: AppAgentClient) => { return createCrudFunctions( appWebsocket, PROJECTS_ZOME_NAME, ENTRY_TYPE_NAMES.OUTCOME_MEMBER ) } -const EntryPointApi = (appWebsocket: AppWebsocket) => { +const EntryPointApi = (appWebsocket: AppAgentClient) => { const entryPointCrud = createCrudFunctions( appWebsocket, PROJECTS_ZOME_NAME, @@ -118,7 +118,7 @@ const EntryPointApi = (appWebsocket: AppWebsocket) => { }, } } -const ProjectMetaApi = (appWebsocket: AppWebsocket) => { +const ProjectMetaApi = (appWebsocket: AppAgentClient) => { const projectMetaCrud = createCrudFunctions( appWebsocket, PROJECTS_ZOME_NAME, @@ -161,7 +161,7 @@ const ProjectMetaApi = (appWebsocket: AppWebsocket) => { } } -const RealtimeInfoSignalApi = (appWebsocket: AppWebsocket) => { +const RealtimeInfoSignalApi = (appWebsocket: AppAgentClient) => { return { send: async (cellId: CellId, payload: RealtimeInfoInput) => { return callZome( @@ -175,7 +175,7 @@ const RealtimeInfoSignalApi = (appWebsocket: AppWebsocket) => { } } -const MembersApi = (appWebsocket: AppWebsocket) => { +const MembersApi = (appWebsocket: AppAgentClient) => { return { fetch: async (cellId: CellId): Promise>> => { return callZome( @@ -189,7 +189,7 @@ const MembersApi = (appWebsocket: AppWebsocket) => { } } -const TagApi = (appWebsocket: AppWebsocket) => { +const TagApi = (appWebsocket: AppAgentClient) => { return createCrudFunctions( appWebsocket, PROJECTS_ZOME_NAME, @@ -198,7 +198,7 @@ const TagApi = (appWebsocket: AppWebsocket) => { } export default class ProjectsZomeApi { - appWebsocket: AppWebsocket + appWebsocket: AppAgentClient outcome: ReturnType entryPoint: ReturnType connection: ReturnType @@ -211,7 +211,7 @@ export default class ProjectsZomeApi { // one per entry type that uses hdk_crud // projectMeta, realtimeInfoSignal and member don't use hdk_crud - constructor(appWebsocket: AppWebsocket) { + constructor(appWebsocket: AppAgentClient) { this.appWebsocket = appWebsocket this.outcome = OutcomeApi(appWebsocket) this.outcomeComment = OutcomeCommentApi(appWebsocket) diff --git a/web/src/components/ProjectSettingsModal/ProjectSettingsModal.component.tsx b/web/src/components/ProjectSettingsModal/ProjectSettingsModal.component.tsx index 5c251a25..55747201 100644 --- a/web/src/components/ProjectSettingsModal/ProjectSettingsModal.component.tsx +++ b/web/src/components/ProjectSettingsModal/ProjectSettingsModal.component.tsx @@ -250,14 +250,14 @@ export default function ProjectSettingsModal({ // const uid = passphraseToUid(projectPassphrase) // const installedAppId = `${PROJECT_APP_PREFIX}-${uid}` useEffect(() => { - getAllApps().then((apps) => { - const appForCell = Object.entries(apps).find(([appId, appInfo]) => { - return appInfo.cellIdString === cellIdString - }) - if (appForCell) { - setInstalledAppId(appForCell[0]) - } - }) + // getAllApps().then((apps) => { + // const appForCell = Object.entries(apps).find(([appId, appInfo]) => { + // return appInfo.cellIdString === cellIdString + // }) + // if (appForCell) { + // setInstalledAppId(appForCell[0]) + // } + // }) }, [cellIdString]) return ( diff --git a/web/src/hcWebsockets.ts b/web/src/hcWebsockets.ts index 77355827..dfe1a5d5 100644 --- a/web/src/hcWebsockets.ts +++ b/web/src/hcWebsockets.ts @@ -1,4 +1,9 @@ -import { AppWebsocket, AdminWebsocket } from '@holochain/client' +import { + AdminWebsocket, + AppAgentWebsocket, + AppAgentClient, +} from '@holochain/client' +import { MAIN_APP_ID } from './holochainConfig' // export for use by holochainMiddleware (redux) @@ -8,8 +13,8 @@ export const APP_WS_URL = new URL(`ws://localhost:${__APP_PORT__}`) // @ts-ignore const ADMIN_WS_URL = new URL(`ws://localhost:${__ADMIN_PORT__}`) -let appWs: AppWebsocket -let appWsPromise: Promise +let appWs: AppAgentClient +let appWsPromise: Promise let adminWs: AdminWebsocket let agentPubKey @@ -18,6 +23,7 @@ export async function getAdminWs(): Promise { return adminWs } else { adminWs = await AdminWebsocket.connect(ADMIN_WS_URL) + // keepalive setInterval(() => { if (adminWs.client.socket.readyState === adminWs.client.socket.OPEN) { adminWs.listDnas() @@ -30,20 +36,27 @@ export async function getAdminWs(): Promise { } } -export async function getAppWs(): Promise { +export async function getAppWs(): Promise { async function connect() { // undefined is for default request timeout - appWsPromise = AppWebsocket.connect(APP_WS_URL) + appWsPromise = AppAgentWebsocket.connect(APP_WS_URL, MAIN_APP_ID) appWs = await appWsPromise appWsPromise = null - appWs.client.socket.addEventListener('close', async () => { - console.log('app websocket closed, trying to re-open') - await connect() - console.log('app websocket reconnected') - }) + ;(appWs as AppAgentWebsocket).appWebsocket.client.socket.addEventListener( + 'close', + async () => { + console.log('app websocket closed, trying to re-open') + await connect() + console.log('app websocket reconnected') + } + ) } - if (appWs && appWs.client.socket.readyState === appWs.client.socket.OPEN) { + if ( + appWs && + (appWs as AppAgentWebsocket).appWebsocket.client.socket.readyState === + (appWs as AppAgentWebsocket).appWebsocket.client.socket.OPEN + ) { return appWs } else if (appWsPromise) { // connection must have been lost @@ -55,13 +68,15 @@ export async function getAppWs(): Promise { await connect() // set up logic for auto-reconnection setInterval(async () => { - if (appWs.client.socket.readyState === appWs.client.socket.OPEN) { + if ( + (appWs as AppAgentWebsocket).appWebsocket.client.socket.readyState === + (appWs as AppAgentWebsocket).appWebsocket.client.socket.OPEN + ) { // random call just to keep the connection open - appWs.appInfo({ - installed_app_id: 'test', - }) + appWs.appInfo() } else if ( - appWs.client.socket.readyState === appWs.client.socket.CLOSED + (appWs as AppAgentWebsocket).appWebsocket.client.socket.readyState === + (appWs as AppAgentWebsocket).appWebsocket.client.socket.CLOSED ) { // try to reconnect await connect() @@ -72,6 +87,13 @@ export async function getAppWs(): Promise { } } +export function setAdminWs(setAs: AdminWebsocket) { + adminWs = setAs +} +export function setAppWs(setAs: AppAgentClient) { + appWs = setAs +} + export function getAgentPubKey() { return agentPubKey } diff --git a/web/src/hooks/useProjectStatusInfos.ts b/web/src/hooks/useProjectStatusInfos.ts index 79166680..7b119b5c 100644 --- a/web/src/hooks/useProjectStatusInfos.ts +++ b/web/src/hooks/useProjectStatusInfos.ts @@ -20,6 +20,7 @@ export type ProjectStatusInfos = { const getNewInfos = async ( projects: { cellId: CellIdString; hasProjectMeta: boolean }[] ): Promise => { + return {} const allApps = await getAllApps() const appWs = await getAppWs() const agentPubKey = await getAgentPubKey() diff --git a/web/src/index.tsx b/web/src/index.tsx index 996e927b..65accec6 100644 --- a/web/src/index.tsx +++ b/web/src/index.tsx @@ -10,15 +10,27 @@ import 'core-js/stable' import 'regenerator-runtime/runtime' -import { WeClient, isWeContext } from '@lightningrodlabs/we-applet' -import main from './indexForElectron' +import { WeClient, isWeContext, initializeHotReload } from '@lightningrodlabs/we-applet' +import createStoreAndRenderToDom, { electronInit } from './indexForElectron' +import { getAdminWs, getAppWs, setAppWs } from './hcWebsockets' + +console.log('HELLLLLLO') if (!isWeContext) { // electron - main() + ;(async () => { + const appWs = await getAppWs() + const adminWs = await getAdminWs() + const store = await createStoreAndRenderToDom(appWs) + await electronInit(store, adminWs, appWs) + })() } else { + console.log('hello2') ;(async () => { + await initializeHotReload(); + console.log('hello3') const weClient = await WeClient.connect() + console.log('hello4') if ( weClient.renderInfo.type !== 'applet-view' || weClient.renderInfo.view.type !== 'main' @@ -28,6 +40,9 @@ if (!isWeContext) { const appAgentClient = weClient.renderInfo.appletClient const profilesClient = weClient.renderInfo.profilesClient + setAppWs(appAgentClient) console.log('made it here') + const store = await createStoreAndRenderToDom(appAgentClient) + console.log('made it here2') })() } diff --git a/web/src/indexForElectron.tsx b/web/src/indexForElectron.tsx index 867d31fa..8b81b1af 100644 --- a/web/src/indexForElectron.tsx +++ b/web/src/indexForElectron.tsx @@ -4,12 +4,12 @@ import { Provider } from 'react-redux' import { createStore, applyMiddleware, compose } from 'redux' // Local Imports -import { MAIN_APP_ID, PROFILES_ROLE_NAME } from './holochainConfig' +import { PROFILES_ROLE_NAME } from './holochainConfig' import acorn from './redux/reducer' import signalsHandlers from './signalsHandlers' import { - setProfilesCellId, - setProjectsCellIds, + setProfilesCellId, + setProjectsCellIds, } from './redux/persistent/cells/actions' import { layoutWatcher } from './redux/ephemeral/layout/middleware' import { realtimeInfoWatcher } from './redux/persistent/projects/realtime-info-signal/middleware' @@ -17,7 +17,7 @@ import { fetchAgents } from './redux/persistent/profiles/agents/actions' import { whoami } from './redux/persistent/profiles/who-am-i/actions' import { fetchAgentAddress } from './redux/persistent/profiles/agent-address/actions' import App from './routes/App.connector' -import { getAppWs, getAdminWs, setAgentPubKey } from './hcWebsockets' +import { setAgentPubKey } from './hcWebsockets' import { getProjectCellIdStrings } from './projectAppIds' import ProfilesZomeApi from './api/profilesApi' import { cellIdFromString, cellIdToString } from './utils' @@ -25,99 +25,97 @@ import { cellIdFromString, cellIdToString } from './utils' // Import styles import './variables.scss' import './global.scss' -import { CellType } from '@holochain/client' +import { AdminWebsocket, AppAgentClient, CellType } from '@holochain/client' - -export default function main() { - // trigger caching of adminWs connection - getAdminWs() - - const middleware = [layoutWatcher, realtimeInfoWatcher] - - // This enables the redux-devtools browser extension - // which gives really awesome debugging for apps that use redux +export default async function createStoreAndRenderToDom( + appWs: AppAgentClient +) { + const middleware = [layoutWatcher, realtimeInfoWatcher] + // This enables the redux-devtools browser extension + // which gives really awesome debugging for apps that use redux + const composeEnhancers = // @ts-ignore - const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose - - // acorn is the top-level reducer. the second argument is custom Holochain middleware - let store = createStore( - acorn, - /* preloadedState, */ composeEnhancers(applyMiddleware(...middleware)) - ) + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose + // acorn is the top-level reducer. the second argument is custom Holochain middleware + let store = createStore( + acorn, + /* preloadedState, */ composeEnhancers(applyMiddleware(...middleware)) + ) + // connect the signal handler to the app websocket + appWs.on('signal', signalsHandlers(store)) - getAppWs().then(async (client) => { - // connect the signal handler to the app websocket - client.on('signal', signalsHandlers(store)) - try { - const profilesInfo = await client.appInfo({ - installed_app_id: MAIN_APP_ID, - }) + // By passing the `store` in as a wrapper around our React component + // we make the state available throughout it + ReactDOM.render( + + + , + document.getElementById('react') + ) - const cellInfo = profilesInfo.cell_info[PROFILES_ROLE_NAME][0] - const cellId = - CellType.Provisioned in cellInfo - ? cellInfo[CellType.Provisioned].cell_id - : undefined - if (cellId == undefined) { - throw 'cellId undefined' - } else { - // authorize zome call signer - const adminWs = await getAdminWs() - await adminWs.authorizeSigningCredentials(cellId) + return store +} - const [_dnaHash, agentPubKey] = cellId - // cache buffer version of agentPubKey - setAgentPubKey(agentPubKey) - const cellIdString = cellIdToString(cellId) - store.dispatch(setProfilesCellId(cellIdString)) - // all functions of the Profiles DNA - const profilesZomeApi = new ProfilesZomeApi(client) +export async function electronInit( + store: any, + adminWs: AdminWebsocket, + appWs: AppAgentClient +) { + try { + const profilesInfo = await appWs.appInfo() + const cellInfo = profilesInfo.cell_info[PROFILES_ROLE_NAME][0] + const cellId = + CellType.Provisioned in cellInfo + ? cellInfo[CellType.Provisioned].cell_id + : undefined + if (cellId == undefined) { + throw 'cellId undefined' + } else { + // authorize zome call signer + await adminWs.authorizeSigningCredentials(cellId) - const profiles = await profilesZomeApi.profile.fetchAgents(cellId) - store.dispatch(fetchAgents(cellIdString, profiles)) - const profile = await profilesZomeApi.profile.whoami(cellId) - // this allows us to 'reclaim' a profile that was imported by someone else that is ours - // (i.e. it relates to our public key) - if (profile) { - let nonImportedProfile = { - ...profile.entry, - isImported: false, - } - await profilesZomeApi.profile.updateWhoami(cellId, { - entry: nonImportedProfile, - actionHash: profile.actionHash, - }) - profile.entry = nonImportedProfile - } - store.dispatch(whoami(cellIdString, profile)) - const agentAddress = await profilesZomeApi.profile.fetchAgentAddress( - cellId - ) - store.dispatch(fetchAgentAddress(cellIdString, agentAddress)) - // which projects do we have installed? - const projectCellIds = await getProjectCellIdStrings() + const [_dnaHash, agentPubKey] = cellId + // cache buffer version of agentPubKey + setAgentPubKey(agentPubKey) + const cellIdString = cellIdToString(cellId) + store.dispatch(setProfilesCellId(cellIdString)) + // all functions of the Profiles DNA + const profilesZomeApi = new ProfilesZomeApi(appWs) - // before any zome calls can be made, we need to gain zome call signing authorization - // for each of the project cells that we have installed - await Promise.all( - projectCellIds.map(async (cellId) => { - await adminWs.authorizeSigningCredentials(cellIdFromString(cellId)) - }) - ) - store.dispatch(setProjectsCellIds(projectCellIds)) - } - } catch (e) { - console.error(e) - return + const profiles = await profilesZomeApi.profile.fetchAgents(cellId) + store.dispatch(fetchAgents(cellIdString, profiles)) + const profile = await profilesZomeApi.profile.whoami(cellId) + // this allows us to 'reclaim' a profile that was imported by someone else that is ours + // (i.e. it relates to our public key) + if (profile) { + let nonImportedProfile = { + ...profile.entry, + isImported: false, } - }) + await profilesZomeApi.profile.updateWhoami(cellId, { + entry: nonImportedProfile, + actionHash: profile.actionHash, + }) + profile.entry = nonImportedProfile + } + store.dispatch(whoami(cellIdString, profile)) + const agentAddress = await profilesZomeApi.profile.fetchAgentAddress( + cellId + ) + store.dispatch(fetchAgentAddress(cellIdString, agentAddress)) + // which projects do we have installed? + const projectCellIds = await getProjectCellIdStrings() - // By passing the `store` in as a wrapper around our React component - // we make the state available throughout it - ReactDOM.render( - - - , - document.getElementById('react') - ) -} \ No newline at end of file + // before any zome calls can be made, we need to gain zome call signing authorization + // for each of the project cells that we have installed + await Promise.all( + projectCellIds.map(async (cellId) => { + await adminWs.authorizeSigningCredentials(cellIdFromString(cellId)) + }) + ) + store.dispatch(setProjectsCellIds(projectCellIds)) + } + } catch (e) { + console.error(e) + } +}