interface: implement subscription lifecycles

This commit is contained in:
Liam Fitzgerald 2021-06-14 09:53:15 +10:00
parent 3d8146b358
commit 71ca208829
No known key found for this signature in database
GPG Key ID: D390E12C61D1CFFB
6 changed files with 98 additions and 39 deletions

View File

@ -0,0 +1,49 @@
import airlock from '~/logic/api';
import useHarkState from '~/logic/state/hark';
import useMetadataState from '~/logic/state/metadata';
import useContactState from '../state/contact';
import useGraphState from '../state/graph';
import useGroupState from '../state/group';
import useInviteState from '../state/invite';
import useLaunchState from '../state/launch';
import useSettingsState from '../state/settings';
import useLocalState from '../state/local';
export const bootstrapApi = async () => {
await airlock.poke({ app: 'hood', mark: 'helm-hi', json: 'opening airlock' });
airlock.onError = (e) => {
(async () => {
try {
useLocalState.setState({ subscription: 'reconnecting' });
airlock.reset();
await bootstrapApi();
} catch (e) {
useLocalState.setState({ subscription: 'disconnected' });
}
})();
};
airlock.onRetry = (e) => {
useLocalState.setState({ subscription: 'reconnecting' });
};
airlock.onOpen = () => {
useLocalState.setState({ subscription: 'connected' });
};
await airlock.eventSource();
[
useHarkState,
useMetadataState,
useGroupState,
useContactState,
useSettingsState,
useLaunchState,
useInviteState,
useGraphState
].forEach((state) => {
state.getState().initialize(airlock);
});
};

View File

@ -1,36 +1,8 @@
import Urbit from '@urbit/http-api';
import useHarkState from '~/logic/state/hark';
import useMetadataState from '~/logic/state/metadata';
import useContactState from '../state/contact';
import useGraphState from '../state/graph';
import useGroupState from '../state/group';
import useInviteState from '../state/invite';
import useLaunchState from '../state/launch';
import useSettingsState from '../state/settings';
const api = new Urbit('', '');
api.ship = window.ship;
api.verbose = true;
// @ts-ignore TODO window typings
window.api = api;
export const bootstrapApi = async () => {
await api.poke({ app: 'hood', mark: 'helm-hi', json: 'opening airlock' });
await api.eventSource();
[
useHarkState,
useMetadataState,
useGroupState,
useContactState,
useSettingsState,
useLaunchState,
useInviteState,
useGraphState
].forEach((state) => {
state.getState().initialize(api);
});
};
export default api;

View File

@ -4,6 +4,10 @@ import React from 'react';
import create, { State } from 'zustand';
import { persist } from 'zustand/middleware';
import { BackgroundConfig, LeapCategories, RemoteContentPolicy, TutorialProgress, tutorialProgress } from '~/types/local-update';
import airlock from '~/logic/api';
import { bootstrapApi } from '../api/bootstrap';
export type SubscriptionStatus = 'connected' | 'disconnected' | 'reconnecting';
export interface LocalState {
theme: 'light' | 'dark' | 'auto';
@ -25,7 +29,9 @@ export interface LocalState {
omniboxShown: boolean;
suspendedFocus?: HTMLElement;
toggleOmnibox: () => void;
set: (fn: (state: LocalState) => void) => void
set: (fn: (state: LocalState) => void) => void;
subscription: SubscriptionStatus;
restartSubscription: () => Promise<void>;
}
type LocalStateZus = LocalState & State;
@ -82,6 +88,26 @@ const useLocalState = create<LocalStateZus>(persist((set, get) => ({
state.suspendedFocus.blur();
}
})),
subscription: 'connected',
restartSubscription: async () => {
try {
set({ subscription: 'reconnecting' });
await airlock.eventSource();
set({ subscription: 'connected' });
} catch (e) {
set({ subscription: 'disconnected' });
}
},
bootstrap: async () => {
try {
set({ subscription: 'reconnecting' });
airlock.reset();
await bootstrapApi();
set({ subscription: 'connected' });
} catch (e) {
set({ subscription: 'disconnected' });
}
},
// @ts-ignore investigate zustand types
set: fn => set(produce(fn))
}), {

View File

@ -27,7 +27,7 @@ import './css/fonts.css';
import './css/indigo-static.css';
import { Content } from './landscape/components/Content';
import './landscape/css/custom.css';
import { bootstrapApi } from '~/logic/api';
import { bootstrapApi } from '~/logic/api/bootstrap';
import useLaunchState from '../logic/state/launch';
const Root = withState(styled.div`

View File

@ -1,18 +1,33 @@
import { Button, LoadingSpinner, Text } from '@tlon/indigo-react';
import React from 'react';
import useLocalState from '~/logic/state/local';
import api from '~/logic/api';
const ReconnectButton = ({ connection, subscription }) => {
const connectedStatus = connection || 'connected';
const reconnect = () => {}; // subscription.restart.bind(subscription);
const ReconnectButton = () => {
const { set, subscription } = useLocalState();
const reconnect = () => {
(async () => {
try {
await api.eventSource();
set((state) => {
state.subscription = 'connected';
});
} catch (e) {
set((state) => {
state.subscription = 'connected';
});
}
})();
};
if (connectedStatus === 'disconnected') {
if (subscription === 'disconnected') {
return (
<Button onClick={reconnect} borderColor='red' px={2}>
<Text display={['none', 'inline']} textAlign='center' color='red'>Reconnect</Text>
<Text color='red'> </Text>
</Button>
);
} else if (connectedStatus === 'reconnecting') {
} else if (subscription === 'reconnecting') {
return (
<Button borderColor='yellow' px={2} onClick={() => {}} cursor='default'>
<LoadingSpinner foreground='scales.yellow60' background='scales.yellow30' />

View File

@ -103,10 +103,7 @@ const StatusBar = (props) => {
{metaKey}/
</Text>
</StatusBarItem>
<ReconnectButton
connection={props.connection}
subscription={props.subscription}
/>
<ReconnectButton />
</Row>
<Row justifyContent='flex-end'>
<StatusBarItem